aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.editorconfig2
-rw-r--r--Makefile11
-rw-r--r--config39
-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-04-10-what-its-like-to-be-a-software-developer.md34
-rw-r--r--content/2018-08-05-the-bullshit-web-developments-pov.md94
-rw-r--r--content/2019-05-11-bci.md71
-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/dev101-git-topics-1.pngbin13317 -> 0 bytes
-rw-r--r--content/files/dev101-git-topics-2.pngbin12260 -> 0 bytes
-rw-r--r--content/files/style.css6
-rw-r--r--gulpfile.js181
-rw-r--r--package.json32
-rw-r--r--robots.txt2
-rw-r--r--settings.js19
-rw-r--r--site.tmpl95
-rw-r--r--source/assets/default.css330
-rw-r--r--source/assets/default.js21
-rw-r--r--source/assets/languages/prism-bash.js84
-rw-r--r--source/assets/languages/prism-c.js33
-rw-r--r--source/assets/languages/prism-css.js52
-rw-r--r--source/assets/languages/prism-go.js12
-rw-r--r--source/assets/languages/prism-javascript.js56
-rw-r--r--source/assets/languages/prism-json.js14
-rw-r--r--source/assets/languages/prism-nginx.js11
-rw-r--r--source/assets/languages/prism-pascal.js55
-rw-r--r--source/assets/languages/prism-python.js29
-rw-r--r--source/assets/prism.css167
-rw-r--r--source/assets/prism.js1071
-rw-r--r--source/layouts/comments.njk2
-rw-r--r--source/layouts/draft.njk62
-rw-r--r--source/layouts/footer.njk47
-rw-r--r--source/layouts/index.njk80
-rw-r--r--source/layouts/navigation.njk47
-rw-r--r--source/layouts/page.njk60
-rw-r--r--source/layouts/post.njk66
-rw-r--r--src/blog/golang-profiling-simplified.md (renamed from content/2017-03-07-golang-profiling-simplified.md)24
-rw-r--r--src/blog/profiling-python-web-applications-with-visual-tools.md (renamed from content/2017-04-21-profiling-python-web-applications-with-visual-tools.md)15
-rw-r--r--src/blog/simple-iot-application.md (renamed from content/2017-08-11-simple-iot.md)36
-rw-r--r--src/blog/simplifying-and-reducing-clutter.md21
-rw-r--r--src/blog/what-i-ve-learned-developing-ad-server.md (renamed from content/2017-04-17-what-i-ve-learned-developing-ad-server.md)20
-rw-r--r--src/curriculum-vitae.md (renamed from content/cv.md)11
-rw-r--r--src/feed.atom55
-rw-r--r--src/files/dna-sequence/benchmarks.ods (renamed from content/files/dna-sequence/benchmarks.ods)bin21911 -> 21911 bytes
-rw-r--r--src/files/dna-sequence/chart-encoding-speed.png (renamed from content/files/dna-sequence/chart-encoding-speed.png)bin14201 -> 14201 bytes
-rw-r--r--src/files/dna-sequence/chart-file-sizes.png (renamed from content/files/dna-sequence/chart-file-sizes.png)bin12391 -> 12391 bytes
-rw-r--r--src/files/dna-sequence/dna-basics.jpg (renamed from content/files/dna-sequence/dna-basics.jpg)bin165883 -> 165883 bytes
-rw-r--r--src/files/dna-sequence/quote.png (renamed from content/files/dna-sequence/quote.png)bin1068 -> 1068 bytes
-rw-r--r--src/files/dna-sequence/sample-binary-file.png (renamed from content/files/dna-sequence/sample-binary-file.png)bin66417 -> 66417 bytes
-rw-r--r--src/files/dna-sequence/sample.png (renamed from content/files/dna-sequence/sample.png)bin65930 -> 65930 bytes
-rw-r--r--src/files/do-fuse/copy-benchmarks.tsv (renamed from content/files/copy-benchmarks.tsv)0
-rw-r--r--src/files/do-fuse/fuse-droplets.png (renamed from content/files/fuse-droplets.png)bin42891 -> 42891 bytes
-rw-r--r--src/files/do-fuse/fuse-spaces.png (renamed from content/files/fuse-spaces.png)bin32450 -> 32450 bytes
-rw-r--r--src/files/do-fuse/sqlite-benchmarks.tsv (renamed from content/files/sqlite-benchmarks.tsv)0
-rw-r--r--src/files/go-profiling/golang-profiling-cpu.pdf (renamed from content/files/golang-profiling-cpu.pdf)bin16518 -> 16518 bytes
-rw-r--r--src/files/go-profiling/golang-profiling-mem.pdf (renamed from content/files/golang-profiling-mem.pdf)bin19221 -> 19221 bytes
-rw-r--r--src/files/iot-application/iot-app-output.png (renamed from content/files/iot-app-output.png)bin23767 -> 23767 bytes
-rw-r--r--src/files/iot-application/iot-rest-example.png (renamed from content/files/iot-rest-example.png)bin33912 -> 33912 bytes
-rw-r--r--src/files/iot-application/iot-sqlite-db.png (renamed from content/files/iot-sqlite-db.png)bin199821 -> 199821 bytes
-rw-r--r--src/files/iot-application/kcachegrind.png (renamed from content/files/kcachegrind.png)bin88486 -> 88486 bytes
-rw-r--r--src/files/iot-application/profiling-viewer.png (renamed from content/files/profiling-viewer.png)bin173672 -> 173672 bytes
-rw-r--r--src/files/iot-application/simple-iot-application-overview.svg (renamed from content/files/simple-iot-application-overview.svg)0
-rw-r--r--src/files/iot-application/simple-iot-application.zip (renamed from content/files/simple-iot-application.zip)bin6406 -> 6406 bytes
-rw-r--r--src/files/iot-application/snakeviz.png (renamed from content/files/snakeviz.png)bin59601 -> 59601 bytes
-rw-r--r--src/index.html19
-rw-r--r--src/research/encoding-binary-data-into-dna-sequence.md (renamed from content/2019-01-03-encoding-binary-data-into-dna-sequence.md)77
-rw-r--r--src/research/using-digitalocean-spaces-object-storage-with-fuse.md (renamed from content/2018-01-16-using-digitalocean-spaces-object-storage-with-fuse.md)30
-rw-r--r--src/static/avatar-512x512.pngbin0 -> 244569 bytes
-rw-r--r--src/static/avatar-64x64.pngbin0 -> 16769 bytes
-rw-r--r--src/static/style.css116
74 files changed, 398 insertions, 3088 deletions
diff --git a/.editorconfig b/.editorconfig
index 1923d41..9f48fab 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -1,8 +1,6 @@
1root = true 1root = true
2 2
3[*] 3[*]
4indent_style = space
5indent_size = 2
6charset = utf-8 4charset = utf-8
7trim_trailing_whitespace = true 5trim_trailing_whitespace = true
8insert_final_newline = true 6insert_final_newline = true
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..2411164
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,11 @@
1GS ?= gostatic
2
3compile:
4 $(GS) config
5
6w:
7 -rm public -rf
8 $(GS) -w config
9
10deploy: compile
11 firebase deploy
diff --git a/config b/config
new file mode 100644
index 0000000..fa65564
--- /dev/null
+++ b/config
@@ -0,0 +1,39 @@
1TEMPLATES = site.tmpl
2SOURCE = src
3OUTPUT = public
4TITLE = Mitja Felicijan - Embedded systems developer
5DESCRIPTION = Embedded systems developer and fanatical fan of science fiction
6GOOGLE_VERIFICATION = EwUGW1WlCkRIQuyQ9AE1-bLitWthw-eVMZFTAMZVZaA
7URL = https://mitjafelicijan.com
8AUTHOR = Mitja Felicijan
9
10blog/*.md:
11 config
12 ext .html
13 tags tags/*.tag
14 markdown
15 template post
16 template page
17
18research/*.md:
19 config
20 ext .html
21 tags tags/*.tag
22 markdown
23 template post
24 template page
25
26feed.atom: blog/*.md
27 inner-template
28
29*.md:
30 config
31 ext .html
32 markdown
33 template post
34 template page
35
36index.html: blog/*.md
37 config
38 inner-template
39 template page
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-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/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-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/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/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/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}
diff --git a/gulpfile.js b/gulpfile.js
deleted file mode 100644
index cf0ce50..0000000
--- a/gulpfile.js
+++ /dev/null
@@ -1,181 +0,0 @@
1'use strict';
2
3const util = require('util');
4const gulp = require('gulp');
5const concat = require('gulp-concat');
6const terser = require('gulp-terser');
7const clean = require('gulp-clean-css');
8const settings = require('./settings.js');
9const minify = require('html-minifier').minify;
10var browserSync = require('browser-sync').create();
11
12const fs = require('fs');
13const markdown = require('markdown-it');
14const prism = require('markdown-it-prism');
15const nunjucks = require('nunjucks');
16const yaml = require('yaml');
17const dayjs = require('dayjs');
18
19const md = new markdown({
20 html: true,
21 linkify: false,
22 typographer: true,
23 breaks: true,
24})
25 .use(prism)
26 .use(require('markdown-it-deflist'))
27 .use(require('markdown-it-footnote'))
28 .use(require('markdown-it-anchor'))
29 .use(require('markdown-it-checkbox'))
30
31nunjucks.configure('source/layouts', {
32 autoescape: false,
33 noCache: true,
34});
35
36gulp.task('js', () => gulp.src(settings.assets.javascript)
37 .pipe(concat('bundle.js'))
38 .pipe(terser())
39 .pipe(gulp.dest('tmp'))
40);
41
42gulp.task('css', () => gulp.src(settings.assets.css)
43 .pipe(concat('bundle.css'))
44 .pipe(clean({}))
45 .pipe(gulp.dest('tmp'))
46);
47
48gulp.task('copy-robots', () => gulp.src('robots.txt')
49 .pipe(gulp.dest('public'))
50);
51
52gulp.task('copy-files', () => gulp.src('content/files/**/*')
53 .pipe(gulp.dest('public/files'))
54);
55
56gulp.task('generate-static', function (done) {
57 fs.readdir('content', function (err, items) {
58
59 let posts = [];
60 items.forEach(item => {
61 if (item.endsWith('.md')) {
62
63 processMarkdown(`content/${item}`);
64
65 let contents = fs.readFileSync(`content/${item}`, 'utf8');
66 let raw = contents.split('---');
67 let meta = null;
68
69 try {
70 meta = yaml.parse(raw[1])
71 } catch (error) { }
72
73 if (meta.layout == 'post') {
74 meta.dateFormatted = dayjs(meta.date).format('MMMM D, YYYY');
75 meta.dateOriginal = meta.date;
76 meta.date = new Date(meta.date);
77 posts.push(meta)
78 }
79 }
80 });
81
82 const css = fs.readFileSync('tmp/bundle.css', 'utf8');
83 const javascript = fs.readFileSync('tmp/bundle.js', 'utf8');
84
85 let page = nunjucks.render(`index.njk`, {
86 css: `<style>${css}</style>`,
87 javascript: `<script>${javascript}</script>`,
88 currentYear: new Date().getFullYear(),
89 timestamp: Math.floor(Date.now() / 1000),
90 vars: settings.vars,
91 posts: posts.reverse(),
92 });
93
94 util.log(`Processing: Index`);
95
96 fs.writeFileSync(`public/index.html`, minify(page, {
97 removeAttributeQuotes: true,
98 collapseWhitespace: true,
99 removeComments: true,
100 removeTagWhitespace: true,
101 }));
102
103 });
104
105 done();
106});
107
108const processMarkdown = (file) => {
109 const contents = fs.readFileSync(file, 'utf8');
110 let raw = contents.split('---');
111 let meta = null;
112
113 try {
114 meta = yaml.parse(raw[1])
115 } catch (error) { }
116
117 //const slug = slugify(meta.title, { lower: true });
118 const slug = meta.slug;
119 const css = fs.readFileSync('tmp/bundle.css', 'utf8');
120 const javascript = fs.readFileSync('tmp/bundle.js', 'utf8');
121
122 raw.shift();
123 raw.shift();
124
125 let post = nunjucks.render(`${meta.layout}.njk`, {
126 content: md.render(raw.join('')),
127 title: meta.title, //.substring(0, 65)
128 description: meta.description,
129 css: `<style>${css}</style>`,
130 javascript: `<script>${javascript}</script>`,
131 slug: slug,
132 currentYear: new Date().getFullYear(),
133 timestamp: Math.floor(Date.now() / 1000),
134 vars: settings.vars,
135 writtenDate: {
136 formatted: dayjs(meta.date).format('MMMM D, YYYY'),
137 original: meta.date,
138 },
139 });
140
141 util.log(`Processing: ${meta.title}`);
142
143 fs.writeFileSync(`public/${slug}.html`, minify(post, {
144 removeAttributeQuotes: true,
145 collapseWhitespace: true,
146 removeComments: true,
147 removeTagWhitespace: true,
148 }));
149};
150
151const watchers = (done) => {
152 gulp.watch('source/assets/*.css', {
153 awaitWriteFinish: true,
154 }).on('change', gulp.series('css'));
155
156 gulp.watch('source/assets/*.js', {
157 awaitWriteFinish: true,
158 }).on('change', gulp.series('js'));
159
160 gulp.watch('content/*.md', {
161 awaitWriteFinish: true,
162 }).on('change', processMarkdown);
163
164 done();
165}
166
167gulp.task('browser-sync', () => {
168 browserSync.init({
169 watch: true,
170 open: false,
171 server: {
172 baseDir: './public',
173 serveStaticOptions: {
174 extensions: ["html"]
175 }
176 }
177 });
178});
179
180gulp.task('dev', gulp.series('css', 'js', 'copy-robots', 'copy-files', 'generate-static', gulp.parallel(watchers, 'browser-sync')));
181gulp.task('build', gulp.series('css', 'js', 'copy-robots', 'copy-files', 'generate-static'));
diff --git a/package.json b/package.json
deleted file mode 100644
index 0cae7e9..0000000
--- a/package.json
+++ /dev/null
@@ -1,32 +0,0 @@
1{
2 "name": "blog",
3 "version": "1.0.0",
4 "description": "",
5 "main": "index.js",
6 "scripts": {
7 "dev": "gulp dev",
8 "build": "gulp build",
9 "deploy": "firebase deploy"
10 },
11 "keywords": [],
12 "author": "",
13 "license": "ISC",
14 "devDependencies": {
15 "browser-sync": "^2.26.7",
16 "dayjs": "^1.8.16",
17 "gulp": "^4.0.2",
18 "gulp-clean-css": "^4.2.0",
19 "gulp-concat": "^2.6.1",
20 "gulp-terser": "^1.2.0",
21 "html-minifier": "^4.0.0",
22 "http-server": "^0.11.1",
23 "markdown-it": "^10.0.0",
24 "markdown-it-anchor": "^5.2.5",
25 "markdown-it-checkbox": "^1.1.0",
26 "markdown-it-deflist": "^2.0.3",
27 "markdown-it-footnote": "^3.0.2",
28 "markdown-it-prism": "^2.0.3",
29 "nunjucks": "^3.2.0",
30 "yaml": "^1.7.2"
31 }
32}
diff --git a/robots.txt b/robots.txt
deleted file mode 100644
index eb05362..0000000
--- a/robots.txt
+++ /dev/null
@@ -1,2 +0,0 @@
1User-agent: *
2Disallow:
diff --git a/settings.js b/settings.js
deleted file mode 100644
index 3d41fcf..0000000
--- a/settings.js
+++ /dev/null
@@ -1,19 +0,0 @@
1exports.assets = {
2 css: [
3 'source/assets/default.css',
4 'source/assets/prism.css',
5 ],
6 javascript: [
7 'source/assets/prism.js',
8 'source/assets/languages/*.js',
9 'source/assets/default.js',
10 ],
11}
12
13exports.vars = {
14 domain: 'https://mitjafelicijan.com',
15 handle: '@mitjafelicijan',
16 author: 'Mitja Felicijan',
17 title: 'Mitja Felicijan - Embedded systems developer',
18 description: 'Embedded systems developer and fanatical fan of science fiction',
19}
diff --git a/site.tmpl b/site.tmpl
new file mode 100644
index 0000000..dc7bb97
--- /dev/null
+++ b/site.tmpl
@@ -0,0 +1,95 @@
1{{ define "header" }}
2 <!doctype html>
3 <html lang="en">
4 <head>
5 <meta charset="utf-8">
6 <meta name="viewport" content="width=device-width, initial-scale=1.0">
7 <meta name="theme-color" content="#ffffff">
8 <meta name="google-site-verification" content="{{ html .Site.Other.Google_verification }}">
9 <meta http-equiv="X-UA-Compatible" content="ie=edge">
10 <meta name=description content="{{ html .Site.Other.Description }}">
11
12 <meta name="author" content="{{ html .Site.Other.Author }}">
13 <link rel="alternate" type="application/atom+xml" title="{{ html .Site.Other.Title }} feed" href="{{ .Rel "feed.atom" }}">
14 <title>{{ .Site.Other.Title }}{{ if .Title }}: {{ .Title }}{{ end }}</title>
15 <link rel="stylesheet" type="text/css" href="{{ .Rel "static/style.css" }}">
16
17 <link rel="icon" type="image/png" href="{{ .Rel "static/avatar-64x64.png" }}">
18 </head>
19 <body>
20 <main>
21{{ end }}
22
23{{ define "footer" }}
24 </main>
25 {{ template "ga" . }}
26 </body>
27 </html>
28{{ end }}
29
30{{ define "navigation" }}
31 <nav>
32 <a href="/">{{ html .Site.Other.Author }}</a>
33 <a href="/curriculum-vitae">Curriculum Vitae</a>
34 <a href="https://twitter.com/mitjafelicijan" target="_blank" rel="noopener nofollow">Twitter</a>
35 <a href="https://github.com/mitjafelicijan" target="_blank" rel="noopener nofollow">Github</a>
36 </nav>
37{{ end }}
38
39{{ define "author" }}
40 <span>by {{ html .Site.Other.Author }}</span>
41{{ end }}
42
43{{define "date"}}
44 <time datetime="{{ .Format "2006-01-02T15:04:05Z07:00" }}">
45 {{ .Format "2006, January 02" }}
46 </time>
47{{end}}
48
49{{ define "page" }}
50 {{ template "header" . }}
51 {{ template "navigation" . }}
52 {{ .Content }}
53 {{ template "mathjax" . }}
54 {{ template "footer" . }}
55{{ end }}
56
57{{ define "post" }}
58 <article>
59 <header>
60 <h1>{{ .Title }}</h1>
61 <div class="info">
62 {{ template "date" .Date }}
63 {{ template "author" . }}
64 </div>
65 </header>
66 <section>
67 {{ .Content }}
68 </section>
69 </article>
70{{ end }}
71
72{{ define "mathjax" }}
73 <script type="text/x-mathjax-config">
74 MathJax.Hub.Config({
75 TeX: { equationNumbers: { autoNumber: "AMS" } },
76 tex2jax: {
77 inlineMath: [ [ '$', '$' ], [ '\\(', '\\)' ] ],
78 displayMath: [ ['$$', '$$'] ],
79 processEscapes: true
80 }});
81 </script>
82 <script src="//cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-AMS-MML_HTMLorMML" async="async"></script>
83{{ end }}
84
85{{ define "ga" }}
86 <script async="async" src="https://www.googletagmanager.com/gtag/js?id=UA-12769079-10"></script>
87 <script>
88 window.dataLayer = window.dataLayer || [];
89 function gtag() {
90 dataLayer.push(arguments);
91 }
92 gtag('js', new Date());
93 gtag('config', 'UA-12769079-10');
94 </script>
95{{ end }} \ No newline at end of file
diff --git a/source/assets/default.css b/source/assets/default.css
deleted file mode 100644
index ee88a25..0000000
--- a/source/assets/default.css
+++ /dev/null
@@ -1,330 +0,0 @@
1@charset "utf-8";
2
3@import url('https://fonts.googleapis.com/css?family=Source+Code+Pro:400,500,600,700,900');
4
5* {
6 box-sizing: border-box;
7 -moz-osx-font-smoothing: grayscale !important;
8 text-rendering: optimizeLegibility !important;
9 -webkit-font-smoothing: antialiased !important;
10}
11
12body {
13 /*font-family: 'Heebo', sans-serif;*/
14 font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
15 font-size: 17px;
16 line-height: 170%;
17}
18
19a {
20 color: inherit;
21 text-decoration: underline;
22 text-decoration-color: fuchsia;
23 text-decoration-style: wavy;
24 border: 2px dotted transparent;
25 display: inline-block;
26}
27
28a:active {
29 border-color: black;
30}
31
32ol a {
33 text-decoration: none;
34}
35
36ol a:hover {
37 text-decoration: underline;
38}
39
40h1 {
41 line-height: 140%;
42 font-weight: 600;
43 font-size: 210%;
44}
45
46h2,h3,h4,h5 {
47 /*margin-top: 50px;*/
48 font-weight: 500;
49}
50
51img {
52 max-width: 100%;
53 margin: 30px auto;
54 display: block;
55}
56
57.wrapper {
58 max-width: 720px;
59 margin: 0 auto;
60}
61
62blockquote {
63 margin: 50px 0 50px 50px;
64}
65
66.pubdate {
67 font-size: 80%;
68 color: #666;
69}
70
71/********************************************************** CODE HIGHLIGHTING */
72
73pre, code {
74 font-family: 'Source Code Pro', monospace !important;
75 font-weight: 500;
76}
77
78pre {
79 font-size: 85%;
80 margin: 20px;
81 background: #eee;
82}
83
84p > code {
85 background: rgb(48, 46, 46);
86 padding: 1px 0.95rem 2px;
87 border-radius: 1em;
88 font-size: 70%;
89 font-weight: 600;
90 color: #fff;
91 display: inline;
92 -webkit-box-decoration-break: clone;
93 cursor:crosshair;
94}
95
96p > code:hover {
97 background: fuchsia;
98}
99
100/***************************************************************** OL COUNTER */
101
102ol {
103 list-style: none;
104 counter-reset: li;
105}
106
107ol li {
108 counter-increment: li;
109}
110
111ol li::before {
112 content: counter(li) ".";
113 color: #ccc;
114 font-weight: 500;
115 display: inline-block;
116 width: 1em;
117 margin-left: -1.5em;
118 margin-right: 0.9em;
119 text-align: right;
120}
121
122ol li a {
123 text-decoration: none;
124}
125
126/********************************************************************* TABLES */
127
128table {
129 width: 100%;
130 border-collapse: collapse;
131 border-spacing: 0;
132 font-size: 90%;
133 text-align: left;
134 margin-top: 50px;
135 margin-bottom: 50px;
136}
137
138th,td {
139 border-bottom: 2px solid #888;
140 padding: 10px;
141}
142
143th {
144 font-size: 130%;
145}
146
147tr:last-child td {
148 border-width: 0;
149}
150
151/****************************************************************** FOOTNOTES */
152
153.footnotes p {
154 padding: 0;
155 display: inline-block;
156 margin: 0;
157}
158
159.footnotes-sep {
160 border: 0;
161}
162
163/************************************************* BGCOLOR WHEN TEXT SELECTED */
164
165::selection {
166 background: #ff0;
167 color: #000;
168}
169
170::-moz-selection {
171 background: #ff0;
172 color: #000;
173}
174
175/********************************************************** CUSTOM SCROLLBARS */
176
177pre::-webkit-scrollbar {
178 width: 5px;
179 height: 8px;
180 background-color: transparent;
181}
182
183pre::-webkit-scrollbar-thumb {
184 background: #ddd;
185}
186
187/*************************************************************** HEADER + NAV */
188
189menu {
190 display: grid;
191 grid-template-columns: 1fr 1fr;
192 font-size: 80%;
193 padding: 0;
194 padding-top: 10px;
195 margin-bottom: 40px;
196}
197
198menu a.logo {
199 font-weight: 600;
200 text-decoration: none;
201 font-size: 130%;
202 padding: 5px 0px ;
203}
204
205menu a.logo:hover {
206 /*background: fuchsia;
207 color: white;*/
208}
209
210menu nav {
211 text-align: right;
212 margin-top: 3px;
213}
214
215menu nav a {
216 padding-top: 8px;
217 margin-left: 25px;
218}
219
220menu nav a svg {
221 width: 20px;
222 height: 20px;
223}
224
225/********************************************************************* FOOTER */
226
227footer {
228 padding-top: 50px;
229 padding-bottom: 50px;
230 font-weight: 500;
231 font-size: 80%;
232}
233
234footer > * {
235 text-decoration: none;
236 margin-right: 20px;
237 color: #333;
238}
239
240/*************************************************************** ARTICLE LIST */
241
242.list .article-list {
243 margin-bottom: 60px;
244}
245
246.list .article-list:last-child {
247 margin-bottom: 10px;
248}
249
250.list h3 {
251 font-weight: 700;
252 font-size: 140%;
253}
254
255.article-list article {
256 margin-bottom: 20px;
257}
258
259.article-list article h2 {
260 margin: 0;
261 line-height: 150%;
262 font-size: 120%;
263}
264
265.article-list a {
266 text-decoration: none;
267}
268
269article img[src*="#large"],
270article img.large {
271 max-width: 1100px;
272 width: 1100px;
273 position: relative;
274 left: -150px;
275 margin: 50px 0;
276}
277
278/***************************************************************** RESPONSIVE */
279
280@media only screen and (max-width:800px) {
281 body {
282 font-size: 16px;
283 }
284
285 .wrapper {
286 padding: 10px 20px !important;
287 }
288
289 h1 {
290 font-size: 200%;
291 }
292
293 footer {
294 text-align: center;
295 }
296
297 article img.large {
298 position: initial;
299 width: 100%;
300 margin: 20px 0;
301 }
302}
303
304/******************************************************************* COMMENTS */
305
306#commento {
307 margin-top: 75px;
308}
309
310#commento-footer {
311 display: none !important;
312}
313
314#commento-submit-button-root {
315 background: #fff !important;
316 color: #495057 !important;
317 box-shadow: none !important;
318}
319
320.commento-avatar-img {
321 margin-top: 0 !important;
322}
323
324/********************************************************************** PRINT */
325
326@media print {
327 nav, footer {
328 display: none;
329 }
330}
diff --git a/source/assets/default.js b/source/assets/default.js
deleted file mode 100644
index 2df34f0..0000000
--- a/source/assets/default.js
+++ /dev/null
@@ -1,21 +0,0 @@
1//Responsive tables
2document.querySelectorAll('table').forEach(function (element) {
3 if (!element.classList.contains('rouge-table')) {
4 let parent = element.parentNode;
5 let wrapper = document.createElement('div');
6 wrapper.classList.add('responsive-table');
7 parent.replaceChild(wrapper, element);
8 wrapper.appendChild(element);
9 }
10});
11
12
13// Open external links in new tab
14let links = document.links;
15for (let i = 0, linksLength = links.length; i < linksLength; i++) {
16 if (links[i].hostname != window.location.hostname) {
17 links[i].target = '_blank';
18 links[i].setAttribute('rel', 'noopener nofollow');
19 }
20}
21
diff --git a/source/assets/languages/prism-bash.js b/source/assets/languages/prism-bash.js
deleted file mode 100644
index 5093ffd..0000000
--- a/source/assets/languages/prism-bash.js
+++ /dev/null
@@ -1,84 +0,0 @@
1(function(Prism) {
2 var insideString = {
3 variable: [
4 // Arithmetic Environment
5 {
6 pattern: /\$?\(\([\s\S]+?\)\)/,
7 inside: {
8 // If there is a $ sign at the beginning highlight $(( and )) as variable
9 variable: [{
10 pattern: /(^\$\(\([\s\S]+)\)\)/,
11 lookbehind: true
12 },
13 /^\$\(\(/
14 ],
15 number: /\b0x[\dA-Fa-f]+\b|(?:\b\d+\.?\d*|\B\.\d+)(?:[Ee]-?\d+)?/,
16 // Operators according to https://www.gnu.org/software/bash/manual/bashref.html#Shell-Arithmetic
17 operator: /--?|-=|\+\+?|\+=|!=?|~|\*\*?|\*=|\/=?|%=?|<<=?|>>=?|<=?|>=?|==?|&&?|&=|\^=?|\|\|?|\|=|\?|:/,
18 // If there is no $ sign at the beginning highlight (( and )) as punctuation
19 punctuation: /\(\(?|\)\)?|,|;/
20 }
21 },
22 // Command Substitution
23 {
24 pattern: /\$\([^)]+\)|`[^`]+`/,
25 greedy: true,
26 inside: {
27 variable: /^\$\(|^`|\)$|`$/
28 }
29 },
30 /\$(?:[\w#?*!@]+|\{[^}]+\})/i
31 ]
32 };
33
34 Prism.languages.bash = {
35 'shebang': {
36 pattern: /^#!\s*\/bin\/bash|^#!\s*\/bin\/sh/,
37 alias: 'important'
38 },
39 'comment': {
40 pattern: /(^|[^"{\\])#.*/,
41 lookbehind: true
42 },
43 'string': [
44 //Support for Here-Documents https://en.wikipedia.org/wiki/Here_document
45 {
46 pattern: /((?:^|[^<])<<\s*)["']?(\w+?)["']?\s*\r?\n(?:[\s\S])*?\r?\n\2/,
47 lookbehind: true,
48 greedy: true,
49 inside: insideString
50 },
51 {
52 pattern: /(["'])(?:\\[\s\S]|\$\([^)]+\)|`[^`]+`|(?!\1)[^\\])*\1/,
53 greedy: true,
54 inside: insideString
55 }
56 ],
57 'variable': insideString.variable,
58 // Originally based on http://ss64.com/bash/
59 'function': {
60 pattern: /(^|[\s;|&])(?:alias|apropos|apt-get|aptitude|aspell|awk|basename|bash|bc|bg|builtin|bzip2|cal|cat|cd|cfdisk|chgrp|chmod|chown|chroot|chkconfig|cksum|clear|cmp|comm|command|cp|cron|crontab|csplit|curl|cut|date|dc|dd|ddrescue|df|diff|diff3|dig|dir|dircolors|dirname|dirs|dmesg|du|egrep|eject|enable|env|ethtool|eval|exec|expand|expect|export|expr|fdformat|fdisk|fg|fgrep|file|find|fmt|fold|format|free|fsck|ftp|fuser|gawk|getopts|git|grep|groupadd|groupdel|groupmod|groups|gzip|hash|head|help|hg|history|hostname|htop|iconv|id|ifconfig|ifdown|ifup|import|install|jobs|join|kill|killall|less|link|ln|locate|logname|logout|look|lpc|lpr|lprint|lprintd|lprintq|lprm|ls|lsof|make|man|mkdir|mkfifo|mkisofs|mknod|more|most|mount|mtools|mtr|mv|mmv|nano|netstat|nice|nl|nohup|notify-send|npm|nslookup|open|op|passwd|paste|pathchk|ping|pkill|popd|pr|printcap|printenv|printf|ps|pushd|pv|pwd|quota|quotacheck|quotactl|ram|rar|rcp|read|readarray|readonly|reboot|rename|renice|remsync|rev|rm|rmdir|rsync|screen|scp|sdiff|sed|seq|service|sftp|shift|shopt|shutdown|sleep|slocate|sort|source|split|ssh|stat|strace|su|sudo|sum|suspend|sync|tail|tar|tee|test|time|timeout|times|touch|top|traceroute|trap|tr|tsort|tty|type|ulimit|umask|umount|unalias|uname|unexpand|uniq|units|unrar|unshar|uptime|useradd|userdel|usermod|users|uuencode|uudecode|v|vdir|vi|vmstat|wait|watch|wc|wget|whereis|which|who|whoami|write|xargs|xdg-open|yes|zip)(?=$|[\s;|&])/,
61 lookbehind: true
62 },
63 'keyword': {
64 pattern: /(^|[\s;|&])(?:let|:|\.|if|then|else|elif|fi|for|break|continue|while|in|case|function|select|do|done|until|echo|exit|return|set|declare)(?=$|[\s;|&])/,
65 lookbehind: true
66 },
67 'boolean': {
68 pattern: /(^|[\s;|&])(?:true|false)(?=$|[\s;|&])/,
69 lookbehind: true
70 },
71 'operator': /&&?|\|\|?|==?|!=?|<<<?|>>|<=?|>=?|=~/,
72 'punctuation': /\$?\(\(?|\)\)?|\.\.|[{}[\];]/
73 };
74
75 var inside = insideString.variable[1].inside;
76 inside.string = Prism.languages.bash.string;
77 inside['function'] = Prism.languages.bash['function'];
78 inside.keyword = Prism.languages.bash.keyword;
79 inside['boolean'] = Prism.languages.bash['boolean'];
80 inside.operator = Prism.languages.bash.operator;
81 inside.punctuation = Prism.languages.bash.punctuation;
82
83 Prism.languages.shell = Prism.languages.bash;
84})(Prism);
diff --git a/source/assets/languages/prism-c.js b/source/assets/languages/prism-c.js
deleted file mode 100644
index 86ffac0..0000000
--- a/source/assets/languages/prism-c.js
+++ /dev/null
@@ -1,33 +0,0 @@
1Prism.languages.c = Prism.languages.extend('clike', {
2 'keyword': /\b(?:_Alignas|_Alignof|_Atomic|_Bool|_Complex|_Generic|_Imaginary|_Noreturn|_Static_assert|_Thread_local|asm|typeof|inline|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|int|long|register|return|short|signed|sizeof|static|struct|switch|typedef|union|unsigned|void|volatile|while)\b/,
3 'operator': /-[>-]?|\+\+?|!=?|<<?=?|>>?=?|==?|&&?|\|\|?|[~^%?*\/]/,
4 'number': /(?:\b0x[\da-f]+|(?:\b\d+\.?\d*|\B\.\d+)(?:e[+-]?\d+)?)[ful]*/i
5});
6
7Prism.languages.insertBefore('c', 'string', {
8 'macro': {
9 // allow for multiline macro definitions
10 // spaces after the # character compile fine with gcc
11 pattern: /(^\s*)#\s*[a-z]+(?:[^\r\n\\]|\\(?:\r\n|[\s\S]))*/im,
12 lookbehind: true,
13 alias: 'property',
14 inside: {
15 // highlight the path of the include statement as a string
16 'string': {
17 pattern: /(#\s*include\s*)(?:<.+?>|("|')(?:\\?.)+?\2)/,
18 lookbehind: true
19 },
20 // highlight macro directives as keywords
21 'directive': {
22 pattern: /(#\s*)\b(?:define|defined|elif|else|endif|error|ifdef|ifndef|if|import|include|line|pragma|undef|using)\b/,
23 lookbehind: true,
24 alias: 'keyword'
25 }
26 }
27 },
28 // highlight predefined macros as constants
29 'constant': /\b(?:__FILE__|__LINE__|__DATE__|__TIME__|__TIMESTAMP__|__func__|EOF|NULL|SEEK_CUR|SEEK_END|SEEK_SET|stdin|stdout|stderr)\b/
30});
31
32delete Prism.languages.c['class-name'];
33delete Prism.languages.c['boolean'];
diff --git a/source/assets/languages/prism-css.js b/source/assets/languages/prism-css.js
deleted file mode 100644
index e6fdf6f..0000000
--- a/source/assets/languages/prism-css.js
+++ /dev/null
@@ -1,52 +0,0 @@
1Prism.languages.css = {
2 'comment': /\/\*[\s\S]*?\*\//,
3 'atrule': {
4 pattern: /@[\w-]+?.*?(?:;|(?=\s*\{))/i,
5 inside: {
6 'rule': /@[\w-]+/
7 // See rest below
8 }
9 },
10 'url': /url\((?:(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1|.*?)\)/i,
11 'selector': /[^{}\s][^{};]*?(?=\s*\{)/,
12 'string': {
13 pattern: /("|')(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,
14 greedy: true
15 },
16 'property': /[-_a-z\xA0-\uFFFF][-\w\xA0-\uFFFF]*(?=\s*:)/i,
17 'important': /\B!important\b/i,
18 'function': /[-a-z0-9]+(?=\()/i,
19 'punctuation': /[(){};:]/
20};
21
22Prism.languages.css['atrule'].inside.rest = Prism.languages.css;
23
24if (Prism.languages.markup) {
25 Prism.languages.insertBefore('markup', 'tag', {
26 'style': {
27 pattern: /(<style[\s\S]*?>)[\s\S]*?(?=<\/style>)/i,
28 lookbehind: true,
29 inside: Prism.languages.css,
30 alias: 'language-css',
31 greedy: true
32 }
33 });
34
35 Prism.languages.insertBefore('inside', 'attr-value', {
36 'style-attr': {
37 pattern: /\s*style=("|')(?:\\[\s\S]|(?!\1)[^\\])*\1/i,
38 inside: {
39 'attr-name': {
40 pattern: /^\s*style/i,
41 inside: Prism.languages.markup.tag.inside
42 },
43 'punctuation': /^\s*=\s*['"]|['"]\s*$/,
44 'attr-value': {
45 pattern: /.+/i,
46 inside: Prism.languages.css
47 }
48 },
49 alias: 'language-css'
50 }
51 }, Prism.languages.markup.tag);
52} \ No newline at end of file
diff --git a/source/assets/languages/prism-go.js b/source/assets/languages/prism-go.js
deleted file mode 100644
index cc792a0..0000000
--- a/source/assets/languages/prism-go.js
+++ /dev/null
@@ -1,12 +0,0 @@
1Prism.languages.go = Prism.languages.extend('clike', {
2 'keyword': /\b(?:break|case|chan|const|continue|default|defer|else|fallthrough|for|func|go(?:to)?|if|import|interface|map|package|range|return|select|struct|switch|type|var)\b/,
3 'builtin': /\b(?:bool|byte|complex(?:64|128)|error|float(?:32|64)|rune|string|u?int(?:8|16|32|64)?|uintptr|append|cap|close|complex|copy|delete|imag|len|make|new|panic|print(?:ln)?|real|recover)\b/,
4 'boolean': /\b(?:_|iota|nil|true|false)\b/,
5 'operator': /[*\/%^!=]=?|\+[=+]?|-[=-]?|\|[=|]?|&(?:=|&|\^=?)?|>(?:>=?|=)?|<(?:<=?|=|-)?|:=|\.\.\./,
6 'number': /(?:\b0x[a-f\d]+|(?:\b\d+\.?\d*|\B\.\d+)(?:e[-+]?\d+)?)i?/i,
7 'string': {
8 pattern: /(["'`])(\\[\s\S]|(?!\1)[^\\])*\1/,
9 greedy: true
10 }
11});
12delete Prism.languages.go['class-name'];
diff --git a/source/assets/languages/prism-javascript.js b/source/assets/languages/prism-javascript.js
deleted file mode 100644
index 7800a7d..0000000
--- a/source/assets/languages/prism-javascript.js
+++ /dev/null
@@ -1,56 +0,0 @@
1Prism.languages.javascript = Prism.languages.extend('clike', {
2 'keyword': /\b(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|var|void|while|with|yield)\b/,
3 'number': /\b(?:0[xX][\dA-Fa-f]+|0[bB][01]+|0[oO][0-7]+|NaN|Infinity)\b|(?:\b\d+\.?\d*|\B\.\d+)(?:[Ee][+-]?\d+)?/,
4 // Allow for all non-ASCII characters (See http://stackoverflow.com/a/2008444)
5 'function': /[_$a-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*\()/i,
6 'operator': /-[-=]?|\+[+=]?|!=?=?|<<?=?|>>?>?=?|=(?:==?|>)?|&[&=]?|\|[|=]?|\*\*?=?|\/=?|~|\^=?|%=?|\?|\.{3}/
7});
8
9Prism.languages.insertBefore('javascript', 'keyword', {
10 'regex': {
11 pattern: /((?:^|[^$\w\xA0-\uFFFF."'\])\s])\s*)\/(\[[^\]\r\n]+]|\\.|[^/\\\[\r\n])+\/[gimyu]{0,5}(?=\s*($|[\r\n,.;})\]]))/,
12 lookbehind: true,
13 greedy: true
14 },
15 // This must be declared before keyword because we use "function" inside the look-forward
16 'function-variable': {
17 pattern: /[_$a-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*=\s*(?:function\b|(?:\([^()]*\)|[_$a-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*)\s*=>))/i,
18 alias: 'function'
19 },
20 'constant': /\b[A-Z][A-Z\d_]*\b/
21});
22
23Prism.languages.insertBefore('javascript', 'string', {
24 'template-string': {
25 pattern: /`(?:\\[\s\S]|\${[^}]+}|[^\\`])*`/,
26 greedy: true,
27 inside: {
28 'interpolation': {
29 pattern: /\${[^}]+}/,
30 inside: {
31 'interpolation-punctuation': {
32 pattern: /^\${|}$/,
33 alias: 'punctuation'
34 },
35 rest: null // See below
36 }
37 },
38 'string': /[\s\S]+/
39 }
40 }
41});
42Prism.languages.javascript['template-string'].inside['interpolation'].inside.rest = Prism.languages.javascript;
43
44if (Prism.languages.markup) {
45 Prism.languages.insertBefore('markup', 'tag', {
46 'script': {
47 pattern: /(<script[\s\S]*?>)[\s\S]*?(?=<\/script>)/i,
48 lookbehind: true,
49 inside: Prism.languages.javascript,
50 alias: 'language-javascript',
51 greedy: true
52 }
53 });
54}
55
56Prism.languages.js = Prism.languages.javascript;
diff --git a/source/assets/languages/prism-json.js b/source/assets/languages/prism-json.js
deleted file mode 100644
index 06e847e..0000000
--- a/source/assets/languages/prism-json.js
+++ /dev/null
@@ -1,14 +0,0 @@
1Prism.languages.json = {
2 'property': /"(?:\\.|[^\\"\r\n])*"(?=\s*:)/i,
3 'string': {
4 pattern: /"(?:\\.|[^\\"\r\n])*"(?!\s*:)/,
5 greedy: true
6 },
7 'number': /\b0x[\dA-Fa-f]+\b|(?:\b\d+\.?\d*|\B\.\d+)(?:[Ee][+-]?\d+)?/,
8 'punctuation': /[{}[\]);,]/,
9 'operator': /:/g,
10 'boolean': /\b(?:true|false)\b/i,
11 'null': /\bnull\b/i
12};
13
14Prism.languages.jsonp = Prism.languages.json;
diff --git a/source/assets/languages/prism-nginx.js b/source/assets/languages/prism-nginx.js
deleted file mode 100644
index c3fea0c..0000000
--- a/source/assets/languages/prism-nginx.js
+++ /dev/null
@@ -1,11 +0,0 @@
1Prism.languages.nginx = Prism.languages.extend('clike', {
2 'comment': {
3 pattern: /(^|[^"{\\])#.*/,
4 lookbehind: true
5 },
6 'keyword': /\b(?:CONTENT_|DOCUMENT_|GATEWAY_|HTTP_|HTTPS|if_not_empty|PATH_|QUERY_|REDIRECT_|REMOTE_|REQUEST_|SCGI|SCRIPT_|SERVER_|http|events|accept_mutex|accept_mutex_delay|access_log|add_after_body|add_before_body|add_header|addition_types|aio|alias|allow|ancient_browser|ancient_browser_value|auth|auth_basic|auth_basic_user_file|auth_http|auth_http_header|auth_http_timeout|autoindex|autoindex_exact_size|autoindex_localtime|break|charset|charset_map|charset_types|chunked_transfer_encoding|client_body_buffer_size|client_body_in_file_only|client_body_in_single_buffer|client_body_temp_path|client_body_timeout|client_header_buffer_size|client_header_timeout|client_max_body_size|connection_pool_size|create_full_put_path|daemon|dav_access|dav_methods|debug_connection|debug_points|default_type|deny|devpoll_changes|devpoll_events|directio|directio_alignment|disable_symlinks|empty_gif|env|epoll_events|error_log|error_page|expires|fastcgi_buffer_size|fastcgi_buffers|fastcgi_busy_buffers_size|fastcgi_cache|fastcgi_cache_bypass|fastcgi_cache_key|fastcgi_cache_lock|fastcgi_cache_lock_timeout|fastcgi_cache_methods|fastcgi_cache_min_uses|fastcgi_cache_path|fastcgi_cache_purge|fastcgi_cache_use_stale|fastcgi_cache_valid|fastcgi_connect_timeout|fastcgi_hide_header|fastcgi_ignore_client_abort|fastcgi_ignore_headers|fastcgi_index|fastcgi_intercept_errors|fastcgi_keep_conn|fastcgi_max_temp_file_size|fastcgi_next_upstream|fastcgi_no_cache|fastcgi_param|fastcgi_pass|fastcgi_pass_header|fastcgi_read_timeout|fastcgi_redirect_errors|fastcgi_send_timeout|fastcgi_split_path_info|fastcgi_store|fastcgi_store_access|fastcgi_temp_file_write_size|fastcgi_temp_path|flv|geo|geoip_city|geoip_country|google_perftools_profiles|gzip|gzip_buffers|gzip_comp_level|gzip_disable|gzip_http_version|gzip_min_length|gzip_proxied|gzip_static|gzip_types|gzip_vary|if|if_modified_since|ignore_invalid_headers|image_filter|image_filter_buffer|image_filter_jpeg_quality|image_filter_sharpen|image_filter_transparency|imap_capabilities|imap_client_buffer|include|index|internal|ip_hash|keepalive|keepalive_disable|keepalive_requests|keepalive_timeout|kqueue_changes|kqueue_events|large_client_header_buffers|limit_conn|limit_conn_log_level|limit_conn_zone|limit_except|limit_rate|limit_rate_after|limit_req|limit_req_log_level|limit_req_zone|limit_zone|lingering_close|lingering_time|lingering_timeout|listen|location|lock_file|log_format|log_format_combined|log_not_found|log_subrequest|map|map_hash_bucket_size|map_hash_max_size|master_process|max_ranges|memcached_buffer_size|memcached_connect_timeout|memcached_next_upstream|memcached_pass|memcached_read_timeout|memcached_send_timeout|merge_slashes|min_delete_depth|modern_browser|modern_browser_value|mp4|mp4_buffer_size|mp4_max_buffer_size|msie_padding|msie_refresh|multi_accept|open_file_cache|open_file_cache_errors|open_file_cache_min_uses|open_file_cache_valid|open_log_file_cache|optimize_server_names|override_charset|pcre_jit|perl|perl_modules|perl_require|perl_set|pid|pop3_auth|pop3_capabilities|port_in_redirect|post_action|postpone_output|protocol|proxy|proxy_buffer|proxy_buffer_size|proxy_buffering|proxy_buffers|proxy_busy_buffers_size|proxy_cache|proxy_cache_bypass|proxy_cache_key|proxy_cache_lock|proxy_cache_lock_timeout|proxy_cache_methods|proxy_cache_min_uses|proxy_cache_path|proxy_cache_use_stale|proxy_cache_valid|proxy_connect_timeout|proxy_cookie_domain|proxy_cookie_path|proxy_headers_hash_bucket_size|proxy_headers_hash_max_size|proxy_hide_header|proxy_http_version|proxy_ignore_client_abort|proxy_ignore_headers|proxy_intercept_errors|proxy_max_temp_file_size|proxy_method|proxy_next_upstream|proxy_no_cache|proxy_pass|proxy_pass_error_message|proxy_pass_header|proxy_pass_request_body|proxy_pass_request_headers|proxy_read_timeout|proxy_redirect|proxy_redirect_errors|proxy_send_lowat|proxy_send_timeout|proxy_set_body|proxy_set_header|proxy_ssl_session_reuse|proxy_store|proxy_store_access|proxy_temp_file_write_size|proxy_temp_path|proxy_timeout|proxy_upstream_fail_timeout|proxy_upstream_max_fails|random_index|read_ahead|real_ip_header|recursive_error_pages|request_pool_size|reset_timedout_connection|resolver|resolver_timeout|return|rewrite|root|rtsig_overflow_events|rtsig_overflow_test|rtsig_overflow_threshold|rtsig_signo|satisfy|satisfy_any|secure_link_secret|send_lowat|send_timeout|sendfile|sendfile_max_chunk|server|server_name|server_name_in_redirect|server_names_hash_bucket_size|server_names_hash_max_size|server_tokens|set|set_real_ip_from|smtp_auth|smtp_capabilities|so_keepalive|source_charset|split_clients|ssi|ssi_silent_errors|ssi_types|ssi_value_length|ssl|ssl_certificate|ssl_certificate_key|ssl_ciphers|ssl_client_certificate|ssl_crl|ssl_dhparam|ssl_engine|ssl_prefer_server_ciphers|ssl_protocols|ssl_session_cache|ssl_session_timeout|ssl_verify_client|ssl_verify_depth|starttls|stub_status|sub_filter|sub_filter_once|sub_filter_types|tcp_nodelay|tcp_nopush|timeout|timer_resolution|try_files|types|types_hash_bucket_size|types_hash_max_size|underscores_in_headers|uninitialized_variable_warn|upstream|use|user|userid|userid_domain|userid_expires|userid_name|userid_p3p|userid_path|userid_service|valid_referers|variables_hash_bucket_size|variables_hash_max_size|worker_connections|worker_cpu_affinity|worker_priority|worker_processes|worker_rlimit_core|worker_rlimit_nofile|worker_rlimit_sigpending|working_directory|xclient|xml_entities|xslt_entities|xslt_stylesheet|xslt_types)\b/i
7});
8
9Prism.languages.insertBefore('nginx', 'keyword', {
10 'variable': /\$[a-z_]+/i
11}); \ No newline at end of file
diff --git a/source/assets/languages/prism-pascal.js b/source/assets/languages/prism-pascal.js
deleted file mode 100644
index bc7a283..0000000
--- a/source/assets/languages/prism-pascal.js
+++ /dev/null
@@ -1,55 +0,0 @@
1// Based on Free Pascal
2
3/* TODO
4 Support inline asm ?
5*/
6
7Prism.languages.pascal = {
8 'comment': [
9 /\(\*[\s\S]+?\*\)/,
10 /\{[\s\S]+?\}/,
11 /\/\/.*/
12 ],
13 'string': {
14 pattern: /(?:'(?:''|[^'\r\n])*'|#[&$%]?[a-f\d]+)+|\^[a-z]/i,
15 greedy: true
16 },
17 'keyword': [
18 {
19 // Turbo Pascal
20 pattern: /(^|[^&])\b(?:absolute|array|asm|begin|case|const|constructor|destructor|do|downto|else|end|file|for|function|goto|if|implementation|inherited|inline|interface|label|nil|object|of|operator|packed|procedure|program|record|reintroduce|repeat|self|set|string|then|to|type|unit|until|uses|var|while|with)\b/i,
21 lookbehind: true
22 },
23 {
24 // Free Pascal
25 pattern: /(^|[^&])\b(?:dispose|exit|false|new|true)\b/i,
26 lookbehind: true
27 },
28 {
29 // Object Pascal
30 pattern: /(^|[^&])\b(?:class|dispinterface|except|exports|finalization|finally|initialization|inline|library|on|out|packed|property|raise|resourcestring|threadvar|try)\b/i,
31 lookbehind: true
32 },
33 {
34 // Modifiers
35 pattern: /(^|[^&])\b(?:absolute|abstract|alias|assembler|bitpacked|break|cdecl|continue|cppdecl|cvar|default|deprecated|dynamic|enumerator|experimental|export|external|far|far16|forward|generic|helper|implements|index|interrupt|iochecks|local|message|name|near|nodefault|noreturn|nostackframe|oldfpccall|otherwise|overload|override|pascal|platform|private|protected|public|published|read|register|reintroduce|result|safecall|saveregisters|softfloat|specialize|static|stdcall|stored|strict|unaligned|unimplemented|varargs|virtual|write)\b/i,
36 lookbehind: true
37 }
38 ],
39 'number': [
40 // Hexadecimal, octal and binary
41 /(?:[&%]\d+|\$[a-f\d]+)/i,
42 // Decimal
43 /\b\d+(?:\.\d+)?(?:e[+-]?\d+)?/i
44 ],
45 'operator': [
46 /\.\.|\*\*|:=|<[<=>]?|>[>=]?|[+\-*\/]=?|[@^=]/i,
47 {
48 pattern: /(^|[^&])\b(?:and|as|div|exclude|in|include|is|mod|not|or|shl|shr|xor)\b/,
49 lookbehind: true
50 }
51 ],
52 'punctuation': /\(\.|\.\)|[()\[\]:;,.]/
53};
54
55Prism.languages.objectpascal = Prism.languages.pascal; \ No newline at end of file
diff --git a/source/assets/languages/prism-python.js b/source/assets/languages/prism-python.js
deleted file mode 100644
index ecad408..0000000
--- a/source/assets/languages/prism-python.js
+++ /dev/null
@@ -1,29 +0,0 @@
1Prism.languages.python = {
2 'comment': {
3 pattern: /(^|[^\\])#.*/,
4 lookbehind: true
5 },
6 'triple-quoted-string': {
7 pattern: /("""|''')[\s\S]+?\1/,
8 greedy: true,
9 alias: 'string'
10 },
11 'string': {
12 pattern: /("|')(?:\\.|(?!\1)[^\\\r\n])*\1/,
13 greedy: true
14 },
15 'function': {
16 pattern: /((?:^|\s)def[ \t]+)[a-zA-Z_]\w*(?=\s*\()/g,
17 lookbehind: true
18 },
19 'class-name': {
20 pattern: /(\bclass\s+)\w+/i,
21 lookbehind: true
22 },
23 'keyword': /\b(?:as|assert|async|await|break|class|continue|def|del|elif|else|except|exec|finally|for|from|global|if|import|in|is|lambda|nonlocal|pass|print|raise|return|try|while|with|yield)\b/,
24 'builtin':/\b(?:__import__|abs|all|any|apply|ascii|basestring|bin|bool|buffer|bytearray|bytes|callable|chr|classmethod|cmp|coerce|compile|complex|delattr|dict|dir|divmod|enumerate|eval|execfile|file|filter|float|format|frozenset|getattr|globals|hasattr|hash|help|hex|id|input|int|intern|isinstance|issubclass|iter|len|list|locals|long|map|max|memoryview|min|next|object|oct|open|ord|pow|property|range|raw_input|reduce|reload|repr|reversed|round|set|setattr|slice|sorted|staticmethod|str|sum|super|tuple|type|unichr|unicode|vars|xrange|zip)\b/,
25 'boolean': /\b(?:True|False|None)\b/,
26 'number': /(?:\b(?=\d)|\B(?=\.))(?:0[bo])?(?:(?:\d|0x[\da-f])[\da-f]*\.?\d*|\.\d+)(?:e[+-]?\d+)?j?\b/i,
27 'operator': /[-+%=]=?|!=|\*\*?=?|\/\/?=?|<[<=>]?|>[=>]?|[&|^~]|\b(?:or|and|not)\b/,
28 'punctuation': /[{}[\];(),.:]/
29};
diff --git a/source/assets/prism.css b/source/assets/prism.css
deleted file mode 100644
index 21c8aa8..0000000
--- a/source/assets/prism.css
+++ /dev/null
@@ -1,167 +0,0 @@
1/**
2 * prism.js default theme for JavaScript, CSS and HTML
3 * Based on dabblet (http://dabblet.com)
4 * @author Lea Verou
5 */
6
7 code[class*="language-"],
8 pre[class*="language-"] {
9 color: black;
10 font-family: monospace;
11 text-align: left;
12 white-space: pre;
13 word-spacing: normal;
14 word-break: normal;
15 word-wrap: normal;
16 line-height: 1.5;
17
18 -moz-tab-size: 4;
19 -o-tab-size: 4;
20 tab-size: 4;
21
22 -webkit-hyphens: none;
23 -moz-hyphens: none;
24 -ms-hyphens: none;
25 hyphens: none;
26 }
27
28 pre[class*="language-"]::-moz-selection, pre[class*="language-"] ::-moz-selection,
29 code[class*="language-"]::-moz-selection, code[class*="language-"] ::-moz-selection {
30 text-shadow: none;
31 }
32
33 pre[class*="language-"]::selection, pre[class*="language-"] ::selection,
34 code[class*="language-"]::selection, code[class*="language-"] ::selection {
35 text-shadow: none;
36 }
37
38 @media print {
39 code[class*="language-"],
40 pre[class*="language-"] {
41 text-shadow: none;
42 }
43 }
44
45 /* Code blocks */
46 pre[class*="language-"] {
47 padding: 1em;
48 margin: .5em 0;
49 overflow: auto;
50 }
51
52 :not(pre) > code[class*="language-"],
53 pre[class*="language-"] {
54 }
55
56 /* Inline code */
57 :not(pre) > code[class*="language-"] {
58 padding: .1em;
59 border-radius: .3em;
60 white-space: normal;
61 }
62
63 .token.comment,
64 .token.prolog,
65 .token.doctype,
66 .token.cdata {
67 color: slategray;
68 }
69
70 .token.punctuation {
71 color: #999;
72 }
73
74 .namespace {
75 opacity: .7;
76 }
77
78 .token.property,
79 .token.tag,
80 .token.boolean,
81 .token.number,
82 .token.constant,
83 .token.symbol,
84 .token.deleted {
85 color: #905;
86 }
87
88 .token.selector,
89 .token.attr-name,
90 .token.string,
91 .token.char,
92 .token.builtin,
93 .token.inserted {
94 color: #690;
95 }
96
97 .token.operator,
98 .token.entity,
99 .token.url,
100 .language-css .token.string,
101 .style .token.string {
102 color: #9a6e3a;
103 /*background: hsla(0, 0%, 100%, .5);*/
104 }
105
106 .token.atrule,
107 .token.attr-value,
108 .token.keyword {
109 color: #07a;
110 }
111
112 .token.function,
113 .token.class-name {
114 color: #DD4A68;
115 }
116
117 .token.regex,
118 .token.important,
119 .token.variable {
120 color: #e90;
121 }
122
123 .token.important,
124 .token.bold {
125 font-weight: bold;
126 }
127 .token.italic {
128 font-style: italic;
129 }
130
131 .token.entity {
132 cursor: help;
133 }
134
135 pre[class*="language-"].line-numbers {
136 position: relative;
137 padding-left: 3.8em;
138 counter-reset: linenumber;
139}
140
141pre[class*="language-"].line-numbers > code {
142 position: relative;
143 white-space: inherit;
144}
145
146.line-numbers .line-numbers-rows {
147 position: absolute;
148 pointer-events: none;
149 top: 0;
150 font-size: 100%;
151 left: -3.8em;
152 width: 3em; /* works for line-numbers below 1000 lines */
153 letter-spacing: -1px;
154 border-right: 1px solid #999;
155
156 -webkit-user-select: none;
157 -moz-user-select: none;
158 -ms-user-select: none;
159 user-select: none;
160
161}
162
163 .line-numbers-rows > span {
164 pointer-events: none;
165 display: block;
166 counter-increment: linenumber;
167 }
diff --git a/source/assets/prism.js b/source/assets/prism.js
deleted file mode 100644
index 304be1e..0000000
--- a/source/assets/prism.js
+++ /dev/null
@@ -1,1071 +0,0 @@
1
2/* **********************************************
3 Begin prism-core.js
4********************************************** */
5
6var _self = (typeof window !== 'undefined')
7 ? window // if in browser
8 : (
9 (typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope)
10 ? self // if in worker
11 : {} // if in node js
12 );
13
14/**
15 * Prism: Lightweight, robust, elegant syntax highlighting
16 * MIT license http://www.opensource.org/licenses/mit-license.php/
17 * @author Lea Verou http://lea.verou.me
18 */
19
20var Prism = (function () {
21
22 // Private helper vars
23 var lang = /\blang(?:uage)?-([\w-]+)\b/i;
24 var uniqueId = 0;
25
26 var _ = _self.Prism = {
27 manual: _self.Prism && _self.Prism.manual,
28 disableWorkerMessageHandler: _self.Prism && _self.Prism.disableWorkerMessageHandler,
29 util: {
30 encode: function (tokens) {
31 if (tokens instanceof Token) {
32 return new Token(tokens.type, _.util.encode(tokens.content), tokens.alias);
33 } else if (_.util.type(tokens) === 'Array') {
34 return tokens.map(_.util.encode);
35 } else {
36 return tokens.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/\u00a0/g, ' ');
37 }
38 },
39
40 type: function (o) {
41 return Object.prototype.toString.call(o).slice(8, -1);
42 },
43
44 objId: function (obj) {
45 if (!obj['__id']) {
46 Object.defineProperty(obj, '__id', { value: ++uniqueId });
47 }
48 return obj['__id'];
49 },
50
51 // Deep clone a language definition (e.g. to extend it)
52 clone: function (o, visited) {
53 var type = _.util.type(o);
54 visited = visited || {};
55
56 switch (type) {
57 case 'Object':
58 if (visited[_.util.objId(o)]) {
59 return visited[_.util.objId(o)];
60 }
61 var clone = {};
62 visited[_.util.objId(o)] = clone;
63
64 for (var key in o) {
65 if (o.hasOwnProperty(key)) {
66 clone[key] = _.util.clone(o[key], visited);
67 }
68 }
69
70 return clone;
71
72 case 'Array':
73 if (visited[_.util.objId(o)]) {
74 return visited[_.util.objId(o)];
75 }
76 var clone = [];
77 visited[_.util.objId(o)] = clone;
78
79 o.forEach(function (v, i) {
80 clone[i] = _.util.clone(v, visited);
81 });
82
83 return clone;
84 }
85
86 return o;
87 }
88 },
89
90 languages: {
91 extend: function (id, redef) {
92 var lang = _.util.clone(_.languages[id]);
93
94 for (var key in redef) {
95 lang[key] = redef[key];
96 }
97
98 return lang;
99 },
100
101 /**
102 * Insert a token before another token in a language literal
103 * As this needs to recreate the object (we cannot actually insert before keys in object literals),
104 * we cannot just provide an object, we need an object and a key.
105 * @param inside The key (or language id) of the parent
106 * @param before The key to insert before.
107 * @param insert Object with the key/value pairs to insert
108 * @param root The object that contains `inside`. If equal to Prism.languages, it can be omitted.
109 */
110 insertBefore: function (inside, before, insert, root) {
111 root = root || _.languages;
112 var grammar = root[inside];
113 var ret = {};
114
115 for (var token in grammar) {
116 if (grammar.hasOwnProperty(token)) {
117
118 if (token == before) {
119 for (var newToken in insert) {
120 if (insert.hasOwnProperty(newToken)) {
121 ret[newToken] = insert[newToken];
122 }
123 }
124 }
125
126 // Do not insert token which also occur in insert. See #1525
127 if (!insert.hasOwnProperty(token)) {
128 ret[token] = grammar[token];
129 }
130 }
131 }
132
133 var old = root[inside];
134 root[inside] = ret;
135
136 // Update references in other language definitions
137 _.languages.DFS(_.languages, function (key, value) {
138 if (value === old && key != inside) {
139 this[key] = ret;
140 }
141 });
142
143 return ret;
144 },
145
146 // Traverse a language definition with Depth First Search
147 DFS: function (o, callback, type, visited) {
148 visited = visited || {};
149 for (var i in o) {
150 if (o.hasOwnProperty(i)) {
151 callback.call(o, i, o[i], type || i);
152
153 if (_.util.type(o[i]) === 'Object' && !visited[_.util.objId(o[i])]) {
154 visited[_.util.objId(o[i])] = true;
155 _.languages.DFS(o[i], callback, null, visited);
156 }
157 else if (_.util.type(o[i]) === 'Array' && !visited[_.util.objId(o[i])]) {
158 visited[_.util.objId(o[i])] = true;
159 _.languages.DFS(o[i], callback, i, visited);
160 }
161 }
162 }
163 }
164 },
165 plugins: {},
166
167 highlightAll: function (async, callback) {
168 _.highlightAllUnder(document, async, callback);
169 },
170
171 highlightAllUnder: function (container, async, callback) {
172 var env = {
173 callback: callback,
174 selector: 'code[class*="language-"], [class*="language-"] code, code[class*="lang-"], [class*="lang-"] code'
175 };
176
177 _.hooks.run("before-highlightall", env);
178
179 var elements = env.elements || container.querySelectorAll(env.selector);
180
181 for (var i = 0, element; element = elements[i++];) {
182 _.highlightElement(element, async === true, env.callback);
183 }
184 },
185
186 highlightElement: function (element, async, callback) {
187 // Find language
188 var language, grammar, parent = element;
189
190 while (parent && !lang.test(parent.className)) {
191 parent = parent.parentNode;
192 }
193
194 if (parent) {
195 language = (parent.className.match(lang) || [, ''])[1].toLowerCase();
196 grammar = _.languages[language];
197 }
198
199 // Set language on the element, if not present
200 element.className = element.className.replace(lang, '').replace(/\s+/g, ' ') + ' language-' + language;
201
202 if (element.parentNode) {
203 // Set language on the parent, for styling
204 parent = element.parentNode;
205
206 if (/pre/i.test(parent.nodeName)) {
207 parent.className = parent.className.replace(lang, '').replace(/\s+/g, ' ') + ' language-' + language;
208 }
209 }
210
211 var code = element.textContent;
212
213 var env = {
214 element: element,
215 language: language,
216 grammar: grammar,
217 code: code
218 };
219
220 var insertHighlightedCode = function (highlightedCode) {
221 env.highlightedCode = highlightedCode;
222
223 _.hooks.run('before-insert', env);
224
225 env.element.innerHTML = env.highlightedCode;
226
227 _.hooks.run('after-highlight', env);
228 _.hooks.run('complete', env);
229 callback && callback.call(env.element);
230 }
231
232 _.hooks.run('before-sanity-check', env);
233
234 if (!env.code) {
235 _.hooks.run('complete', env);
236 return;
237 }
238
239 _.hooks.run('before-highlight', env);
240
241 if (!env.grammar) {
242 insertHighlightedCode(_.util.encode(env.code));
243 return;
244 }
245
246 if (async && _self.Worker) {
247 var worker = new Worker(_.filename);
248
249 worker.onmessage = function (evt) {
250 insertHighlightedCode(evt.data);
251 };
252
253 worker.postMessage(JSON.stringify({
254 language: env.language,
255 code: env.code,
256 immediateClose: true
257 }));
258 }
259 else {
260 insertHighlightedCode(_.highlight(env.code, env.grammar, env.language));
261 }
262 },
263
264 highlight: function (text, grammar, language) {
265 var env = {
266 code: text,
267 grammar: grammar,
268 language: language
269 };
270 _.hooks.run('before-tokenize', env);
271 env.tokens = _.tokenize(env.code, env.grammar);
272 _.hooks.run('after-tokenize', env);
273 return Token.stringify(_.util.encode(env.tokens), env.language);
274 },
275
276 matchGrammar: function (text, strarr, grammar, index, startPos, oneshot, target) {
277 var Token = _.Token;
278
279 for (var token in grammar) {
280 if (!grammar.hasOwnProperty(token) || !grammar[token]) {
281 continue;
282 }
283
284 if (token == target) {
285 return;
286 }
287
288 var patterns = grammar[token];
289 patterns = (_.util.type(patterns) === "Array") ? patterns : [patterns];
290
291 for (var j = 0; j < patterns.length; ++j) {
292 var pattern = patterns[j],
293 inside = pattern.inside,
294 lookbehind = !!pattern.lookbehind,
295 greedy = !!pattern.greedy,
296 lookbehindLength = 0,
297 alias = pattern.alias;
298
299 if (greedy && !pattern.pattern.global) {
300 // Without the global flag, lastIndex won't work
301 var flags = pattern.pattern.toString().match(/[imuy]*$/)[0];
302 pattern.pattern = RegExp(pattern.pattern.source, flags + "g");
303 }
304
305 pattern = pattern.pattern || pattern;
306
307 // Don’t cache length as it changes during the loop
308 for (var i = index, pos = startPos; i < strarr.length; pos += strarr[i].length, ++i) {
309
310 var str = strarr[i];
311
312 if (strarr.length > text.length) {
313 // Something went terribly wrong, ABORT, ABORT!
314 return;
315 }
316
317 if (str instanceof Token) {
318 continue;
319 }
320
321 if (greedy && i != strarr.length - 1) {
322 pattern.lastIndex = pos;
323 var match = pattern.exec(text);
324 if (!match) {
325 break;
326 }
327
328 var from = match.index + (lookbehind ? match[1].length : 0),
329 to = match.index + match[0].length,
330 k = i,
331 p = pos;
332
333 for (var len = strarr.length; k < len && (p < to || (!strarr[k].type && !strarr[k - 1].greedy)); ++k) {
334 p += strarr[k].length;
335 // Move the index i to the element in strarr that is closest to from
336 if (from >= p) {
337 ++i;
338 pos = p;
339 }
340 }
341
342 // If strarr[i] is a Token, then the match starts inside another Token, which is invalid
343 if (strarr[i] instanceof Token) {
344 continue;
345 }
346
347 // Number of tokens to delete and replace with the new match
348 delNum = k - i;
349 str = text.slice(pos, p);
350 match.index -= pos;
351 } else {
352 pattern.lastIndex = 0;
353
354 var match = pattern.exec(str),
355 delNum = 1;
356 }
357
358 if (!match) {
359 if (oneshot) {
360 break;
361 }
362
363 continue;
364 }
365
366 if (lookbehind) {
367 lookbehindLength = match[1] ? match[1].length : 0;
368 }
369
370 var from = match.index + lookbehindLength,
371 match = match[0].slice(lookbehindLength),
372 to = from + match.length,
373 before = str.slice(0, from),
374 after = str.slice(to);
375
376 var args = [i, delNum];
377
378 if (before) {
379 ++i;
380 pos += before.length;
381 args.push(before);
382 }
383
384 var wrapped = new Token(token, inside ? _.tokenize(match, inside) : match, alias, match, greedy);
385
386 args.push(wrapped);
387
388 if (after) {
389 args.push(after);
390 }
391
392 Array.prototype.splice.apply(strarr, args);
393
394 if (delNum != 1)
395 _.matchGrammar(text, strarr, grammar, i, pos, true, token);
396
397 if (oneshot)
398 break;
399 }
400 }
401 }
402 },
403
404 tokenize: function (text, grammar) {
405 var strarr = [text];
406
407 var rest = grammar.rest;
408
409 if (rest) {
410 for (var token in rest) {
411 grammar[token] = rest[token];
412 }
413
414 delete grammar.rest;
415 }
416
417 _.matchGrammar(text, strarr, grammar, 0, 0, false);
418
419 return strarr;
420 },
421
422 hooks: {
423 all: {},
424
425 add: function (name, callback) {
426 var hooks = _.hooks.all;
427
428 hooks[name] = hooks[name] || [];
429
430 hooks[name].push(callback);
431 },
432
433 run: function (name, env) {
434 var callbacks = _.hooks.all[name];
435
436 if (!callbacks || !callbacks.length) {
437 return;
438 }
439
440 for (var i = 0, callback; callback = callbacks[i++];) {
441 callback(env);
442 }
443 }
444 }
445 };
446
447 var Token = _.Token = function (type, content, alias, matchedStr, greedy) {
448 this.type = type;
449 this.content = content;
450 this.alias = alias;
451 // Copy of the full string this token was created from
452 this.length = (matchedStr || "").length | 0;
453 this.greedy = !!greedy;
454 };
455
456 Token.stringify = function (o, language, parent) {
457 if (typeof o == 'string') {
458 return o;
459 }
460
461 if (_.util.type(o) === 'Array') {
462 return o.map(function (element) {
463 return Token.stringify(element, language, o);
464 }).join('');
465 }
466
467 var env = {
468 type: o.type,
469 content: Token.stringify(o.content, language, parent),
470 tag: 'span',
471 classes: ['token', o.type],
472 attributes: {},
473 language: language,
474 parent: parent
475 };
476
477 if (o.alias) {
478 var aliases = _.util.type(o.alias) === 'Array' ? o.alias : [o.alias];
479 Array.prototype.push.apply(env.classes, aliases);
480 }
481
482 _.hooks.run('wrap', env);
483
484 var attributes = Object.keys(env.attributes).map(function (name) {
485 return name + '="' + (env.attributes[name] || '').replace(/"/g, '&quot;') + '"';
486 }).join(' ');
487
488 return '<' + env.tag + ' class="' + env.classes.join(' ') + '"' + (attributes ? ' ' + attributes : '') + '>' + env.content + '</' + env.tag + '>';
489
490 };
491
492 if (!_self.document) {
493 if (!_self.addEventListener) {
494 // in Node.js
495 return _self.Prism;
496 }
497
498 if (!_.disableWorkerMessageHandler) {
499 // In worker
500 _self.addEventListener('message', function (evt) {
501 var message = JSON.parse(evt.data),
502 lang = message.language,
503 code = message.code,
504 immediateClose = message.immediateClose;
505
506 _self.postMessage(_.highlight(code, _.languages[lang], lang));
507 if (immediateClose) {
508 _self.close();
509 }
510 }, false);
511 }
512
513 return _self.Prism;
514 }
515
516 //Get current script and highlight
517 var script = document.currentScript || [].slice.call(document.getElementsByTagName("script")).pop();
518
519 if (script) {
520 _.filename = script.src;
521
522 if (!_.manual && !script.hasAttribute('data-manual')) {
523 if (document.readyState !== "loading") {
524 if (window.requestAnimationFrame) {
525 window.requestAnimationFrame(_.highlightAll);
526 } else {
527 window.setTimeout(_.highlightAll, 16);
528 }
529 }
530 else {
531 document.addEventListener('DOMContentLoaded', _.highlightAll);
532 }
533 }
534 }
535
536 return _self.Prism;
537
538})();
539
540if (typeof module !== 'undefined' && module.exports) {
541 module.exports = Prism;
542}
543
544// hack for components to work correctly in node.js
545if (typeof global !== 'undefined') {
546 global.Prism = Prism;
547}
548
549
550/* **********************************************
551 Begin prism-markup.js
552********************************************** */
553
554Prism.languages.markup = {
555 'comment': /<!--[\s\S]*?-->/,
556 'prolog': /<\?[\s\S]+?\?>/,
557 'doctype': /<!DOCTYPE[\s\S]+?>/i,
558 'cdata': /<!\[CDATA\[[\s\S]*?]]>/i,
559 'tag': {
560 pattern: /<\/?(?!\d)[^\s>\/=$<%]+(?:\s+[^\s>\/=]+(?:=(?:("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|[^\s'">=]+))?)*\s*\/?>/i,
561 greedy: true,
562 inside: {
563 'tag': {
564 pattern: /^<\/?[^\s>\/]+/i,
565 inside: {
566 'punctuation': /^<\/?/,
567 'namespace': /^[^\s>\/:]+:/
568 }
569 },
570 'attr-value': {
571 pattern: /=(?:("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|[^\s'">=]+)/i,
572 inside: {
573 'punctuation': [
574 /^=/,
575 {
576 pattern: /(^|[^\\])["']/,
577 lookbehind: true
578 }
579 ]
580 }
581 },
582 'punctuation': /\/?>/,
583 'attr-name': {
584 pattern: /[^\s>\/]+/,
585 inside: {
586 'namespace': /^[^\s>\/:]+:/
587 }
588 }
589
590 }
591 },
592 'entity': /&#?[\da-z]{1,8};/i
593};
594
595Prism.languages.markup['tag'].inside['attr-value'].inside['entity'] =
596 Prism.languages.markup['entity'];
597
598// Plugin to make entity title show the real entity, idea by Roman Komarov
599Prism.hooks.add('wrap', function (env) {
600
601 if (env.type === 'entity') {
602 env.attributes['title'] = env.content.replace(/&amp;/, '&');
603 }
604});
605
606Prism.languages.xml = Prism.languages.extend('markup', {});
607Prism.languages.html = Prism.languages.markup;
608Prism.languages.mathml = Prism.languages.markup;
609Prism.languages.svg = Prism.languages.markup;
610
611
612/* **********************************************
613 Begin prism-css.js
614********************************************** */
615
616Prism.languages.css = {
617 'comment': /\/\*[\s\S]*?\*\//,
618 'atrule': {
619 pattern: /@[\w-]+?[\s\S]*?(?:;|(?=\s*\{))/i,
620 inside: {
621 'rule': /@[\w-]+/
622 // See rest below
623 }
624 },
625 'url': /url\((?:(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1|.*?)\)/i,
626 'selector': /[^{}\s][^{};]*?(?=\s*\{)/,
627 'string': {
628 pattern: /("|')(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,
629 greedy: true
630 },
631 'property': /[-_a-z\xA0-\uFFFF][-\w\xA0-\uFFFF]*(?=\s*:)/i,
632 'important': /!important\b/i,
633 'function': /[-a-z0-9]+(?=\()/i,
634 'punctuation': /[(){};:,]/
635};
636
637Prism.languages.css['atrule'].inside.rest = Prism.languages.css;
638
639if (Prism.languages.markup) {
640 Prism.languages.insertBefore('markup', 'tag', {
641 'style': {
642 pattern: /(<style[\s\S]*?>)[\s\S]*?(?=<\/style>)/i,
643 lookbehind: true,
644 inside: Prism.languages.css,
645 alias: 'language-css',
646 greedy: true
647 }
648 });
649
650 Prism.languages.insertBefore('inside', 'attr-value', {
651 'style-attr': {
652 pattern: /\s*style=("|')(?:\\[\s\S]|(?!\1)[^\\])*\1/i,
653 inside: {
654 'attr-name': {
655 pattern: /^\s*style/i,
656 inside: Prism.languages.markup.tag.inside
657 },
658 'punctuation': /^\s*=\s*['"]|['"]\s*$/,
659 'attr-value': {
660 pattern: /.+/i,
661 inside: Prism.languages.css
662 }
663 },
664 alias: 'language-css'
665 }
666 }, Prism.languages.markup.tag);
667}
668
669
670/* **********************************************
671 Begin prism-clike.js
672********************************************** */
673
674Prism.languages.clike = {
675 'comment': [
676 {
677 pattern: /(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/,
678 lookbehind: true
679 },
680 {
681 pattern: /(^|[^\\:])\/\/.*/,
682 lookbehind: true,
683 greedy: true
684 }
685 ],
686 'string': {
687 pattern: /(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,
688 greedy: true
689 },
690 'class-name': {
691 pattern: /((?:\b(?:class|interface|extends|implements|trait|instanceof|new)\s+)|(?:catch\s+\())[\w.\\]+/i,
692 lookbehind: true,
693 inside: {
694 punctuation: /[.\\]/
695 }
696 },
697 'keyword': /\b(?:if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/,
698 'boolean': /\b(?:true|false)\b/,
699 'function': /\w+(?=\()/,
700 'number': /\b0x[\da-f]+\b|(?:\b\d+\.?\d*|\B\.\d+)(?:e[+-]?\d+)?/i,
701 'operator': /--?|\+\+?|!=?=?|<=?|>=?|==?=?|&&?|\|\|?|\?|\*|\/|~|\^|%/,
702 'punctuation': /[{}[\];(),.:]/
703};
704
705
706/* **********************************************
707 Begin prism-javascript.js
708********************************************** */
709
710Prism.languages.javascript = Prism.languages.extend('clike', {
711 'class-name': [
712 Prism.languages.clike['class-name'],
713 {
714 pattern: /(^|[^$\w\xA0-\uFFFF])[_$A-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\.(?:prototype|constructor))/,
715 lookbehind: true
716 }
717 ],
718 'keyword': [
719 {
720 pattern: /((?:^|})\s*)(?:catch|finally)\b/,
721 lookbehind: true
722 },
723 /\b(?:as|async|await|break|case|class|const|continue|debugger|default|delete|do|else|enum|export|extends|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)\b/
724 ],
725 'number': /\b(?:(?:0[xX][\dA-Fa-f]+|0[bB][01]+|0[oO][0-7]+)n?|\d+n|NaN|Infinity)\b|(?:\b\d+\.?\d*|\B\.\d+)(?:[Ee][+-]?\d+)?/,
726 // Allow for all non-ASCII characters (See http://stackoverflow.com/a/2008444)
727 'function': /[_$a-zA-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*\(|\.(?:apply|bind|call)\()/,
728 'operator': /-[-=]?|\+[+=]?|!=?=?|<<?=?|>>?>?=?|=(?:==?|>)?|&[&=]?|\|[|=]?|\*\*?=?|\/=?|~|\^=?|%=?|\?|\.{3}/
729});
730
731Prism.languages.javascript['class-name'][0].pattern = /(\b(?:class|interface|extends|implements|instanceof|new)\s+)[\w.\\]+/
732
733Prism.languages.insertBefore('javascript', 'keyword', {
734 'regex': {
735 pattern: /((?:^|[^$\w\xA0-\uFFFF."'\])\s])\s*)\/(\[(?:[^\]\\\r\n]|\\.)*]|\\.|[^/\\\[\r\n])+\/[gimyu]{0,5}(?=\s*($|[\r\n,.;})\]]))/,
736 lookbehind: true,
737 greedy: true
738 },
739 // This must be declared before keyword because we use "function" inside the look-forward
740 'function-variable': {
741 pattern: /[_$a-zA-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*[=:]\s*(?:async\s*)?(?:\bfunction\b|(?:\((?:[^()]|\([^()]*\))*\)|[_$a-zA-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*)\s*=>))/,
742 alias: 'function'
743 },
744 'parameter': [
745 {
746 pattern: /(function(?:\s+[_$A-Za-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*)?\s*\(\s*)(?!\s)(?:[^()]|\([^()]*\))+?(?=\s*\))/,
747 lookbehind: true,
748 inside: Prism.languages.javascript
749 },
750 {
751 pattern: /[_$a-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*=>)/i,
752 inside: Prism.languages.javascript
753 },
754 {
755 pattern: /(\(\s*)(?!\s)(?:[^()]|\([^()]*\))+?(?=\s*\)\s*=>)/,
756 lookbehind: true,
757 inside: Prism.languages.javascript
758 },
759 {
760 pattern: /((?:\b|\s|^)(?!(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)(?![$\w\xA0-\uFFFF]))(?:[_$A-Za-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*\s*)\(\s*)(?!\s)(?:[^()]|\([^()]*\))+?(?=\s*\)\s*\{)/,
761 lookbehind: true,
762 inside: Prism.languages.javascript
763 }
764 ],
765 'constant': /\b[A-Z][A-Z\d_]*\b/
766});
767
768Prism.languages.insertBefore('javascript', 'string', {
769 'template-string': {
770 pattern: /`(?:\\[\s\S]|\${[^}]+}|[^\\`])*`/,
771 greedy: true,
772 inside: {
773 'interpolation': {
774 pattern: /\${[^}]+}/,
775 inside: {
776 'interpolation-punctuation': {
777 pattern: /^\${|}$/,
778 alias: 'punctuation'
779 },
780 rest: Prism.languages.javascript
781 }
782 },
783 'string': /[\s\S]+/
784 }
785 }
786});
787
788if (Prism.languages.markup) {
789 Prism.languages.insertBefore('markup', 'tag', {
790 'script': {
791 pattern: /(<script[\s\S]*?>)[\s\S]*?(?=<\/script>)/i,
792 lookbehind: true,
793 inside: Prism.languages.javascript,
794 alias: 'language-javascript',
795 greedy: true
796 }
797 });
798}
799
800Prism.languages.js = Prism.languages.javascript;
801
802
803/* **********************************************
804 Begin prism-file-highlight.js
805********************************************** */
806
807(function () {
808 if (typeof self === 'undefined' || !self.Prism || !self.document || !document.querySelector) {
809 return;
810 }
811
812 /**
813 * @param {Element} [container=document]
814 */
815 self.Prism.fileHighlight = function (container) {
816 container = container || document;
817
818 var Extensions = {
819 'js': 'javascript',
820 'py': 'python',
821 'rb': 'ruby',
822 'ps1': 'powershell',
823 'psm1': 'powershell',
824 'sh': 'bash',
825 'bat': 'batch',
826 'h': 'c',
827 'tex': 'latex'
828 };
829
830 Array.prototype.slice.call(container.querySelectorAll('pre[data-src]')).forEach(function (pre) {
831 // ignore if already loaded
832 if (pre.hasAttribute('data-src-loaded')) {
833 return;
834 }
835
836 // load current
837 var src = pre.getAttribute('data-src');
838
839 var language, parent = pre;
840 var lang = /\blang(?:uage)?-([\w-]+)\b/i;
841 while (parent && !lang.test(parent.className)) {
842 parent = parent.parentNode;
843 }
844
845 if (parent) {
846 language = (pre.className.match(lang) || [, ''])[1];
847 }
848
849 if (!language) {
850 var extension = (src.match(/\.(\w+)$/) || [, ''])[1];
851 language = Extensions[extension] || extension;
852 }
853
854 var code = document.createElement('code');
855 code.className = 'language-' + language;
856
857 pre.textContent = '';
858
859 code.textContent = 'Loading…';
860
861 pre.appendChild(code);
862
863 var xhr = new XMLHttpRequest();
864
865 xhr.open('GET', src, true);
866
867 xhr.onreadystatechange = function () {
868 if (xhr.readyState == 4) {
869
870 if (xhr.status < 400 && xhr.responseText) {
871 code.textContent = xhr.responseText;
872
873 Prism.highlightElement(code);
874 // mark as loaded
875 pre.setAttribute('data-src-loaded', '');
876 }
877 else if (xhr.status >= 400) {
878 code.textContent = '✖ Error ' + xhr.status + ' while fetching file: ' + xhr.statusText;
879 }
880 else {
881 code.textContent = '✖ Error: File does not exist or is empty';
882 }
883 }
884 };
885
886 xhr.send(null);
887 });
888
889 if (Prism.plugins.toolbar) {
890 Prism.plugins.toolbar.registerButton('download-file', function (env) {
891 var pre = env.element.parentNode;
892 if (!pre || !/pre/i.test(pre.nodeName) || !pre.hasAttribute('data-src') || !pre.hasAttribute('data-download-link')) {
893 return;
894 }
895 var src = pre.getAttribute('data-src');
896 var a = document.createElement('a');
897 a.textContent = pre.getAttribute('data-download-link-label') || 'Download';
898 a.setAttribute('download', '');
899 a.href = src;
900 return a;
901 });
902 }
903
904 };
905
906 document.addEventListener('DOMContentLoaded', function () {
907 // execute inside handler, for dropping Event as argumnet
908 self.Prism.fileHighlight();
909 });
910
911})();
912
913(function () {
914
915 if (typeof self === 'undefined' || !self.Prism || !self.document) {
916 return;
917 }
918
919 /**
920 * Plugin name which is used as a class name for <pre> which is activating the plugin
921 * @type {String}
922 */
923 var PLUGIN_NAME = 'line-numbers';
924
925 /**
926 * Regular expression used for determining line breaks
927 * @type {RegExp}
928 */
929 var NEW_LINE_EXP = /\n(?!$)/g;
930
931 /**
932 * Resizes line numbers spans according to height of line of code
933 * @param {Element} element <pre> element
934 */
935 var _resizeElement = function (element) {
936 var codeStyles = getStyles(element);
937 var whiteSpace = codeStyles['white-space'];
938
939 if (whiteSpace === 'pre-wrap' || whiteSpace === 'pre-line') {
940 var codeElement = element.querySelector('code');
941 var lineNumbersWrapper = element.querySelector('.line-numbers-rows');
942 var lineNumberSizer = element.querySelector('.line-numbers-sizer');
943 var codeLines = codeElement.textContent.split(NEW_LINE_EXP);
944
945 if (!lineNumberSizer) {
946 lineNumberSizer = document.createElement('span');
947 lineNumberSizer.className = 'line-numbers-sizer';
948
949 codeElement.appendChild(lineNumberSizer);
950 }
951
952 lineNumberSizer.style.display = 'block';
953
954 codeLines.forEach(function (line, lineNumber) {
955 lineNumberSizer.textContent = line || '\n';
956 var lineSize = lineNumberSizer.getBoundingClientRect().height;
957 lineNumbersWrapper.children[lineNumber].style.height = lineSize + 'px';
958 });
959
960 lineNumberSizer.textContent = '';
961 lineNumberSizer.style.display = 'none';
962 }
963 };
964
965 /**
966 * Returns style declarations for the element
967 * @param {Element} element
968 */
969 var getStyles = function (element) {
970 if (!element) {
971 return null;
972 }
973
974 return window.getComputedStyle ? getComputedStyle(element) : (element.currentStyle || null);
975 };
976
977 window.addEventListener('resize', function () {
978 Array.prototype.forEach.call(document.querySelectorAll('pre.' + PLUGIN_NAME), _resizeElement);
979 });
980
981 Prism.hooks.add('complete', function (env) {
982 if (!env.code) {
983 return;
984 }
985
986 // works only for <code> wrapped inside <pre> (not inline)
987 var pre = env.element.parentNode;
988 var clsReg = /\s*\bline-numbers\b\s*/;
989 if (
990 !pre || !/pre/i.test(pre.nodeName) ||
991 // Abort only if nor the <pre> nor the <code> have the class
992 (!clsReg.test(pre.className) && !clsReg.test(env.element.className))
993 ) {
994 return;
995 }
996
997 if (env.element.querySelector('.line-numbers-rows')) {
998 // Abort if line numbers already exists
999 return;
1000 }
1001
1002 if (clsReg.test(env.element.className)) {
1003 // Remove the class 'line-numbers' from the <code>
1004 env.element.className = env.element.className.replace(clsReg, ' ');
1005 }
1006 if (!clsReg.test(pre.className)) {
1007 // Add the class 'line-numbers' to the <pre>
1008 pre.className += ' line-numbers';
1009 }
1010
1011 var match = env.code.match(NEW_LINE_EXP);
1012 var linesNum = match ? match.length + 1 : 1;
1013 var lineNumbersWrapper;
1014
1015 var lines = new Array(linesNum + 1);
1016 lines = lines.join('<span></span>');
1017
1018 lineNumbersWrapper = document.createElement('span');
1019 lineNumbersWrapper.setAttribute('aria-hidden', 'true');
1020 lineNumbersWrapper.className = 'line-numbers-rows';
1021 lineNumbersWrapper.innerHTML = lines;
1022
1023 if (pre.hasAttribute('data-start')) {
1024 pre.style.counterReset = 'linenumber ' + (parseInt(pre.getAttribute('data-start'), 10) - 1);
1025 }
1026
1027 env.element.appendChild(lineNumbersWrapper);
1028
1029 _resizeElement(pre);
1030
1031 Prism.hooks.run('line-numbers', env);
1032 });
1033
1034 Prism.hooks.add('line-numbers', function (env) {
1035 env.plugins = env.plugins || {};
1036 env.plugins.lineNumbers = true;
1037 });
1038
1039 /**
1040 * Global exports
1041 */
1042 Prism.plugins.lineNumbers = {
1043 /**
1044 * Get node for provided line number
1045 * @param {Element} element pre element
1046 * @param {Number} number line number
1047 * @return {Element|undefined}
1048 */
1049 getLine: function (element, number) {
1050 if (element.tagName !== 'PRE' || !element.classList.contains(PLUGIN_NAME)) {
1051 return;
1052 }
1053
1054 var lineNumberRows = element.querySelector('.line-numbers-rows');
1055 var lineNumberStart = parseInt(element.getAttribute('data-start'), 10) || 1;
1056 var lineNumberEnd = lineNumberStart + (lineNumberRows.children.length - 1);
1057
1058 if (number < lineNumberStart) {
1059 number = lineNumberStart;
1060 }
1061 if (number > lineNumberEnd) {
1062 number = lineNumberEnd;
1063 }
1064
1065 var lineIndex = number - lineNumberStart;
1066
1067 return lineNumberRows.children[lineIndex];
1068 }
1069 };
1070
1071}());
diff --git a/source/layouts/comments.njk b/source/layouts/comments.njk
deleted file mode 100644
index 7ee4af8..0000000
--- a/source/layouts/comments.njk
+++ /dev/null
@@ -1,2 +0,0 @@
1<div id="commento"></div>
2<script src="https://cdn.commento.io/js/commento.js"></script>
diff --git a/source/layouts/draft.njk b/source/layouts/draft.njk
deleted file mode 100644
index 0f2091c..0000000
--- a/source/layouts/draft.njk
+++ /dev/null
@@ -1,62 +0,0 @@
1<!DOCTYPE html>
2<html lang="en">
3
4 <head>
5 <meta charset="utf-8">
6 <meta name="viewport" content="width=device-width, initial-scale=1.0">
7 <meta http-equiv="X-UA-Compatible" content="ie=edge">
8 <meta name="theme-color" content="#ffffff">
9
10 <meta name="google-site-verification" content="EwUGW1WlCkRIQuyQ9AE1-bLitWthw-eVMZFTAMZVZaA">
11
12 <link rel="icon" type="image/png" href="{{ vars.domain }}/files/avatar-64x64.png?ver={{ timestamp }}">
13
14 <title>{{ title }}</title>
15 <meta name="author" content="{{ vars.author }}">
16 <meta name="description" content="{{ description }}">
17
18 <meta name="og:url" content="{{ vars.domain }}/{{ slug }}">
19 <meta name="og:type" content="website">
20 <meta name="og:title" content="{{ title }}">
21 <meta name="og:description" content="{{ description }}">
22 <meta name="og:image" content="{{ vars.domain }}/files/avatar-512x512.png?ver={{ timestamp }}">
23
24 <meta name="twitter:card" content="summary">
25 <meta name="twitter:site" content="@mitjafelicijan">
26 <meta name="twitter:title" content="{{ title }}">
27 <meta name="twitter:description" content="{{ description }}">
28 <meta name="twitter:image" content="{{ vars.domain }}/files/avatar-512x512.png?ver={{ timestamp }}">
29
30 {{ css }}
31
32 </head>
33
34 <body>
35
36 <main class="wrapper">
37
38 {% include "navigation.njk" %}
39
40 <article>
41
42 <header>
43 <h1>{{ title }}</h1>
44 <p class="pubdate">Published on
45 <time pubdate="{{ writtenDate.original }}">{{ writtenDate.formatted }}</time>
46 by
47 {{ vars.author }}</p>
48 </header>
49
50 {{ content|safe }}
51
52 </article>
53
54 {{ javascript }}
55
56 {% include "footer.njk" %}
57
58 </main>
59
60 </body>
61
62</html>
diff --git a/source/layouts/footer.njk b/source/layouts/footer.njk
deleted file mode 100644
index c4cf79e..0000000
--- a/source/layouts/footer.njk
+++ /dev/null
@@ -1,47 +0,0 @@
1<footer>
2 <span>© 2010-{{ currentYear }}</span>
3 <a href="/curriculum-vitae">Curriculum Vitae</a>
4 <a href="//github.com/mitjafelicijan" target="_blank" rel="noopener nofollow">Github</a>
5 <a href="//twitter.com/mitjafelicijan" target="_blank" rel="noopener nofollow">Twitter</a>
6</footer>
7
8<!-- MathJax -->
9<script type="text/x-mathjax-config">
10 MathJax
11 .Hub
12 .Config({
13 TeX: {
14 equationNumbers: {
15 autoNumber: "AMS"
16 }
17 },
18 tex2jax: {
19 inlineMath: [
20 [
21 '$', '$'
22 ],
23 [
24 '\\(', '\\)'
25 ]
26 ],
27 displayMath: [
28 ['$$', '$$']
29 ],
30 processEscapes: true
31 }
32 });
33</script>
34
35<!-- Global site tag (gtag.js) - Google Analytics -->
36<script async="async" src="https://www.googletagmanager.com/gtag/js?id=UA-12769079-10"></script>
37<script>
38 window.dataLayer = window.dataLayer || [];
39 function gtag() {
40 dataLayer.push(arguments);
41 }
42 gtag('js', new Date());
43
44 gtag('config', 'UA-12769079-10');
45</script>
46
47<script src="//cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-AMS-MML_HTMLorMML" async="async"></script>
diff --git a/source/layouts/index.njk b/source/layouts/index.njk
deleted file mode 100644
index 9e2fde8..0000000
--- a/source/layouts/index.njk
+++ /dev/null
@@ -1,80 +0,0 @@
1<!DOCTYPE html>
2<html lang="en">
3
4 <head>
5 <meta charset="utf-8">
6 <meta name="viewport" content="width=device-width, initial-scale=1.0">
7 <meta http-equiv="X-UA-Compatible" content="ie=edge">
8 <meta name="theme-color" content="#ffffff">
9
10 <meta name="google-site-verification" content="EwUGW1WlCkRIQuyQ9AE1-bLitWthw-eVMZFTAMZVZaA">
11
12 <link rel="icon" type="image/png" href="{{ vars.domain }}/files/avatar-64x64.png?ver={{ timestamp }}">
13
14 <title>{{ vars.title }}</title>
15 <meta name="author" content="{{ vars.author }}">
16 <meta name="description" content="{{ vars.description }}">
17
18 <meta name="og:url" content="{{ vars.domain }}">
19 <meta name="og:type" content="website">
20 <meta name="og:title" content="{{ vars.title }}">
21 <meta name="og:description" content="{{ vars.description }}">
22 <meta name="og:image" content="{{ vars.domain }}/files/avatar-512x512.png?ver={{ timestamp }}">
23
24 <meta name="twitter:card" content="summary">
25 <meta name="twitter:site" content="@mitjafelicijan">
26 <meta name="twitter:title" content="{{ vars.title }}">
27 <meta name="twitter:description" content="{{ vars.description }}">
28 <meta name="twitter:image" content="{{ vars.domain }}/files/avatar-512x512.png?ver={{ timestamp }}">
29
30 {{ css }}
31
32 </head>
33
34 <body>
35
36 <main class="wrapper">
37
38 {% include "navigation.njk" %}
39
40 <div class="list">
41
42 <h3>Research</h3>
43 <nav class="article-list">
44 {% for post in posts %}
45 {% if post.type == "research" %}
46 <article>
47 <a href="/{{ post.slug }}" aria-label="Read more about {{ post.title }}">
48 <time pubdate="{{ post.dateOriginal }}" class="pubdate">{{ post.dateFormatted }}</time>
49 <h2>{{ post.title }}</h2>
50 </a>
51 </article>
52 {% endif %}
53 {% endfor %}
54 </nav>
55
56 <h3>General</h3>
57 <nav class="article-list">
58 {% for post in posts %}
59 {% if post.type != "research" %}
60 <article itemtype="http://schema.org/Article">
61 <a href="/{{ post.slug }}" aria-label="Read more about {{ post.title }}" itemprop="url" rel="bookmark">
62 <time pubdate="{{ post.dateOriginal }}" class="pubdate">{{ post.dateFormatted }}</time>
63 <h2>{{ post.title }}</h2>
64 </a>
65 </article>
66 {% endif %}
67 {% endfor %}
68 </nav>
69
70 </div>
71
72 {{ javascript }}
73
74 {% include "footer.njk" %}
75
76 </main>
77
78 </body>
79
80</html>
diff --git a/source/layouts/navigation.njk b/source/layouts/navigation.njk
deleted file mode 100644
index c5c6c80..0000000
--- a/source/layouts/navigation.njk
+++ /dev/null
@@ -1,47 +0,0 @@
1<menu>
2 <div>
3 <a href="/" class="logo">Mitja Felicijan</a>
4 </div>
5 <nav>
6
7 <a href="/curriculum-vitae" title="Curriculum Vitae" aria-label="Curriculum Vitae">
8 <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
9 <g>
10 <path fill="none" d="M0 0h24v24H0z"/>
11 <path d="M7 5V2a1 1 0 0 1 1-1h8a1 1 0 0 1 1 1v3h4a1 1 0 0 1 1 1v14a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V6a1 1 0 0 1 1-1h4zM4 15v4h16v-4H4zm7-4v2h2v-2h-2zM9 3v2h6V3H9z"/>
12 </g>
13 </svg>
14 </a>
15
16 <a href="//github.com/mitjafelicijan" title="Github" aria-label="Github">
17 <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewbox="0 0 92 92" style="enable-background:new 0 0 92 92;" xml:space="preserve">
18 <g>
19 <path style="fill:#030104;" d="M61.896,52.548c-3.59,0-6.502,4.026-6.502,8.996c0,4.971,2.912,8.999,6.502,8.999
20 c3.588,0,6.498-4.028,6.498-8.999C68.395,56.574,65.484,52.548,61.896,52.548z M84.527,29.132c0.74-1.826,0.777-12.201-3.17-22.132
21 c0,0-9.057,0.993-22.76,10.396c-2.872-0.793-7.736-1.19-12.597-1.19s-9.723,0.396-12.598,1.189C19.699,7.993,10.645,7,10.645,7
22 c-3.948,9.931-3.913,20.306-3.172,22.132C2.834,34.169,0,40.218,0,48.483c0,35.932,29.809,36.508,37.334,36.508
23 c1.703,0,5.088,0.004,8.666,0.009c3.578-0.005,6.965-0.009,8.666-0.009C62.191,84.991,92,84.415,92,48.483
24 C92,40.218,89.166,34.169,84.527,29.132z M46.141,80.574H45.86c-18.859,0-33.545-2.252-33.545-20.58
25 c0-4.389,1.549-8.465,5.229-11.847c6.141-5.636,16.527-2.651,28.316-2.651c0.045,0,0.093-0.001,0.141-0.003
26 c0.049,0.002,0.096,0.003,0.141,0.003c11.789,0,22.178-2.984,28.316,2.651c3.68,3.382,5.229,7.458,5.229,11.847
27 C79.686,78.322,65,80.574,46.141,80.574z M30.104,52.548c-3.588,0-6.498,4.026-6.498,8.996c0,4.971,2.91,8.999,6.498,8.999
28 c3.592,0,6.502-4.028,6.502-8.999C36.605,56.574,33.695,52.548,30.104,52.548z"/>
29 </g>
30 </svg>
31 </a>
32
33 <a href="//twitter.com/mitjafelicijan" title="Twitter" aria-label="Twitter">
34 <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewbox="0 0 612 612" style="enable-background:new 0 0 612 612;" xml:space="preserve">
35 <g>
36 <path style="fill:#010002;" d="M612,116.258c-22.525,9.981-46.694,16.75-72.088,19.772c25.929-15.527,45.777-40.155,55.184-69.411
37 c-24.322,14.379-51.169,24.82-79.775,30.48c-22.907-24.437-55.49-39.658-91.63-39.658c-69.334,0-125.551,56.217-125.551,125.513
38 c0,9.828,1.109,19.427,3.251,28.606C197.065,206.32,104.556,156.337,42.641,80.386c-10.823,18.51-16.98,40.078-16.98,63.101
39 c0,43.559,22.181,81.993,55.835,104.479c-20.575-0.688-39.926-6.348-56.867-15.756v1.568c0,60.806,43.291,111.554,100.693,123.104
40 c-10.517,2.83-21.607,4.398-33.08,4.398c-8.107,0-15.947-0.803-23.634-2.333c15.985,49.907,62.336,86.199,117.253,87.194
41 c-42.947,33.654-97.099,53.655-155.916,53.655c-10.134,0-20.116-0.612-29.944-1.721c55.567,35.681,121.536,56.485,192.438,56.485
42 c230.948,0,357.188-191.291,357.188-357.188l-0.421-16.253C573.872,163.526,595.211,141.422,612,116.258z"/>
43 </g>
44 </svg>
45 </a>
46 </nav>
47</menu>
diff --git a/source/layouts/page.njk b/source/layouts/page.njk
deleted file mode 100644
index 89aea8b..0000000
--- a/source/layouts/page.njk
+++ /dev/null
@@ -1,60 +0,0 @@
1<!DOCTYPE html>
2<html lang="en">
3
4 <head>
5 <meta charset="utf-8">
6 <meta name="viewport" content="width=device-width, initial-scale=1.0">
7 <meta http-equiv="X-UA-Compatible" content="ie=edge">
8 <meta name="theme-color" content="#ffffff">
9
10 <meta name="google-site-verification" content="EwUGW1WlCkRIQuyQ9AE1-bLitWthw-eVMZFTAMZVZaA">
11
12 <link rel="icon" type="image/png" href="{{ vars.domain }}/files/avatar-64x64.png?ver={{ timestamp }}">
13
14 <title>{{ title }}</title>
15 <meta name="author" content="{{ vars.author }}">
16 <meta name="description" content="{{ description }}">
17
18 <meta name="og:url" content="{{ vars.domain }}/{{ slug }}">
19 <meta name="og:type" content="website">
20 <meta name="og:title" content="{{ title }}">
21 <meta name="og:description" content="{{ description }}">
22 <meta name="og:image" content="{{ vars.domain }}/files/avatar-512x512.png?ver={{ timestamp }}">
23
24 <meta name="twitter:card" content="summary">
25 <meta name="twitter:site" content="@mitjafelicijan">
26 <meta name="twitter:title" content="{{ title }}">
27 <meta name="twitter:description" content="{{ description }}">
28 <meta name="twitter:image" content="{{ vars.domain }}/files/avatar-512x512.png?ver={{ timestamp }}">
29
30 {{ css }}
31
32 </head>
33
34 <body>
35
36 <main class="wrapper">
37
38 {% include "navigation.njk" %}
39
40 <article itemtype="http://schema.org/Article">
41
42 <header>
43 <h1>{{ title }}</h1>
44 </header>
45
46 <div>
47 {{ content|safe }}
48 </div>
49
50 </article>
51
52 {{ javascript }}
53
54 {% include "footer.njk" %}
55
56 </main>
57
58 </body>
59
60</html>
diff --git a/source/layouts/post.njk b/source/layouts/post.njk
deleted file mode 100644
index 9851c13..0000000
--- a/source/layouts/post.njk
+++ /dev/null
@@ -1,66 +0,0 @@
1<!DOCTYPE html>
2<html lang="en">
3
4 <head>
5 <meta charset="utf-8">
6 <meta name="viewport" content="width=device-width, initial-scale=1.0">
7 <meta http-equiv="X-UA-Compatible" content="ie=edge">
8 <meta name="theme-color" content="#ffffff">
9
10 <meta name="google-site-verification" content="EwUGW1WlCkRIQuyQ9AE1-bLitWthw-eVMZFTAMZVZaA">
11
12 <link rel="icon" type="image/png" href="{{ vars.domain }}/files/avatar-64x64.png?ver={{ timestamp }}">
13
14 <title>{{ title }}</title>
15 <meta name="author" content="{{ vars.author }}">
16 <meta name="description" content="{{ description }}">
17
18 <meta name="og:url" content="{{ vars.domain }}/{{ slug }}">
19 <meta name="og:type" content="article">
20 <meta name="og:title" content="{{ title }}">
21 <meta name="og:description" content="{{ description }}">
22 <meta name="og:image" content="{{ vars.domain }}/files/avatar-512x512.png?ver={{ timestamp }}">
23
24 <meta name="twitter:card" content="summary">
25 <meta name="twitter:site" content="@mitjafelicijan">
26 <meta name="twitter:title" content="{{ title }}">
27 <meta name="twitter:description" content="{{ description }}">
28 <meta name="twitter:image" content="{{ vars.domain }}/files/avatar-512x512.png?ver={{ timestamp }}">
29
30 {{ css }}
31
32 </head>
33
34 <body>
35
36 <main class="wrapper">
37
38 {% include "navigation.njk" %}
39
40 <article itemtype="http://schema.org/Article">
41
42 <header>
43 <h1>{{ title }}</h1>
44 <p class="pubdate">Published on
45 <time pubdate="{{ writtenDate.original }}">{{ writtenDate.formatted }}</time>
46 by
47 {{ vars.author }}</p>
48 </header>
49
50 <div>
51 {{ content|safe }}
52 </div>
53
54 </article>
55
56 {{ javascript }}
57
58 {% include "comments.njk" %}
59
60 {% include "footer.njk" %}
61
62 </main>
63
64 </body>
65
66</html>
diff --git a/content/2017-03-07-golang-profiling-simplified.md b/src/blog/golang-profiling-simplified.md
index fc79020..a49de67 100644
--- a/content/2017-03-07-golang-profiling-simplified.md
+++ b/src/blog/golang-profiling-simplified.md
@@ -1,20 +1,8 @@
1---
2layout: post
3title: Golang profiling simplified 1title: Golang profiling simplified
4description: Golang profiling made easy
5slug: golang-profiling-simplified
6type: note
7date: 2017-03-07 2date: 2017-03-07
8--- 3tags: blog
9 4hide: false
10**Table of contents** 5----
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 6
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. 7Many 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 8
@@ -24,7 +12,7 @@ Nevertheless, after searching and experimenting I have found a solution that wor
24 12
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. 13By 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 14
27## Why is my cpu profile empty? 15## Why is my CPU profile empty?
28 16
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. 17I 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 18
@@ -118,5 +106,5 @@ go tool pprof -pdf ./cpu cpu.pprof > cpu.pdf
118 106
119This will generate PDF document with visualized profile. 107This will generate PDF document with visualized profile.
120 108
121- [Memory PDF profile example](/files/golang-profiling-mem.pdf) 109- [Memory PDF profile example](/files/go-profiling/golang-profiling-mem.pdf)
122- [CPU PDF profile example](/files/golang-profiling-cpu.pdf) 110- [CPU PDF profile example](/files/go-profiling/golang-profiling-cpu.pdf)
diff --git a/content/2017-04-21-profiling-python-web-applications-with-visual-tools.md b/src/blog/profiling-python-web-applications-with-visual-tools.md
index 6e52ee0..e99b9ff 100644
--- a/content/2017-04-21-profiling-python-web-applications-with-visual-tools.md
+++ b/src/blog/profiling-python-web-applications-with-visual-tools.md
@@ -1,17 +1,8 @@
1---
2layout: post
3title: Profiling Python web applications with visual tools 1title: 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 2date: 2017-04-21
8--- 3tags: blog
9 4hide: false
10**Table of contents** 5----
11
121. [Simple web-service](#simple-web-service)
132. [Visualize profile](#visualize-profile)
143. [Update 2017-04-22](#update-2017-04-22)
15 6
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. 7I 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 8
diff --git a/content/2017-08-11-simple-iot.md b/src/blog/simple-iot-application.md
index 2eac869..2b7d67f 100644
--- a/content/2017-08-11-simple-iot.md
+++ b/src/blog/simple-iot-application.md
@@ -1,22 +1,8 @@
1---
2layout: post
3title: Simple IOT application supported by real-time monitoring and data history 1title: 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 2date: 2017-08-11
8--- 3tags: blog
9 4hide: false
10**Table of contents** 5----
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 6
21## Initial thoughts 7## Initial thoughts
22 8
@@ -40,7 +26,7 @@ Step 1. and 3. will share the same web application. One route will be dedicated
40 26
41Schema below represents what we will try to achieve and how different parts correlates to each other. 27Schema below represents what we will try to achieve and how different parts correlates to each other.
42 28
43![Overview](/files/simple-iot-application-overview.svg) 29![Overview](/files/iot-application/simple-iot-application-overview.svg)
44 30
45## Simple Python API 31## Simple Python API
46 32
@@ -86,7 +72,7 @@ If you would like change the port of your application (like port 80) and not use
86 72
87If this fails at any time please fix it before you continue, because nothing below will work otherwise. 73If this fails at any time please fix it before you continue, because nothing below will work otherwise.
88 74
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. 75We 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 76
91### Web application security 77### Web application security
92 78
@@ -161,15 +147,15 @@ To run this simply go to folder containing python file and run ```python webapp.
161 147
162After testing the service with Restlet Client you should be able to view your data in a database file ```data.db```. 148After testing the service with Restlet Client you should be able to view your data in a database file ```data.db```.
163 149
164![REST settings example](/files/iot-rest-example.png) 150![REST settings example](/files/iot-application/iot-rest-example.png)
165 151
166You can also check the contents of new database file by using desktop client for SQLite → [DB Browser for SQLite](http://sqlitebrowser.org/). 152You can also check the contents of new database file by using desktop client for SQLite → [DB Browser for SQLite](http://sqlitebrowser.org/).
167 153
168![SQLite database example](/files/iot-sqlite-db.png) 154![SQLite database example](/files/iot-application/iot-sqlite-db.png)
169 155
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. 156Table 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 157
172> If you will deploy this app with uWSGI and multi-threaded, use DSN (Data Source Name) url with ```?check_same_thread=False```. 158If you will deploy this app with uWSGI and multi-threaded, use DSN (Data Source Name) url with ```?check_same_thread=False```.
173 159
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. 160Ok, 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 161
@@ -482,9 +468,9 @@ If everything goes well you should be seeing new data-points rendered on chart e
482 468
483If you navigate to ```http://0.0.0.0:5000``` you should see rendered chart as shown on picture below. 469If you navigate to ```http://0.0.0.0:5000``` you should see rendered chart as shown on picture below.
484 470
485![Application output](/files/iot-app-output.png) 471![Application output](/files/iot-application/iot-app-output.png)
486 472
487Complete application with all the code is available for [download](/files/simple-iot-application.zip). 473Complete application with all the code is available for [download](/files/iot-application/simple-iot-application.zip).
488 474
489## Conclusion 475## Conclusion
490 476
@@ -497,4 +483,4 @@ If you would like to continue exploring IOT world here are some interesting reso
497* [Stream Updates with Server-Sent Events](https://www.html5rocks.com/en/tutorials/eventsource/basics/) 483* [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/) 484* [Internet of Things (IoT) Tutorials](http://www.tutorialspoint.com/internet_of_things/)
499 485
500Any comment or additional ideas are welcomed in comments below.) 486Any comment or additional ideas are welcomed in comments below.
diff --git a/src/blog/simplifying-and-reducing-clutter.md b/src/blog/simplifying-and-reducing-clutter.md
new file mode 100644
index 0000000..b435834
--- /dev/null
+++ b/src/blog/simplifying-and-reducing-clutter.md
@@ -0,0 +1,21 @@
1title: Simplifying and reducing clutter in my life and work
2date: 2019-10-14
3tags: blog
4hide: false
5----
6
7I recently moved my main working machine back from Hachintosh to Linux. Well the experiment was interesting and I have done some great work on macOS but it was time to move back.
8
9I actually really missed Linux. The simplicity of `apt-get` or just the amount of software that exists for Linux should be a no-brainer. I spent most of my time on macOS finding solutions to make things work. Using [Brew](https://brew.sh/) was just a horrible experience and far from package managers of Linux. At least they managed to get that `sudo` debacle sorted.
10
11Not all was bad. macOS in general was a perfectly good environment. Things like Docker and tooling like this worked without any hiccups. My normal tools like coding IDE worked flawlessly and the whole look and feel is just superb. I have been using MacBook Air for couple of years so I was used to the system but never as a daily driver.
12
13One of the things I did after I installed Linux back on my machine was cleaning up my Dropbox folder. I have everything on Dropbox. Even projects folder. I write code for living so my whole life revolves around couple of megs of code (with assets). So it's not like I have huge files on my machine. I don't have movies or music or pictures on my PC. All of that stuff is in cloud. I use Google music and I have Netflix account which is more than enough for me.
14
15I also went and deleted some of the repositories on my Github account. I have deleted more code than deployed. People find this strange but for me deleting something feels so cathartic and also forces me to write better code next time around when I am faced with similar problem. That was a huge relief if I am being totally honest.
16
17Next step was to do something with my webpage. I have been using some scripts I wrote a while ago to generate static pages from markdown source posts. I kept on adding and adding stuff on top of it and it became a source of a frustration. And this is just a simple blog and I was using gulp and npm. Anyways after couple of hours of searching and testing static generators I found an interesting one [https://github.com/piranha/gostatic](https://github.com/piranha/gostatic) and I just decided to use this one. It was the only one that had a simple templating engine, not that I really need one. But others had this convoluted way of trying to solve everything and at the end just required quite bigger learning curve I was ready to go with. So I deleted couple of old posts, simplified HTML, trashed most of the CSS and went with [https://motherfuckingwebsite.com/](https://motherfuckingwebsite.com/) aesthetics. Yeah, the previous site was more visually stimulating but all I really care is the content at this point. And Times New Roman font is kind of awesome.
18
19I stopped working on most of the projects in the past couple of months because the overhead was just too insane. There comes a point when you stretch yourself too much and then you stop progressing and with that comes dissatisfaction.
20
21So that's about it. Moving forward minimal style.
diff --git a/content/2017-04-17-what-i-ve-learned-developing-ad-server.md b/src/blog/what-i-ve-learned-developing-ad-server.md
index c186484..527f9d0 100644
--- a/content/2017-04-17-what-i-ve-learned-developing-ad-server.md
+++ b/src/blog/what-i-ve-learned-developing-ad-server.md
@@ -1,20 +1,8 @@
1---
2layout: post
3title: What I've learned developing ad server 1title: 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 2date: 2017-04-17
8--- 3tags: blog
9 4hide: false
10**Table of contents** 5----
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 6
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. 7For 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 8
@@ -26,7 +14,7 @@ The system is made from couple of core components:
26 14
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. 15Initial 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 16
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. 17Because 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 18
31So now that you know basic information about the product lets get into the lessons we learned. 19So now that you know basic information about the product lets get into the lessons we learned.
32 20
diff --git a/content/cv.md b/src/curriculum-vitae.md
index ca02245..29c576d 100644
--- a/content/cv.md
+++ b/src/curriculum-vitae.md
@@ -1,12 +1,13 @@
1---
2layout: page
3title: Curriculum Vitae 1title: Curriculum Vitae
4description: Summary of my experiences, skills and major projects I have worked on through year 2date: 2018-01-16
5slug: curriculum-vitae 3tags: research
6--- 4hide: false
5----
7 6
8**Mitja Felicijan** 7**Mitja Felicijan**
8
9*[mitja.felicijan@gmail.com](mailto:mitja.felicijan@gmail.com?subject=Website+CV+Contact)* 9*[mitja.felicijan@gmail.com](mailto:mitja.felicijan@gmail.com?subject=Website+CV+Contact)*
10
10*Slovenia, EU* 11*Slovenia, EU*
11 12
12## Technical experience 13## Technical experience
diff --git a/src/feed.atom b/src/feed.atom
new file mode 100644
index 0000000..9dc15ae
--- /dev/null
+++ b/src/feed.atom
@@ -0,0 +1,55 @@
1<?xml version="1.0" encoding="utf-8"?>
2<feed xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0">
3 <id>{{ .Site.Other.Url }}</id>
4 <title>{{ .Site.Other.Title }}</title>
5 {{ with .Site.Pages.Children "blog/" }}
6 <updated>{{ .First.Date.Format "2006-01-02T15:04:05Z07:00" }}</updated>
7 {{ end }}
8 <author><name>{{ .Site.Other.Author }}</name></author>
9 <link href="{{ .Site.Other.Url }}" rel="alternate"></link>
10 <generator uri="https://github.com/piranha/gostatic">gostatic</generator>
11
12{{ with .Site.Pages.Children "blog/" }}
13{{ range .Slice 0 5 }}
14<entry>
15 <id>{{ .Url }}</id>
16 <author><name>{{ or .Other.Author .Site.Other.Author }}</name></author>
17 <title type="html">{{ html .Title }}</title>
18 <published>{{ .Date.Format "2006-01-02T15:04:05Z07:00" }}</published>
19 {{ range .Tags }}
20 <category term="{{ . }}"></category>
21 {{ end }}
22 <link href="{{ .Site.Other.Url }}/{{ .Url }}" rel="alternate"></link>
23 <content type="html">
24 {{/* .Process runs here in case only feed changed */}}
25 {{ with cut "<section>" "</section>" .Process.Content }}
26 {{ html . }}
27 {{ end }}
28 </content>
29</entry>
30{{ end }}
31{{ end }}
32
33{{ with .Site.Pages.Children "research/" }}
34{{ range .Slice 0 5 }}
35<entry>
36 <id>{{ .Url }}</id>
37 <author><name>{{ or .Other.Author .Site.Other.Author }}</name></author>
38 <title type="html">{{ html .Title }}</title>
39 <published>{{ .Date.Format "2006-01-02T15:04:05Z07:00" }}</published>
40 {{ range .Tags }}
41 <category term="{{ . }}"></category>
42 {{ end }}
43 <link href="{{ .Site.Other.Url }}/{{ .Url }}" rel="alternate"></link>
44 <content type="html">
45 {{/* .Process runs here in case only feed changed */}}
46 {{ with cut "<section>" "</section>" .Process.Content }}
47 {{ html . }}
48 {{ end }}
49 </content>
50</entry>
51{{ end }}
52{{ end }}
53
54
55</feed>
diff --git a/content/files/dna-sequence/benchmarks.ods b/src/files/dna-sequence/benchmarks.ods
index 62a8e30..62a8e30 100644
--- a/content/files/dna-sequence/benchmarks.ods
+++ b/src/files/dna-sequence/benchmarks.ods
Binary files differ
diff --git a/content/files/dna-sequence/chart-encoding-speed.png b/src/files/dna-sequence/chart-encoding-speed.png
index 7fb106d..7fb106d 100644
--- a/content/files/dna-sequence/chart-encoding-speed.png
+++ b/src/files/dna-sequence/chart-encoding-speed.png
Binary files differ
diff --git a/content/files/dna-sequence/chart-file-sizes.png b/src/files/dna-sequence/chart-file-sizes.png
index 31bfa66..31bfa66 100644
--- a/content/files/dna-sequence/chart-file-sizes.png
+++ b/src/files/dna-sequence/chart-file-sizes.png
Binary files differ
diff --git a/content/files/dna-sequence/dna-basics.jpg b/src/files/dna-sequence/dna-basics.jpg
index c2e7f52..c2e7f52 100644
--- a/content/files/dna-sequence/dna-basics.jpg
+++ b/src/files/dna-sequence/dna-basics.jpg
Binary files differ
diff --git a/content/files/dna-sequence/quote.png b/src/files/dna-sequence/quote.png
index 09fb01c..09fb01c 100644
--- a/content/files/dna-sequence/quote.png
+++ b/src/files/dna-sequence/quote.png
Binary files differ
diff --git a/content/files/dna-sequence/sample-binary-file.png b/src/files/dna-sequence/sample-binary-file.png
index 1e4622a..1e4622a 100644
--- a/content/files/dna-sequence/sample-binary-file.png
+++ b/src/files/dna-sequence/sample-binary-file.png
Binary files differ
diff --git a/content/files/dna-sequence/sample.png b/src/files/dna-sequence/sample.png
index 30f12da..30f12da 100644
--- a/content/files/dna-sequence/sample.png
+++ b/src/files/dna-sequence/sample.png
Binary files differ
diff --git a/content/files/copy-benchmarks.tsv b/src/files/do-fuse/copy-benchmarks.tsv
index c7a7af4..c7a7af4 100644
--- a/content/files/copy-benchmarks.tsv
+++ b/src/files/do-fuse/copy-benchmarks.tsv
diff --git a/content/files/fuse-droplets.png b/src/files/do-fuse/fuse-droplets.png
index d7ce243..d7ce243 100644
--- a/content/files/fuse-droplets.png
+++ b/src/files/do-fuse/fuse-droplets.png
Binary files differ
diff --git a/content/files/fuse-spaces.png b/src/files/do-fuse/fuse-spaces.png
index 4dcc1c5..4dcc1c5 100644
--- a/content/files/fuse-spaces.png
+++ b/src/files/do-fuse/fuse-spaces.png
Binary files differ
diff --git a/content/files/sqlite-benchmarks.tsv b/src/files/do-fuse/sqlite-benchmarks.tsv
index daa2c21..daa2c21 100644
--- a/content/files/sqlite-benchmarks.tsv
+++ b/src/files/do-fuse/sqlite-benchmarks.tsv
diff --git a/content/files/golang-profiling-cpu.pdf b/src/files/go-profiling/golang-profiling-cpu.pdf
index 15241cb..15241cb 100644
--- a/content/files/golang-profiling-cpu.pdf
+++ b/src/files/go-profiling/golang-profiling-cpu.pdf
Binary files differ
diff --git a/content/files/golang-profiling-mem.pdf b/src/files/go-profiling/golang-profiling-mem.pdf
index 822e445..822e445 100644
--- a/content/files/golang-profiling-mem.pdf
+++ b/src/files/go-profiling/golang-profiling-mem.pdf
Binary files differ
diff --git a/content/files/iot-app-output.png b/src/files/iot-application/iot-app-output.png
index 1c80589..1c80589 100644
--- a/content/files/iot-app-output.png
+++ b/src/files/iot-application/iot-app-output.png
Binary files differ
diff --git a/content/files/iot-rest-example.png b/src/files/iot-application/iot-rest-example.png
index 3ed86aa..3ed86aa 100644
--- a/content/files/iot-rest-example.png
+++ b/src/files/iot-application/iot-rest-example.png
Binary files differ
diff --git a/content/files/iot-sqlite-db.png b/src/files/iot-application/iot-sqlite-db.png
index 82e1e29..82e1e29 100644
--- a/content/files/iot-sqlite-db.png
+++ b/src/files/iot-application/iot-sqlite-db.png
Binary files differ
diff --git a/content/files/kcachegrind.png b/src/files/iot-application/kcachegrind.png
index 0dc48ab..0dc48ab 100644
--- a/content/files/kcachegrind.png
+++ b/src/files/iot-application/kcachegrind.png
Binary files differ
diff --git a/content/files/profiling-viewer.png b/src/files/iot-application/profiling-viewer.png
index a450513..a450513 100644
--- a/content/files/profiling-viewer.png
+++ b/src/files/iot-application/profiling-viewer.png
Binary files differ
diff --git a/content/files/simple-iot-application-overview.svg b/src/files/iot-application/simple-iot-application-overview.svg
index 817666d..817666d 100644
--- a/content/files/simple-iot-application-overview.svg
+++ b/src/files/iot-application/simple-iot-application-overview.svg
diff --git a/content/files/simple-iot-application.zip b/src/files/iot-application/simple-iot-application.zip
index 46d3205..46d3205 100644
--- a/content/files/simple-iot-application.zip
+++ b/src/files/iot-application/simple-iot-application.zip
Binary files differ
diff --git a/content/files/snakeviz.png b/src/files/iot-application/snakeviz.png
index 5bab395..5bab395 100644
--- a/content/files/snakeviz.png
+++ b/src/files/iot-application/snakeviz.png
Binary files differ
diff --git a/src/index.html b/src/index.html
new file mode 100644
index 0000000..383737b
--- /dev/null
+++ b/src/index.html
@@ -0,0 +1,19 @@
1<h2>Research</h2>
2<ul class="article-list">
3{{ range .Site.Pages.Children "research/" }}
4 <li>
5 {{ template "date" .Date }}
6 <a href="{{ $.Rel .Url }}" title="{{ .Title }}">{{ .Title }}</a>
7 </li>
8{{ end }}
9</ul>
10
11<h2>Blog posts</h2>
12<ul class="article-list">
13{{ range .Site.Pages.Children "blog/" }}
14 <li>
15 {{ template "date" .Date }}
16 <a href="{{ $.Rel .Url }}" title="{{ .Title }}">{{ .Title }}</a>
17 </li>
18{{ end }}
19</ul>
diff --git a/content/2019-01-03-encoding-binary-data-into-dna-sequence.md b/src/research/encoding-binary-data-into-dna-sequence.md
index d3c1396..3bfeaab 100644
--- a/content/2019-01-03-encoding-binary-data-into-dna-sequence.md
+++ b/src/research/encoding-binary-data-into-dna-sequence.md
@@ -1,29 +1,8 @@
1---
2layout: post
3title: Encoding binary data into DNA sequence 1title: 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 2date: 2019-01-03
8--- 3tags: research
9 4hide: false
10**Table of contents** 5----
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 6
28## Initial thoughts 7## Initial thoughts
29 8
@@ -355,56 +334,6 @@ Then we GZIP all the FASTA files to see how much the can be compressed.
355gzip -9 < 10MB.fa > 10MB.fa.gz 334gzip -9 < 10MB.fa > 10MB.fa.gz
356``` 335```
357 336
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). 337[Download ODS file with benchmarks](/files/dna-sequence/benchmarks.ods).
409 338
410## References 339## References
diff --git a/content/2018-01-16-using-digitalocean-spaces-object-storage-with-fuse.md b/src/research/using-digitalocean-spaces-object-storage-with-fuse.md
index f1c893a..099fbef 100644
--- a/content/2018-01-16-using-digitalocean-spaces-object-storage-with-fuse.md
+++ b/src/research/using-digitalocean-spaces-object-storage-with-fuse.md
@@ -1,20 +1,8 @@
1---
2layout: post
3title: Using DigitalOcean Spaces Object Storage with FUSE 1title: 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 2date: 2018-01-16
8--- 3tags: research
9 4hide: false
10**Table of contents** 5----
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 6
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 :) 7Couple 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 8
@@ -37,13 +25,13 @@ To make this work you will need DigitalOcean account. If you don't have one you
37 25
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). 26Instuctions 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 27
40![DigitalOcean Droplets](/files/fuse-droplets.png) 28![DigitalOcean Droplets](/files/do-fuse/fuse-droplets.png)
41 29
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. 30After 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 31
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. 32When 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 33
46![DigitalOcean Spaces](/files/fuse-spaces.png) 34![DigitalOcean Spaces](/files/do-fuse/fuse-spaces.png)
47 35
48Now that we have new Space and Access key we should SSH into our machine. 36Now that we have new Space and Access key we should SSH into our machine.
49 37
@@ -113,14 +101,14 @@ As I suspected, object size is not really that important. Sadly I don't have the
113 101
114**Here are plotted results** 102**Here are plotted results**
115 103
116You can download [raw result here](/files/copy-benchmarks.tsv). Measurements are in seconds. 104You can download [raw result here](/files/do-fuse/copy-benchmarks.tsv). Measurements are in seconds.
117 105
118<script src="//cdn.plot.ly/plotly-latest.min.js"></script> 106<script src="//cdn.plot.ly/plotly-latest.min.js"></script>
119<div id="copy-benchmarks"></div> 107<div id="copy-benchmarks"></div>
120<script> 108<script>
121(function(){ 109(function(){
122 var request = new XMLHttpRequest(); 110 var request = new XMLHttpRequest();
123 request.open("GET", "/files/copy-benchmarks.tsv", true); 111 request.open("GET", "/files/do-fuse/copy-benchmarks.tsv", true);
124 request.onload = function() { 112 request.onload = function() {
125 if (request.status >= 200 && request.status < 400) { 113 if (request.status >= 200 && request.status < 400) {
126 var payload = request.responseText.trim(); 114 var payload = request.responseText.trim();
@@ -229,13 +217,13 @@ result_time = CLOSE = end_time - start_time
229print("CLOSE: %g seconds" % (result_time)) 217print("CLOSE: %g seconds" % (result_time))
230``` 218```
231 219
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. 220You can download [raw result here](/files/do-fuse/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 221
234<div id="sqlite-benchmarks"></div> 222<div id="sqlite-benchmarks"></div>
235<script> 223<script>
236(function(){ 224(function(){
237 var request = new XMLHttpRequest(); 225 var request = new XMLHttpRequest();
238 request.open("GET", "/files/sqlite-benchmarks.tsv", true); 226 request.open("GET", "/files/do-fuse/sqlite-benchmarks.tsv", true);
239 request.onload = function() { 227 request.onload = function() {
240 if (request.status >= 200 && request.status < 400) { 228 if (request.status >= 200 && request.status < 400) {
241 var payload = request.responseText.trim(); 229 var payload = request.responseText.trim();
diff --git a/src/static/avatar-512x512.png b/src/static/avatar-512x512.png
new file mode 100644
index 0000000..fc34eee
--- /dev/null
+++ b/src/static/avatar-512x512.png
Binary files differ
diff --git a/src/static/avatar-64x64.png b/src/static/avatar-64x64.png
new file mode 100644
index 0000000..1406f46
--- /dev/null
+++ b/src/static/avatar-64x64.png
Binary files differ
diff --git a/src/static/style.css b/src/static/style.css
new file mode 100644
index 0000000..efb65c0
--- /dev/null
+++ b/src/static/style.css
@@ -0,0 +1,116 @@
1body {
2 line-height: 150%;
3 margin-bottom: 100px;
4}
5
6main {
7 max-width: 680px;
8 padding: 20px 30px;
9}
10
11nav {
12 margin-bottom: 50px;
13}
14
15nav a {
16 display: inline-block;
17 margin-right: 20px;
18}
19
20h1 {
21 font-size: 280%;
22 line-height: initial;
23}
24
25h2 {
26 font-size: 200%;
27 line-height: initial;
28}
29
30h3 {
31 font-size: 160%;
32 line-height: initial;
33}
34
35img {
36 max-width: 100%;
37 margin: 30px auto;
38 display: block;
39}
40
41ul.article-list li {
42 margin-bottom: 10px;
43}
44
45ul.article-list time {
46 display: inline-block;
47 min-width: 120px;
48}
49
50article .info {
51 font-style: oblique;
52}
53
54pre {
55 overflow: auto;
56}
57
58table {
59 width: 100%;
60}
61
62table, th, td {
63 border: 1px solid black;
64 text-align: left;
65}
66
67th, td {
68 padding: 5px 10px;
69}
70
71::selection {
72 background: #ff0;
73 color: #000;
74}
75
76::-moz-selection {
77 background: #ff0;
78 color: #000;
79}
80
81@media only screen and (max-width:480px) {
82 nav {
83 text-align: center;
84 margin-bottom: initial;
85 }
86
87 nav a {
88 margin-bottom: 10px;
89 }
90
91 ul.article-list {
92 padding-left: 20px;
93
94 }
95
96 ul.article-list li {
97 margin-bottom: 20px;
98
99 }
100
101 ul.article-list a {
102 display: block;
103 }
104
105 h1 {
106 font-size: 220%;
107 }
108
109 h2 {
110 font-size: 180%;
111 }
112
113 h3 {
114 font-size: 160%;
115 }
116}