diff options
| author | Mitja Felicijan <mitja.felicijan@gmail.com> | 2019-10-22 03:40:14 +0200 |
|---|---|---|
| committer | Mitja Felicijan <mitja.felicijan@gmail.com> | 2019-10-22 03:40:14 +0200 |
| commit | 28dd784a088a35739cdfdc4ce79f8ee6d50bf816 (patch) | |
| tree | c198abb97177f60864530ee46f5cdcf0ae88d2bf | |
| parent | 421677613114bb40780d3a5516b6930d386d0b09 (diff) | |
| download | mitjafelicijan.com-28dd784a088a35739cdfdc4ce79f8ee6d50bf816.tar.gz | |
Cleanup of repo and move to gostatic
| -rw-r--r-- | .editorconfig | 2 | ||||
| -rw-r--r-- | Makefile | 11 | ||||
| -rw-r--r-- | config | 39 | ||||
| -rw-r--r-- | content/2015-11-10-software-development-pitfalls.md | 86 | ||||
| -rw-r--r-- | content/2016-10-14-how-we-destroyed-development.md | 40 | ||||
| -rw-r--r-- | content/2017-01-12-gce-aws-docker-digitalocean.md | 51 | ||||
| -rw-r--r-- | content/2017-04-10-what-its-like-to-be-a-software-developer.md | 34 | ||||
| -rw-r--r-- | content/2018-08-05-the-bullshit-web-developments-pov.md | 94 | ||||
| -rw-r--r-- | content/2019-05-11-bci.md | 71 | ||||
| -rw-r--r-- | content/files/avatar-512x512.png | bin | 533383 -> 0 bytes | |||
| -rw-r--r-- | content/files/avatar-64x64.png | bin | 11266 -> 0 bytes | |||
| -rw-r--r-- | content/files/bci/spike-waves.png | bin | 1037764 -> 0 bytes | |||
| -rw-r--r-- | content/files/dev101-git-topics-1.png | bin | 13317 -> 0 bytes | |||
| -rw-r--r-- | content/files/dev101-git-topics-2.png | bin | 12260 -> 0 bytes | |||
| -rw-r--r-- | content/files/style.css | 6 | ||||
| -rw-r--r-- | gulpfile.js | 181 | ||||
| -rw-r--r-- | package.json | 32 | ||||
| -rw-r--r-- | robots.txt | 2 | ||||
| -rw-r--r-- | settings.js | 19 | ||||
| -rw-r--r-- | site.tmpl | 95 | ||||
| -rw-r--r-- | source/assets/default.css | 330 | ||||
| -rw-r--r-- | source/assets/default.js | 21 | ||||
| -rw-r--r-- | source/assets/languages/prism-bash.js | 84 | ||||
| -rw-r--r-- | source/assets/languages/prism-c.js | 33 | ||||
| -rw-r--r-- | source/assets/languages/prism-css.js | 52 | ||||
| -rw-r--r-- | source/assets/languages/prism-go.js | 12 | ||||
| -rw-r--r-- | source/assets/languages/prism-javascript.js | 56 | ||||
| -rw-r--r-- | source/assets/languages/prism-json.js | 14 | ||||
| -rw-r--r-- | source/assets/languages/prism-nginx.js | 11 | ||||
| -rw-r--r-- | source/assets/languages/prism-pascal.js | 55 | ||||
| -rw-r--r-- | source/assets/languages/prism-python.js | 29 | ||||
| -rw-r--r-- | source/assets/prism.css | 167 | ||||
| -rw-r--r-- | source/assets/prism.js | 1071 | ||||
| -rw-r--r-- | source/layouts/comments.njk | 2 | ||||
| -rw-r--r-- | source/layouts/draft.njk | 62 | ||||
| -rw-r--r-- | source/layouts/footer.njk | 47 | ||||
| -rw-r--r-- | source/layouts/index.njk | 80 | ||||
| -rw-r--r-- | source/layouts/navigation.njk | 47 | ||||
| -rw-r--r-- | source/layouts/page.njk | 60 | ||||
| -rw-r--r-- | source/layouts/post.njk | 66 | ||||
| -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.md | 21 | ||||
| -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.atom | 55 | ||||
| -rw-r--r-- | src/files/dna-sequence/benchmarks.ods (renamed from content/files/dna-sequence/benchmarks.ods) | bin | 21911 -> 21911 bytes | |||
| -rw-r--r-- | src/files/dna-sequence/chart-encoding-speed.png (renamed from content/files/dna-sequence/chart-encoding-speed.png) | bin | 14201 -> 14201 bytes | |||
| -rw-r--r-- | src/files/dna-sequence/chart-file-sizes.png (renamed from content/files/dna-sequence/chart-file-sizes.png) | bin | 12391 -> 12391 bytes | |||
| -rw-r--r-- | src/files/dna-sequence/dna-basics.jpg (renamed from content/files/dna-sequence/dna-basics.jpg) | bin | 165883 -> 165883 bytes | |||
| -rw-r--r-- | src/files/dna-sequence/quote.png (renamed from content/files/dna-sequence/quote.png) | bin | 1068 -> 1068 bytes | |||
| -rw-r--r-- | src/files/dna-sequence/sample-binary-file.png (renamed from content/files/dna-sequence/sample-binary-file.png) | bin | 66417 -> 66417 bytes | |||
| -rw-r--r-- | src/files/dna-sequence/sample.png (renamed from content/files/dna-sequence/sample.png) | bin | 65930 -> 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) | bin | 42891 -> 42891 bytes | |||
| -rw-r--r-- | src/files/do-fuse/fuse-spaces.png (renamed from content/files/fuse-spaces.png) | bin | 32450 -> 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) | bin | 16518 -> 16518 bytes | |||
| -rw-r--r-- | src/files/go-profiling/golang-profiling-mem.pdf (renamed from content/files/golang-profiling-mem.pdf) | bin | 19221 -> 19221 bytes | |||
| -rw-r--r-- | src/files/iot-application/iot-app-output.png (renamed from content/files/iot-app-output.png) | bin | 23767 -> 23767 bytes | |||
| -rw-r--r-- | src/files/iot-application/iot-rest-example.png (renamed from content/files/iot-rest-example.png) | bin | 33912 -> 33912 bytes | |||
| -rw-r--r-- | src/files/iot-application/iot-sqlite-db.png (renamed from content/files/iot-sqlite-db.png) | bin | 199821 -> 199821 bytes | |||
| -rw-r--r-- | src/files/iot-application/kcachegrind.png (renamed from content/files/kcachegrind.png) | bin | 88486 -> 88486 bytes | |||
| -rw-r--r-- | src/files/iot-application/profiling-viewer.png (renamed from content/files/profiling-viewer.png) | bin | 173672 -> 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) | bin | 6406 -> 6406 bytes | |||
| -rw-r--r-- | src/files/iot-application/snakeviz.png (renamed from content/files/snakeviz.png) | bin | 59601 -> 59601 bytes | |||
| -rw-r--r-- | src/index.html | 19 | ||||
| -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.png | bin | 0 -> 244569 bytes | |||
| -rw-r--r-- | src/static/avatar-64x64.png | bin | 0 -> 16769 bytes | |||
| -rw-r--r-- | src/static/style.css | 116 |
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 @@ | |||
| 1 | root = true | 1 | root = true |
| 2 | 2 | ||
| 3 | [*] | 3 | [*] |
| 4 | indent_style = space | ||
| 5 | indent_size = 2 | ||
| 6 | charset = utf-8 | 4 | charset = utf-8 |
| 7 | trim_trailing_whitespace = true | 5 | trim_trailing_whitespace = true |
| 8 | insert_final_newline = true | 6 | insert_final_newline = true |
diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..2411164 --- /dev/null +++ b/Makefile | |||
| @@ -0,0 +1,11 @@ | |||
| 1 | GS ?= gostatic | ||
| 2 | |||
| 3 | compile: | ||
| 4 | $(GS) config | ||
| 5 | |||
| 6 | w: | ||
| 7 | -rm public -rf | ||
| 8 | $(GS) -w config | ||
| 9 | |||
| 10 | deploy: compile | ||
| 11 | firebase deploy | ||
| @@ -0,0 +1,39 @@ | |||
| 1 | TEMPLATES = site.tmpl | ||
| 2 | SOURCE = src | ||
| 3 | OUTPUT = public | ||
| 4 | TITLE = Mitja Felicijan - Embedded systems developer | ||
| 5 | DESCRIPTION = Embedded systems developer and fanatical fan of science fiction | ||
| 6 | GOOGLE_VERIFICATION = EwUGW1WlCkRIQuyQ9AE1-bLitWthw-eVMZFTAMZVZaA | ||
| 7 | URL = https://mitjafelicijan.com | ||
| 8 | AUTHOR = Mitja Felicijan | ||
| 9 | |||
| 10 | blog/*.md: | ||
| 11 | config | ||
| 12 | ext .html | ||
| 13 | tags tags/*.tag | ||
| 14 | markdown | ||
| 15 | template post | ||
| 16 | template page | ||
| 17 | |||
| 18 | research/*.md: | ||
| 19 | config | ||
| 20 | ext .html | ||
| 21 | tags tags/*.tag | ||
| 22 | markdown | ||
| 23 | template post | ||
| 24 | template page | ||
| 25 | |||
| 26 | feed.atom: blog/*.md | ||
| 27 | inner-template | ||
| 28 | |||
| 29 | *.md: | ||
| 30 | config | ||
| 31 | ext .html | ||
| 32 | markdown | ||
| 33 | template post | ||
| 34 | template page | ||
| 35 | |||
| 36 | index.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 | |||
| 3 | layout: post | ||
| 4 | title: Software development and my favorite pitfalls | ||
| 5 | description: Couple of observations regarding project management. | ||
| 6 | slug: software-development-pitfalls | ||
| 7 | date: 2015-11-10 | ||
| 8 | --- | ||
| 9 | |||
| 10 | **Table of contents** | ||
| 11 | |||
| 12 | 1. [Initial thoughts](#initial-thoughts) | ||
| 13 | 2. [Ping emails](#ping-emails) | ||
| 14 | 3. [Everybody is a project manager](#everybody-is-a-project-manager) | ||
| 15 | 4. [We are never wrong](#we-are-never-wrong) | ||
| 16 | 5. [Micromanaging](#micromanaging) | ||
| 17 | 6. [Human contact, no need for it!](#human-contact-no-need-for-it) | ||
| 18 | 7. [MVP is killing innovation](#mvp-is-killing-innovation) | ||
| 19 | 8. [Pressure wasteland](#pressure-wasteland) | ||
| 20 | 9. [Conclusion](#conclusion) | ||
| 21 | |||
| 22 | ## Initial thoughts | ||
| 23 | |||
| 24 | Over 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 | |||
| 26 | As 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 | |||
| 28 | I 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 | |||
| 30 | There 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 | |||
| 32 | There 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 | |||
| 34 | Let 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 | |||
| 38 | Ping 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 | |||
| 40 | They 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 | |||
| 44 | Well, 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 | |||
| 46 | People 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 | |||
| 48 | Project 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 | |||
| 52 | I 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 | |||
| 54 | I 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 | |||
| 58 | This 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 | |||
| 60 | I 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 | |||
| 64 | We 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 | |||
| 66 | We 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 | |||
| 70 | Many 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 | |||
| 72 | MVP 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 | |||
| 74 | Well MVP is not directly killing innovation but stupid people do when they try to understand it. | ||
| 75 | |||
| 76 | ## Pressure wasteland | ||
| 77 | |||
| 78 | You 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 | |||
| 80 | People 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 | |||
| 82 | If 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 | |||
| 86 | I 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 | --- | ||
| 2 | layout: post | ||
| 3 | title: How we successfully destroyed the joy of product development | ||
| 4 | description: My take on project development. | ||
| 5 | slug: how-we-successfully-destroyed-the-joy-of-product-development | ||
| 6 | type: note | ||
| 7 | date: 2016-10-14 | ||
| 8 | --- | ||
| 9 | |||
| 10 | No 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 | |||
| 12 | I 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 | |||
| 14 | Good 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 | |||
| 16 | Natural 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 | |||
| 23 | Designer 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 | |||
| 25 | Yes 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 | |||
| 27 | When 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 | |||
| 29 | Being 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 | |||
| 31 | Manifesto 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 | |||
| 38 | This 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 | |||
| 40 | Development 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 | --- | ||
| 2 | layout: post | ||
| 3 | title: GCE, AWS, Docker and why I choose classic VM’s and DigitalOcean for my current project | ||
| 4 | description: Reasons why I choose DigitalOcean for my project | ||
| 5 | slug: gce-aws-docker-and-why-i-choose-classic-vms-and-digitalocean | ||
| 6 | type: note | ||
| 7 | date: 2017-01-12 | ||
| 8 | --- | ||
| 9 | |||
| 10 | **Table of contents** | ||
| 11 | |||
| 12 | 1. [Docker tools and complexity that comes with it](#docker-tools-and-complexity-that-comes-with-it) | ||
| 13 | 2. [Lack of real life examples of Docker in action](#lack-of-real-life-examples-of-docker-in-action) | ||
| 14 | 3. [Ease of deployment](#ease-of-deployment) | ||
| 15 | 4. [Where to go from here](#where-to-go-from-here) | ||
| 16 | |||
| 17 | I 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 | |||
| 19 | As 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 | |||
| 21 | To 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 | |||
| 27 | The 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 | |||
| 29 | I 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 | |||
| 33 | Probably 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 | |||
| 37 | I 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 | |||
| 39 | This 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 | |||
| 43 | What 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 | |||
| 45 | Because 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 | |||
| 49 | Docker 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 | |||
| 51 | I 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 | --- | ||
| 2 | layout: post | ||
| 3 | title: What it's like to be a software developer | ||
| 4 | description: Couple of observations regarding project management | ||
| 5 | slug: what-its-like-to-be-a-software-developer | ||
| 6 | type: note | ||
| 7 | date: 2017-04-10 | ||
| 8 | --- | ||
| 9 | |||
| 10 | I 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 | |||
| 12 | Well, 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 | |||
| 14 | What 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 | |||
| 16 | I 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 | |||
| 18 | I 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 | |||
| 20 | My 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 | |||
| 22 | I 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 | |||
| 24 | I 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 | |||
| 26 | The 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 | |||
| 28 | This 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 | |||
| 30 | What 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 | --- | ||
| 2 | layout: post | ||
| 3 | title: The Bullshit Web - Development's Point of View | ||
| 4 | description: State of front-end development and what this does to the future of web | ||
| 5 | slug: the-bullshit-web-developments-pov | ||
| 6 | type: note | ||
| 7 | date: 2018-08-05 | ||
| 8 | --- | ||
| 9 | |||
| 10 | **Table of contents** | ||
| 11 | |||
| 12 | 1. [Initial thoughts](#initial-thoughts) | ||
| 13 | 2. [Front-end frameworks](#front-end-frameworks) | ||
| 14 | 3. [Obsolescence to the rescue](#obsolescence-to-the-rescue) | ||
| 15 | 4. [Unnecessary complexity](#unnecessary-complexity) | ||
| 16 | 5. [Speed of development trumps code quality](#speed-of-development-trumps-code-quality) | ||
| 17 | 6. [Load times of most popular websites](#load-times-of-most-popular-websites) | ||
| 18 | |||
| 19 | ## Initial thoughts | ||
| 20 | |||
| 21 | I 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 | |||
| 27 | I 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 | |||
| 29 | I 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 | |||
| 31 | The 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 | |||
| 33 | Currently we have two types of websites: | ||
| 34 | |||
| 35 | - informational websites, | ||
| 36 | - web applications. | ||
| 37 | |||
| 38 | The 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 | |||
| 40 | We 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 | |||
| 44 | I 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 | |||
| 46 | Whenever 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 | |||
| 48 | There 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 | |||
| 50 | Huge 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 | |||
| 52 | I 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 | |||
| 56 | We 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 | |||
| 58 | Don'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 | |||
| 60 | And 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 | |||
| 68 | Libraries 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 | |||
| 70 | Another 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 | |||
| 72 | This 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 | |||
| 78 | An 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 | |||
| 82 | I 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 | |||
| 84 | Every 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 | |||
| 86 | Workarounds 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 | |||
| 88 | The 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 | |||
| 90 | Code 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 | |||
| 94 | All 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 | --- | ||
| 2 | layout: draft | ||
| 3 | title: BCI | ||
| 4 | description: 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. | ||
| 5 | slug: bci | ||
| 6 | type: research | ||
| 7 | date: 2019-05-11 | ||
| 8 | --- | ||
| 9 | |||
| 10 | **Table of contents** | ||
| 11 | |||
| 12 | 1. [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) | ||
| 18 | 2. [Generic text for testing CSS styles](#generic-text-for-testing-css-styles) | ||
| 19 | 3. [Resources](#resources) | ||
| 20 | |||
| 21 | |||
| 22 | ## Intefacing with Bluetooth device | ||
| 23 | |||
| 24 | A 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 | |||
| 26 | The 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 | |||
| 32 | Services, 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 | |||
| 36 | Services, 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 | |||
| 40 | A 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 | |||
| 44 | Characteristics 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 | |||
| 46 | Characteristics contain various parts. They have a type, a value, some properties and some permissions. | ||
| 47 | |||
| 48 | Type 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 | |||
| 50 | Properties 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 | |||
| 52 | Sometimes 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 | |||
| 54 | Permissions 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 | |||
| 58 | Lorem 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 |  | ||
| 61 | |||
| 62 | Lorem 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 |  | ||
| 65 | |||
| 66 | Lorem 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 | |||
| 3 | const util = require('util'); | ||
| 4 | const gulp = require('gulp'); | ||
| 5 | const concat = require('gulp-concat'); | ||
| 6 | const terser = require('gulp-terser'); | ||
| 7 | const clean = require('gulp-clean-css'); | ||
| 8 | const settings = require('./settings.js'); | ||
| 9 | const minify = require('html-minifier').minify; | ||
| 10 | var browserSync = require('browser-sync').create(); | ||
| 11 | |||
| 12 | const fs = require('fs'); | ||
| 13 | const markdown = require('markdown-it'); | ||
| 14 | const prism = require('markdown-it-prism'); | ||
| 15 | const nunjucks = require('nunjucks'); | ||
| 16 | const yaml = require('yaml'); | ||
| 17 | const dayjs = require('dayjs'); | ||
| 18 | |||
| 19 | const 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 | |||
| 31 | nunjucks.configure('source/layouts', { | ||
| 32 | autoescape: false, | ||
| 33 | noCache: true, | ||
| 34 | }); | ||
| 35 | |||
| 36 | gulp.task('js', () => gulp.src(settings.assets.javascript) | ||
| 37 | .pipe(concat('bundle.js')) | ||
| 38 | .pipe(terser()) | ||
| 39 | .pipe(gulp.dest('tmp')) | ||
| 40 | ); | ||
| 41 | |||
| 42 | gulp.task('css', () => gulp.src(settings.assets.css) | ||
| 43 | .pipe(concat('bundle.css')) | ||
| 44 | .pipe(clean({})) | ||
| 45 | .pipe(gulp.dest('tmp')) | ||
| 46 | ); | ||
| 47 | |||
| 48 | gulp.task('copy-robots', () => gulp.src('robots.txt') | ||
| 49 | .pipe(gulp.dest('public')) | ||
| 50 | ); | ||
| 51 | |||
| 52 | gulp.task('copy-files', () => gulp.src('content/files/**/*') | ||
| 53 | .pipe(gulp.dest('public/files')) | ||
| 54 | ); | ||
| 55 | |||
| 56 | gulp.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 | |||
| 108 | const 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 | |||
| 151 | const 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 | |||
| 167 | gulp.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 | |||
| 180 | gulp.task('dev', gulp.series('css', 'js', 'copy-robots', 'copy-files', 'generate-static', gulp.parallel(watchers, 'browser-sync'))); | ||
| 181 | gulp.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 @@ | |||
| 1 | User-agent: * | ||
| 2 | Disallow: | ||
diff --git a/settings.js b/settings.js deleted file mode 100644 index 3d41fcf..0000000 --- a/settings.js +++ /dev/null | |||
| @@ -1,19 +0,0 @@ | |||
| 1 | exports.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 | |||
| 13 | exports.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 | |||
| 12 | body { | ||
| 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 | |||
| 19 | a { | ||
| 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 | |||
| 28 | a:active { | ||
| 29 | border-color: black; | ||
| 30 | } | ||
| 31 | |||
| 32 | ol a { | ||
| 33 | text-decoration: none; | ||
| 34 | } | ||
| 35 | |||
| 36 | ol a:hover { | ||
| 37 | text-decoration: underline; | ||
| 38 | } | ||
| 39 | |||
| 40 | h1 { | ||
| 41 | line-height: 140%; | ||
| 42 | font-weight: 600; | ||
| 43 | font-size: 210%; | ||
| 44 | } | ||
| 45 | |||
| 46 | h2,h3,h4,h5 { | ||
| 47 | /*margin-top: 50px;*/ | ||
| 48 | font-weight: 500; | ||
| 49 | } | ||
| 50 | |||
| 51 | img { | ||
| 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 | |||
| 62 | blockquote { | ||
| 63 | margin: 50px 0 50px 50px; | ||
| 64 | } | ||
| 65 | |||
| 66 | .pubdate { | ||
| 67 | font-size: 80%; | ||
| 68 | color: #666; | ||
| 69 | } | ||
| 70 | |||
| 71 | /********************************************************** CODE HIGHLIGHTING */ | ||
| 72 | |||
| 73 | pre, code { | ||
| 74 | font-family: 'Source Code Pro', monospace !important; | ||
| 75 | font-weight: 500; | ||
| 76 | } | ||
| 77 | |||
| 78 | pre { | ||
| 79 | font-size: 85%; | ||
| 80 | margin: 20px; | ||
| 81 | background: #eee; | ||
| 82 | } | ||
| 83 | |||
| 84 | p > 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 | |||
| 96 | p > code:hover { | ||
| 97 | background: fuchsia; | ||
| 98 | } | ||
| 99 | |||
| 100 | /***************************************************************** OL COUNTER */ | ||
| 101 | |||
| 102 | ol { | ||
| 103 | list-style: none; | ||
| 104 | counter-reset: li; | ||
| 105 | } | ||
| 106 | |||
| 107 | ol li { | ||
| 108 | counter-increment: li; | ||
| 109 | } | ||
| 110 | |||
| 111 | ol 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 | |||
| 122 | ol li a { | ||
| 123 | text-decoration: none; | ||
| 124 | } | ||
| 125 | |||
| 126 | /********************************************************************* TABLES */ | ||
| 127 | |||
| 128 | table { | ||
| 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 | |||
| 138 | th,td { | ||
| 139 | border-bottom: 2px solid #888; | ||
| 140 | padding: 10px; | ||
| 141 | } | ||
| 142 | |||
| 143 | th { | ||
| 144 | font-size: 130%; | ||
| 145 | } | ||
| 146 | |||
| 147 | tr: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 | |||
| 177 | pre::-webkit-scrollbar { | ||
| 178 | width: 5px; | ||
| 179 | height: 8px; | ||
| 180 | background-color: transparent; | ||
| 181 | } | ||
| 182 | |||
| 183 | pre::-webkit-scrollbar-thumb { | ||
| 184 | background: #ddd; | ||
| 185 | } | ||
| 186 | |||
| 187 | /*************************************************************** HEADER + NAV */ | ||
| 188 | |||
| 189 | menu { | ||
| 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 | |||
| 198 | menu a.logo { | ||
| 199 | font-weight: 600; | ||
| 200 | text-decoration: none; | ||
| 201 | font-size: 130%; | ||
| 202 | padding: 5px 0px ; | ||
| 203 | } | ||
| 204 | |||
| 205 | menu a.logo:hover { | ||
| 206 | /*background: fuchsia; | ||
| 207 | color: white;*/ | ||
| 208 | } | ||
| 209 | |||
| 210 | menu nav { | ||
| 211 | text-align: right; | ||
| 212 | margin-top: 3px; | ||
| 213 | } | ||
| 214 | |||
| 215 | menu nav a { | ||
| 216 | padding-top: 8px; | ||
| 217 | margin-left: 25px; | ||
| 218 | } | ||
| 219 | |||
| 220 | menu nav a svg { | ||
| 221 | width: 20px; | ||
| 222 | height: 20px; | ||
| 223 | } | ||
| 224 | |||
| 225 | /********************************************************************* FOOTER */ | ||
| 226 | |||
| 227 | footer { | ||
| 228 | padding-top: 50px; | ||
| 229 | padding-bottom: 50px; | ||
| 230 | font-weight: 500; | ||
| 231 | font-size: 80%; | ||
| 232 | } | ||
| 233 | |||
| 234 | footer > * { | ||
| 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 | |||
| 269 | article img[src*="#large"], | ||
| 270 | article 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 | ||
| 2 | document.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 | ||
| 14 | let links = document.links; | ||
| 15 | for (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 @@ | |||
| 1 | Prism.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 | |||
| 7 | Prism.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 | |||
| 32 | delete Prism.languages.c['class-name']; | ||
| 33 | delete 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 @@ | |||
| 1 | Prism.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 | |||
| 22 | Prism.languages.css['atrule'].inside.rest = Prism.languages.css; | ||
| 23 | |||
| 24 | if (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 @@ | |||
| 1 | Prism.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 | }); | ||
| 12 | delete 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 @@ | |||
| 1 | Prism.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 | |||
| 9 | Prism.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 | |||
| 23 | Prism.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 | }); | ||
| 42 | Prism.languages.javascript['template-string'].inside['interpolation'].inside.rest = Prism.languages.javascript; | ||
| 43 | |||
| 44 | if (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 | |||
| 56 | Prism.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 @@ | |||
| 1 | Prism.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 | |||
| 14 | Prism.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 @@ | |||
| 1 | Prism.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 | |||
| 9 | Prism.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 | |||
| 7 | Prism.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 | |||
| 55 | Prism.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 @@ | |||
| 1 | Prism.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 | |||
| 141 | pre[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 | |||
| 6 | var _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 | |||
| 20 | var 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, '&').replace(/</g, '<').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, '"') + '"'; | ||
| 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 | |||
| 540 | if (typeof module !== 'undefined' && module.exports) { | ||
| 541 | module.exports = Prism; | ||
| 542 | } | ||
| 543 | |||
| 544 | // hack for components to work correctly in node.js | ||
| 545 | if (typeof global !== 'undefined') { | ||
| 546 | global.Prism = Prism; | ||
| 547 | } | ||
| 548 | |||
| 549 | |||
| 550 | /* ********************************************** | ||
| 551 | Begin prism-markup.js | ||
| 552 | ********************************************** */ | ||
| 553 | |||
| 554 | Prism.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 | |||
| 595 | Prism.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 | ||
| 599 | Prism.hooks.add('wrap', function (env) { | ||
| 600 | |||
| 601 | if (env.type === 'entity') { | ||
| 602 | env.attributes['title'] = env.content.replace(/&/, '&'); | ||
| 603 | } | ||
| 604 | }); | ||
| 605 | |||
| 606 | Prism.languages.xml = Prism.languages.extend('markup', {}); | ||
| 607 | Prism.languages.html = Prism.languages.markup; | ||
| 608 | Prism.languages.mathml = Prism.languages.markup; | ||
| 609 | Prism.languages.svg = Prism.languages.markup; | ||
| 610 | |||
| 611 | |||
| 612 | /* ********************************************** | ||
| 613 | Begin prism-css.js | ||
| 614 | ********************************************** */ | ||
| 615 | |||
| 616 | Prism.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 | |||
| 637 | Prism.languages.css['atrule'].inside.rest = Prism.languages.css; | ||
| 638 | |||
| 639 | if (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 | |||
| 674 | Prism.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 | |||
| 710 | Prism.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 | |||
| 731 | Prism.languages.javascript['class-name'][0].pattern = /(\b(?:class|interface|extends|implements|instanceof|new)\s+)[\w.\\]+/ | ||
| 732 | |||
| 733 | Prism.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 | |||
| 768 | Prism.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 | |||
| 788 | if (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 | |||
| 800 | Prism.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 | --- | ||
| 2 | layout: post | ||
| 3 | title: Golang profiling simplified | 1 | title: Golang profiling simplified |
| 4 | description: Golang profiling made easy | ||
| 5 | slug: golang-profiling-simplified | ||
| 6 | type: note | ||
| 7 | date: 2017-03-07 | 2 | date: 2017-03-07 |
| 8 | --- | 3 | tags: blog |
| 9 | 4 | hide: false | |
| 10 | **Table of contents** | 5 | ---- |
| 11 | |||
| 12 | 1. [Where are my pprof files?](#where-are-my-pprof-files) | ||
| 13 | 2. [Why is my cpu profile empty?](#why-is-my-cpu-profile-empty) | ||
| 14 | 3. [Profiling](#profiling) | ||
| 15 | 1. [Memory profiling](#memory-profiling) | ||
| 16 | 2. [CPU profiling](#cpu-profiling) | ||
| 17 | 3. [Generating profiling reports](#generating-profiling-reports) | ||
| 18 | 6 | ||
| 19 | Many 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. | 7 | Many 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 | ||
| 25 | By 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. | 13 | By 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 | ||
| 29 | I 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. | 17 | I 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 | ||
| 119 | This will generate PDF document with visualized profile. | 107 | This 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 | --- | ||
| 2 | layout: post | ||
| 3 | title: Profiling Python web applications with visual tools | 1 | title: Profiling Python web applications with visual tools |
| 4 | description: Missing link when debugging and profiling python web applications | ||
| 5 | slug: profiling-python-web-applications-with-visual-tools | ||
| 6 | type: note | ||
| 7 | date: 2017-04-21 | 2 | date: 2017-04-21 |
| 8 | --- | 3 | tags: blog |
| 9 | 4 | hide: false | |
| 10 | **Table of contents** | 5 | ---- |
| 11 | |||
| 12 | 1. [Simple web-service](#simple-web-service) | ||
| 13 | 2. [Visualize profile](#visualize-profile) | ||
| 14 | 3. [Update 2017-04-22](#update-2017-04-22) | ||
| 15 | 6 | ||
| 16 | I 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. | 7 | I 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 | --- | ||
| 2 | layout: post | ||
| 3 | title: Simple IOT application supported by real-time monitoring and data history | 1 | title: Simple IOT application supported by real-time monitoring and data history |
| 4 | description: Develop simple IOT application with Arduino MKR1000 and Python | ||
| 5 | slug: simple-iot-application | ||
| 6 | type: note | ||
| 7 | date: 2017-08-11 | 2 | date: 2017-08-11 |
| 8 | --- | 3 | tags: blog |
| 9 | 4 | hide: false | |
| 10 | **Table of contents** | 5 | ---- |
| 11 | |||
| 12 | 1. [Initial thoughts](#initial-thoughts) | ||
| 13 | 2. [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) | ||
| 17 | 3. [Sending data to API with Arduino MKR1000](#sending-data-to-api-with-arduino-mkr1000) | ||
| 18 | 4. [Data visualization](#data-visualization) | ||
| 19 | 5. [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 | ||
| 41 | Schema below represents what we will try to achieve and how different parts correlates to each other. | 27 | Schema below represents what we will try to achieve and how different parts correlates to each other. |
| 42 | 28 | ||
| 43 |  | 29 |  |
| 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 | ||
| 87 | If this fails at any time please fix it before you continue, because nothing below will work otherwise. | 73 | If 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. | 75 | We use 0.0.0.0 as default host so that this app is available over your local network. If you find your local ip ```ifconfig``` and try accessing this site with your phone (if on same network/router as your machine) this should work as well (example of such ip ```http://192.168.1.15:5000```). This is a must have because Arduino will be accessing this application to send it's data. |
| 90 | 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 | ||
| 162 | After testing the service with Restlet Client you should be able to view your data in a database file ```data.db```. | 148 | After testing the service with Restlet Client you should be able to view your data in a database file ```data.db```. |
| 163 | 149 | ||
| 164 |  | 150 |  |
| 165 | 151 | ||
| 166 | You can also check the contents of new database file by using desktop client for SQLite → [DB Browser for SQLite](http://sqlitebrowser.org/). | 152 | You 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 |  | 154 |  |
| 169 | 155 | ||
| 170 | Table 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. | 156 | Table 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```. | 158 | If you will deploy this app with uWSGI and multi-threaded, use DSN (Data Source Name) url with ```?check_same_thread=False```. |
| 173 | 159 | ||
| 174 | Ok, 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. | 160 | Ok, 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 | ||
| 483 | If you navigate to ```http://0.0.0.0:5000``` you should see rendered chart as shown on picture below. | 469 | If you navigate to ```http://0.0.0.0:5000``` you should see rendered chart as shown on picture below. |
| 484 | 470 | ||
| 485 |  | 471 |  |
| 486 | 472 | ||
| 487 | Complete application with all the code is available for [download](/files/simple-iot-application.zip). | 473 | Complete 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 | ||
| 500 | Any comment or additional ideas are welcomed in comments below.) | 486 | Any 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 @@ | |||
| 1 | title: Simplifying and reducing clutter in my life and work | ||
| 2 | date: 2019-10-14 | ||
| 3 | tags: blog | ||
| 4 | hide: false | ||
| 5 | ---- | ||
| 6 | |||
| 7 | I 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 | |||
| 9 | I 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 | |||
| 11 | Not 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 | |||
| 13 | One 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 | |||
| 15 | I 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 | |||
| 17 | Next 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 | |||
| 19 | I 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 | |||
| 21 | So 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 | --- | ||
| 2 | layout: post | ||
| 3 | title: What I've learned developing ad server | 1 | title: What I've learned developing ad server |
| 4 | description: Lessons I learned developing contextual ad server | ||
| 5 | slug: what-i-ve-learned-developing-ad-server | ||
| 6 | type: note | ||
| 7 | date: 2017-04-17 | 2 | date: 2017-04-17 |
| 8 | --- | 3 | tags: blog |
| 9 | 4 | hide: false | |
| 10 | **Table of contents** | 5 | ---- |
| 11 | |||
| 12 | 1. [Aggregate everything](#aggregate-everything) | ||
| 13 | 2. [Measure everything](#measure-everything) | ||
| 14 | 3. [Cache control is your friend](#cache-control-is-your-friend) | ||
| 15 | 4. [Learn NGINX](#learn-nginx) | ||
| 16 | 5. [Use Redis/Memcached](#use-redismemcached) | ||
| 17 | 6. [Conclusion](#conclusion) | ||
| 18 | 6 | ||
| 19 | For 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. | 7 | For 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 | ||
| 27 | Initial 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. | 15 | Initial 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 | ||
| 29 | Because 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. | 17 | Because 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 | ||
| 31 | So now that you know basic information about the product lets get into the lessons we learned. | 19 | So 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 | --- | ||
| 2 | layout: page | ||
| 3 | title: Curriculum Vitae | 1 | title: Curriculum Vitae |
| 4 | description: Summary of my experiences, skills and major projects I have worked on through year | 2 | date: 2018-01-16 |
| 5 | slug: curriculum-vitae | 3 | tags: research |
| 6 | --- | 4 | hide: 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 | --- | ||
| 2 | layout: post | ||
| 3 | title: Encoding binary data into DNA sequence | 1 | title: Encoding binary data into DNA sequence |
| 4 | description: 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. | ||
| 5 | slug: encoding-binary-data-into-dna-sequence | ||
| 6 | type: research | ||
| 7 | date: 2019-01-03 | 2 | date: 2019-01-03 |
| 8 | --- | 3 | tags: research |
| 9 | 4 | hide: false | |
| 10 | **Table of contents** | 5 | ---- |
| 11 | |||
| 12 | 1. [Initial thoughts](#initial-thoughts) | ||
| 13 | 2. [Glossary](#glossary) | ||
| 14 | 3. [Data encoding](#data-encoding) | ||
| 15 | 4. [Quick history of DNA](#quick-history-of-dna) | ||
| 16 | 5. [What is DNA?](#what-is-dna) | ||
| 17 | 6. [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) | ||
| 21 | 7. [Encoding text file in practice](#encoding-text-file-in-practice) | ||
| 22 | 8. [Toolkit for encoding data](#toolkit-for-encoding-data) | ||
| 23 | 1. [dnae-encode](#dnae-encode) | ||
| 24 | 2. [dnae-png](#dnae-png) | ||
| 25 | 9. [Benchmarks](#benchmarks) | ||
| 26 | 10. [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. | |||
| 355 | gzip -9 < 10MB.fa > 10MB.fa.gz | 334 | gzip -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 | --- | ||
| 2 | layout: post | ||
| 3 | title: Using DigitalOcean Spaces Object Storage with FUSE | 1 | title: Using DigitalOcean Spaces Object Storage with FUSE |
| 4 | description: Using DigitalOcean Spaces Object Storage with FUSE | ||
| 5 | slug: using-digitalocean-spaces-object-storage-with-fuse | ||
| 6 | type: research | ||
| 7 | date: 2018-01-16 | 2 | date: 2018-01-16 |
| 8 | --- | 3 | tags: research |
| 9 | 4 | hide: false | |
| 10 | **Table of contents** | 5 | ---- |
| 11 | |||
| 12 | 1. [Is it possible to use them as a mounted drive with FUSE?](#is-it-possible-to-use-them-as-a-mounted-drive-with-fuse) | ||
| 13 | 2. [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) | ||
| 16 | 3. [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) | ||
| 17 | 4. [Observations and conslusion](#observations-and-conslusion) | ||
| 18 | 6 | ||
| 19 | Couple 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 :) | 7 | Couple 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 | ||
| 38 | Instuctions 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). | 26 | Instuctions 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 |  | 28 |  |
| 41 | 29 | ||
| 42 | After 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. | 30 | After 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 | ||
| 44 | When 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. | 32 | When 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 |  | 34 |  |
| 47 | 35 | ||
| 48 | Now that we have new Space and Access key we should SSH into our machine. | 36 | Now 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 | ||
| 116 | You can download [raw result here](/files/copy-benchmarks.tsv). Measurements are in seconds. | 104 | You 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 | |||
| 229 | print("CLOSE: %g seconds" % (result_time)) | 217 | print("CLOSE: %g seconds" % (result_time)) |
| 230 | ``` | 218 | ``` |
| 231 | 219 | ||
| 232 | You 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. | 220 | You 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 @@ | |||
| 1 | body { | ||
| 2 | line-height: 150%; | ||
| 3 | margin-bottom: 100px; | ||
| 4 | } | ||
| 5 | |||
| 6 | main { | ||
| 7 | max-width: 680px; | ||
| 8 | padding: 20px 30px; | ||
| 9 | } | ||
| 10 | |||
| 11 | nav { | ||
| 12 | margin-bottom: 50px; | ||
| 13 | } | ||
| 14 | |||
| 15 | nav a { | ||
| 16 | display: inline-block; | ||
| 17 | margin-right: 20px; | ||
| 18 | } | ||
| 19 | |||
| 20 | h1 { | ||
| 21 | font-size: 280%; | ||
| 22 | line-height: initial; | ||
| 23 | } | ||
| 24 | |||
| 25 | h2 { | ||
| 26 | font-size: 200%; | ||
| 27 | line-height: initial; | ||
| 28 | } | ||
| 29 | |||
| 30 | h3 { | ||
| 31 | font-size: 160%; | ||
| 32 | line-height: initial; | ||
| 33 | } | ||
| 34 | |||
| 35 | img { | ||
| 36 | max-width: 100%; | ||
| 37 | margin: 30px auto; | ||
| 38 | display: block; | ||
| 39 | } | ||
| 40 | |||
| 41 | ul.article-list li { | ||
| 42 | margin-bottom: 10px; | ||
| 43 | } | ||
| 44 | |||
| 45 | ul.article-list time { | ||
| 46 | display: inline-block; | ||
| 47 | min-width: 120px; | ||
| 48 | } | ||
| 49 | |||
| 50 | article .info { | ||
| 51 | font-style: oblique; | ||
| 52 | } | ||
| 53 | |||
| 54 | pre { | ||
| 55 | overflow: auto; | ||
| 56 | } | ||
| 57 | |||
| 58 | table { | ||
| 59 | width: 100%; | ||
| 60 | } | ||
| 61 | |||
| 62 | table, th, td { | ||
| 63 | border: 1px solid black; | ||
| 64 | text-align: left; | ||
| 65 | } | ||
| 66 | |||
| 67 | th, 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 | } | ||
