├── .gitignore ├── Content ├── about.md ├── afterWork.md ├── archive.md ├── index.md ├── notes.md ├── notes │ ├── Adaptivity and Resilience.md │ ├── Arrays and Strings.md │ ├── Big0.md │ ├── Bit Manipulation.md │ ├── Cheat Sheet of PM.md │ ├── Decision paralysis.md │ ├── Good Metrics.md │ ├── K-nearest neighbors.md │ ├── Linked Lists.md │ ├── Math and Logic Puzzles.md │ ├── Meeting Facilitation.md │ ├── Object Oriented Design.md │ ├── Point Free.md │ ├── Practical Deep Learning.md │ ├── Product.md │ ├── Recursion and Dynamic Programming.md │ ├── Searching.md │ ├── Sorting.md │ ├── Stacks and Queues.md │ ├── Strategic Thinking.md │ ├── Strategy vs Planning.md │ ├── Strategy.md │ ├── Strings.md │ ├── System Design and Scalability.md │ ├── Trees and Graphs.md │ ├── Useful Algorithms.md │ ├── iOS AV.md │ ├── iOS Background Tasks.md │ ├── iOS Concurrency.md │ └── notes.code-workspace └── posts │ ├── 2019-03-11-aerogami_series_part_1.md │ ├── 2019-03-17-aerogami_series_part_2.md │ ├── 2019-03-18-aerogami_series_part_3.md │ ├── 2019-03-20-aerogami_series_part_4.md │ ├── 2019-03-24-aerogami_series_part_5.md │ ├── 2020-01-26-publish.md │ └── 2020-06-23-app-clip.md ├── Output ├── CNAME ├── Pure │ └── styles.css ├── about │ └── index.html ├── afterWork │ └── index.html ├── all.css ├── archive │ └── index.html ├── feed.rss ├── images │ ├── Octocat.png │ ├── aerogami-tutorial │ │ ├── part1 │ │ │ ├── architecture.png │ │ │ └── screenshot.png │ │ ├── part2 │ │ │ └── project_frameworks.png │ │ ├── part4 │ │ │ ├── app_icon.gif │ │ │ ├── app_icon.png │ │ │ ├── app_screen_example.png │ │ │ └── app_screen_real.png │ │ └── part5 │ │ │ └── app_demo.gif │ ├── app-clip │ │ ├── associated_domains.png │ │ ├── associated_domains_example.png │ │ ├── hello_app_clip.png │ │ ├── new_target.png │ │ ├── new_target_app_clip.png │ │ ├── testing.png │ │ └── testing_success.png │ ├── archive │ │ ├── aerogami.png │ │ ├── bemed.jpg │ │ ├── bemed0.png │ │ ├── bukdetektyvas0.png │ │ ├── bukdetektyvas1.jpg │ │ ├── bukdetektyvas2.jpg │ │ ├── bukdetektyvas3.jpg │ │ ├── bukdetektyvas4.jpg │ │ ├── radistaivillage0.png │ │ ├── radistaivillage1.jpg │ │ ├── summerburst0.png │ │ ├── summerburst1.jpg │ │ ├── whatsthescore1.PNG │ │ ├── whatsthescore2.PNG │ │ ├── whatsthescore3.PNG │ │ ├── whatsthescore4.PNG │ │ └── whatsthescore5.PNG │ ├── notes │ │ ├── 1bccd220960e2615c1c6b0933efea56e88b83393de2c8d325a749f8d37b9e4f6.png │ │ ├── 42d971b30d15ec5efd2f8e1238e39424451afd922a0d719fa83811f80aeaf160.png │ │ ├── 4b53bbaf1ca1cab5b0a3959afb3ae6aaeefd5c8bf7772fb509f1d80a00ca5492.png │ │ ├── 67ea9a4463080be07ce89fc92ba437d53482bdce56217f6ff1ffe17e021bf200.png │ │ ├── 7e695531912858f96e685ace9f097d2692be7ebcd2c4e9808388f7a07f171669.png │ │ ├── 80f6b547b2282e1625e834be09bfa310ff0bb1f97819d40ace9eb9b28633f2e3.png │ │ ├── 86b326043320bbd1a5d8d05117e1187489c2d15b285e3a773dd4476c23e2dc14.png │ │ ├── 92fd3d4ecd5caee3c6cc2980d0918499ff0b5588294b07575264314b0f8e47ca.png │ │ ├── b8daa97dce2af0a8feb01d20e075456e68904da809bc44e9afb26ac5a82ca17e.png │ │ ├── f53df9570974ef456f0347b2fe8bb8e09876c4c0c4910f51a3fb2bfb42ffc5fb.png │ │ └── fa7d4a6f8a071d1f4a6f1e3e9572c148813a06ed4f917a948a40f932f719b073.png │ └── publish │ │ ├── blog_1.png │ │ ├── blog_new_1.png │ │ ├── blog_new_2.png │ │ ├── previous_1.png │ │ └── previous_2.png ├── index.html ├── notes │ ├── Adaptivity and Resilience │ │ └── index.html │ ├── Arrays and Strings │ │ └── index.html │ ├── Big0 │ │ └── index.html │ ├── Bit Manipulation │ │ └── index.html │ ├── Cheat Sheet of PM │ │ └── index.html │ ├── Decision paralysis │ │ └── index.html │ ├── Good Metrics │ │ └── index.html │ ├── K-nearest neighbors │ │ └── index.html │ ├── Linked Lists │ │ └── index.html │ ├── Math and Logic Puzzles │ │ └── index.html │ ├── Meeting Facilitation │ │ └── index.html │ ├── Object Oriented Design │ │ └── index.html │ ├── Point Free │ │ └── index.html │ ├── Practical Deep Learning │ │ └── index.html │ ├── Product │ │ └── index.html │ ├── Recursion and Dynamic Programming │ │ └── index.html │ ├── Searching │ │ └── index.html │ ├── Sorting │ │ └── index.html │ ├── Stacks and Queues │ │ └── index.html │ ├── Strategic Thinking │ │ └── index.html │ ├── Strategy vs Planning │ │ └── index.html │ ├── Strategy │ │ └── index.html │ ├── Strings │ │ └── index.html │ ├── System Design and Scalability │ │ └── index.html │ ├── Trees and Graphs │ │ └── index.html │ ├── Useful Algorithms │ │ └── index.html │ ├── iOS AV │ │ └── index.html │ ├── iOS Background Tasks │ │ └── index.html │ ├── iOS Concurrency │ │ └── index.html │ └── index.html ├── posts │ ├── 2019-03-11-aerogami_series_part_1 │ │ └── index.html │ ├── 2019-03-17-aerogami_series_part_2 │ │ └── index.html │ ├── 2019-03-18-aerogami_series_part_3 │ │ └── index.html │ ├── 2019-03-20-aerogami_series_part_4 │ │ └── index.html │ ├── 2019-03-24-aerogami_series_part_5 │ │ └── index.html │ ├── 2020-01-26-publish │ │ └── index.html │ ├── 2020-06-23-app-clip │ │ └── index.html │ └── index.html ├── sitemap.xml ├── tags │ ├── app-clip │ │ └── index.html │ ├── index.html │ ├── ios-14 │ │ └── index.html │ ├── ios │ │ └── index.html │ ├── swift │ │ └── index.html │ ├── tutorial │ │ └── index.html │ └── web │ │ └── index.html └── webfonts │ ├── fa-brands-400.eot │ ├── fa-brands-400.svg │ ├── fa-brands-400.ttf │ ├── fa-brands-400.woff │ ├── fa-brands-400.woff2 │ ├── fa-regular-400.eot │ ├── fa-regular-400.svg │ ├── fa-regular-400.ttf │ ├── fa-regular-400.woff │ ├── fa-regular-400.woff2 │ ├── fa-solid-900.eot │ ├── fa-solid-900.svg │ ├── fa-solid-900.ttf │ ├── fa-solid-900.woff │ └── fa-solid-900.woff2 ├── Package.resolved ├── Package.swift ├── Resources ├── CNAME ├── Pure │ └── styles.css ├── all.css ├── images │ ├── Octocat.png │ ├── aerogami-tutorial │ │ ├── part1 │ │ │ ├── architecture.png │ │ │ └── screenshot.png │ │ ├── part2 │ │ │ └── project_frameworks.png │ │ ├── part4 │ │ │ ├── app_icon.gif │ │ │ ├── app_icon.png │ │ │ ├── app_screen_example.png │ │ │ └── app_screen_real.png │ │ └── part5 │ │ │ └── app_demo.gif │ ├── app-clip │ │ ├── associated_domains.png │ │ ├── associated_domains_example.png │ │ ├── hello_app_clip.png │ │ ├── new_target.png │ │ ├── new_target_app_clip.png │ │ ├── testing.png │ │ └── testing_success.png │ ├── archive │ │ ├── aerogami.png │ │ ├── bemed.jpg │ │ ├── bemed0.png │ │ ├── bukdetektyvas0.png │ │ ├── bukdetektyvas1.jpg │ │ ├── bukdetektyvas2.jpg │ │ ├── bukdetektyvas3.jpg │ │ ├── bukdetektyvas4.jpg │ │ ├── radistaivillage0.png │ │ ├── radistaivillage1.jpg │ │ ├── summerburst0.png │ │ ├── summerburst1.jpg │ │ ├── whatsthescore1.PNG │ │ ├── whatsthescore2.PNG │ │ ├── whatsthescore3.PNG │ │ ├── whatsthescore4.PNG │ │ └── whatsthescore5.PNG │ ├── notes │ │ ├── 1bccd220960e2615c1c6b0933efea56e88b83393de2c8d325a749f8d37b9e4f6.png │ │ ├── 42d971b30d15ec5efd2f8e1238e39424451afd922a0d719fa83811f80aeaf160.png │ │ ├── 4b53bbaf1ca1cab5b0a3959afb3ae6aaeefd5c8bf7772fb509f1d80a00ca5492.png │ │ ├── 67ea9a4463080be07ce89fc92ba437d53482bdce56217f6ff1ffe17e021bf200.png │ │ ├── 7e695531912858f96e685ace9f097d2692be7ebcd2c4e9808388f7a07f171669.png │ │ ├── 80f6b547b2282e1625e834be09bfa310ff0bb1f97819d40ace9eb9b28633f2e3.png │ │ ├── 86b326043320bbd1a5d8d05117e1187489c2d15b285e3a773dd4476c23e2dc14.png │ │ ├── 92fd3d4ecd5caee3c6cc2980d0918499ff0b5588294b07575264314b0f8e47ca.png │ │ ├── b8daa97dce2af0a8feb01d20e075456e68904da809bc44e9afb26ac5a82ca17e.png │ │ ├── f53df9570974ef456f0347b2fe8bb8e09876c4c0c4910f51a3fb2bfb42ffc5fb.png │ │ └── fa7d4a6f8a071d1f4a6f1e3e9572c148813a06ed4f917a948a40f932f719b073.png │ └── publish │ │ ├── blog_1.png │ │ ├── blog_new_1.png │ │ ├── blog_new_2.png │ │ ├── previous_1.png │ │ └── previous_2.png └── webfonts │ ├── fa-brands-400.eot │ ├── fa-brands-400.svg │ ├── fa-brands-400.ttf │ ├── fa-brands-400.woff │ ├── fa-brands-400.woff2 │ ├── fa-regular-400.eot │ ├── fa-regular-400.svg │ ├── fa-regular-400.ttf │ ├── fa-regular-400.woff │ ├── fa-regular-400.woff2 │ ├── fa-solid-900.eot │ ├── fa-solid-900.svg │ ├── fa-solid-900.ttf │ ├── fa-solid-900.woff │ └── fa-solid-900.woff2 └── Sources └── Blog ├── Blog.swift ├── BlogTheme ├── BlogDateFormatter.swift ├── BlogHTMLFactory.swift ├── Nodes │ ├── Node+Footer.swift │ ├── Node+Grid.swift │ ├── Node+Head.swift │ ├── Node+Header.swift │ ├── Node+Icon.swift │ ├── Node+Item.swift │ ├── Node+Page.swift │ ├── Node+PageContent.swift │ ├── Node+Post.swift │ ├── Node+PostExcerpt.swift │ ├── Node+Posts.swift │ ├── Node+Sidebar.swift │ ├── Node+TagList.swift │ └── Notes │ │ ├── Node+NotePage.swift │ │ ├── Node+NotesPage.swift │ │ └── Topic.swift └── Theme+Blog.swift ├── SocialMediaLink.swift └── main.swift /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /build 3 | /.build 4 | /.swiftpm 5 | /*.xcodeproj 6 | .publish 7 | .vscode -------------------------------------------------------------------------------- /Content/about.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: About 3 | --- 4 | 5 | Hey, welcome to my blog! I've been doing software development since 2015, most of it on the iOS platform. Throughout this time I worked as a solo developer, with small and large teams as well as taught iOS development in a coding academy. 6 | 7 | When working on my own I got the experience of communicating with clients face to face, formulating requirements, making designs, and eventually releasing applications. The work in larger organizations taught me the importance of clear communication both in real-life and in code. I developed in large and fast-growing codebases that required rethinking, coordination, refactoring, and automation efforts to make them suitable for the work of multiple teams. 8 | 9 | I intend to use this blog as a way to share my learnings, my projects or just to fulfill random bursts of creativity. 10 | 11 | Feel free to contact me on Twitter, LinkedIn or simply write me an email! -------------------------------------------------------------------------------- /Content/afterWork.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: After work 3 | --- 4 | 5 | Here I'm sharing projects not related to software development: 6 | 7 | - [A traveling blog - 100days.travel](https://www.staskus.io/100DaysOfTravel/) 8 | -------------------------------------------------------------------------------- /Content/archive.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: App Store Archive 3 | --- 4 | 5 | Here are some of the applications I published that are no longer available in the App Store: 6 | 7 | ## beMED (2020) 8 | 9 | beMED 10 | 11 | The beMED was the first Medical Application in Lithuania. It provided medical staff with easy and convenient access to complex medical forms, scales, and classifications. 12 | 13 | * Created a JSON structure that supports the definition of different measurements, mathematical 14 | expressions, and conclusions which was used to generate dynamic and interactive UIs. 15 | * Persisted data using Firebase which allowed to update the data of the application remotely. 16 | 17 | beMED 18 | 19 | ## Aerogami (2019) 20 | 21 | iOS application for discovering flight ideas. 22 | 23 | Aerogami was written entirely in Swift. It was used to [show](https://www.staskus.io/posts/2019-03-11-aerogami_series_part_1/) iOS application creation approach which separates code into frameworks, leveraging RxSwift for composing asynchronous operations and used the newest Swift APIs for encoding and decoding data. 24 | 25 | Aerogami 26 | 27 | ## What's The Score? (ViscaWeb) (2017 - 2018) 28 | 29 | This livescore application was created for the World Cup 2018 which presented many fun challenges in dealing with the constant flow of the data. 30 | 31 | What's The Score 32 | What's The Score 33 | What's The Score 34 | What's The Score 35 | What's The Score 36 | 37 | ## Būk Detektyvas (Be Detective) (2017 - 2018) 38 | 39 | Buk Detektyvas 40 | 41 | „Būk Detektyvas!” was a location-based application that allowed users to travel and discover interesting places. It was possible to have an account, share the experiences and compete with the others. This application also used image editing technologies creating the possibility to compare future and past images in real-time. It was created together with [the National Lithuanian Television](http://www.lrt.lt/naujienos/tavo_lrt/37/179323). 42 | 43 | * Stored and processed user-generated data using Firebase Realtime Database, Database Rules, and 44 | Cloud Functions that allowed to guard private data as well as generate public statistics and the 45 | leaderboard. 46 | * Implemented interactive location-based quizzes using MapKit and CoreLocation. 47 | * Developed animations using CoreAnimation which resulted in a user-friendly experience. 48 | 49 | Buk Detektyvas 50 | Buk Detektyvas 51 | Buk Detektyvas 52 | Buk Detektyvas 53 | 54 | ## Summerburst Baltic (2016) 55 | 56 | Summerburst 57 | 58 | Summerburst Baltic ’16 was an application for the international music festival. This application followed the modern design guidelines to reflect the event’s brand and spirit. The users of this application could follow the social network activity of the organizers and artists. Additionally, it was allowed to set reminders for your favorite performances and receive important notifications. Location services were also used to enable easier navigation in the territory of an event. 59 | 60 | beMED 61 | 62 | ## Radistai Village (2015 - 2016) 63 | 64 | Radistai Village 65 | 66 | Radistai Village ’15 was a music festival application. Using the application users could conveniently check the schedule for all the events. Moreover, it was possible to set reminders for your favorite performances and receive important notifications about them. This application contained an originally designed event map that shows the user’s location and convenient information. 67 | 68 | Radistai Village ’16 was a new version of the musical festival application. It gave the organizers a possibility to always keep the schedule up-to-date and notify users of the changes. Moreover, it displayed the social network feeds to keep in touch with the organizers and artists. 69 | 70 | Radistai Village -------------------------------------------------------------------------------- /Content/index.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Content/notes.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Notes 3 | --- -------------------------------------------------------------------------------- /Content/notes/Adaptivity and Resilience.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Adaptivity and Resilience 3 | excerpt: Soft Skills 4 | --- 5 | 6 | ## Awareness 7 | 8 | We need to learn of our `style under stress`, and know the default coping style: 9 | 10 | ### For example 11 | 12 | - Freeze: slow/stall 13 | - Fight: aggressive problem-solve, debate 14 | - Rabbit holing: dig deep on one topic 15 | - Spin: jump from topic to topic, distract 16 | - Robot-mode: show no emotions 17 | - Helper-mode: give advice 18 | 19 | When we notice someones default coping style, we can help them by noticing people mentioning or doing these things, and offering help or asking how they are doing. "Don' take a bait and make it worse". See through: Don't take others' response personally. "Oh, That's them coping!" 20 | 21 | ## Individual level response 22 | 23 | ### Regain homeostaic balance 24 | 25 | Homeostasis is the tendency to maintain a stable, relatively constant internal environment 26 | 27 | - Animals shake it out 28 | - Humans breathe, stretch, move 29 | 30 | People who have patterns of resilience understand when the situation need to be changed: when they need to breathe, stretch, go grab a water. 31 | 32 | #### Deliberate pauses 33 | 34 | - Micro: Stretches between meeetings 35 | - Meso: Lunch breaks and constant sleeping time 36 | - Macro: Vacations 37 | 38 | 39 | ### De-fuse 40 | 41 | Brain is a problem-finding machine. If we just let it run, it will find constant stream of problems. Just aknowledge the thoughts and let them go. 42 | 43 | To defuse, prefix the worriyng thoughts with: "My brain is having the thought that...". You can look deeper what these worries are trying to tell you and what needs are behind them. 44 | 45 | ### Do a two-hander 46 | 47 | Goal: Organize the thinking 48 | 49 | - Can't control, can control 50 | - Won't focus on, will focus on 51 | - What I don't know, do know 52 | 53 | ### Articulate the positive 54 | 55 | It's helpful just to think about any positive things that happened recently. Ask yourself "What am I grateful for?", "What can I learn from this?" 56 | 57 | 58 | ## Team level response 59 | 60 | ### Invite cognitive offload 61 | 62 | #### Small talk questions 63 | 64 | - How are you feeling today? 65 | - How has you week been going? 66 | - What's been you highlight this week? What made it a highlight? 67 | 68 | #### Playback 69 | 70 | - Am I right in hearing you say? 71 | - I'm wondering if you are feeling frustrated / worried / confused? 72 | - Ok, you're wanting certainty / closure/ clarity? Is that right? 73 | 74 | 75 | ### Reset questions 76 | 77 | Reset questions help when there's a feeling of being stuck: 78 | 79 | Observation statement: I feel we're spinning a bit. 80 | Reset: How about we pause and do a quick reset... 81 | Ask questions: 82 | - What's the most important thing? 83 | - What is our decision criteria? 84 | - What's another angle? 85 | - What's important to you about this? 86 | - What's the first smallest step to take? 87 | - How can I help? 88 | - Should we take a break? 89 | 90 | ### Scenario planning 91 | 92 | Use the term `Let's create scenarios`. Creatre 2-3 scenarios of what could happen about the things we're anxious about, add likelihood, impact, readiness, comfort level. 93 | 94 | ### Celebrate adaptivity 95 | 96 | Discuss: Where are you/your team already good at celebrating adaptivity? What opportunities do you have to do this more? How do you want to celebrate adaptivity moving forward? -------------------------------------------------------------------------------- /Content/notes/Big0.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Big O 3 | excerpt: Algorithms 4 | --- 5 | 6 | Big O describes the efficiency of algorithms. 7 | 8 | ## Time Complexity 9 | 10 | ## Space Complexity 11 | 12 | Space complexity is the amount of memory required by an algorithm. 13 | 14 | ### Recursive calls 15 | 16 | In recursive functions, each call is added to the stack and we take this space into account. 17 | 18 | ## Cases 19 | 20 | * Best Case 21 | * Worst Case 22 | * Expected Case 23 | 24 | The best case is not insightful. The expected case and the worst case are usually the same but not always. 25 | 26 | ## Simplification 27 | 28 | Big O is only concerned about the *rate of increase* and expressed how the runtime scales, thus we can drop the constants and non-dominant terms. O(2N) is just O(N). 29 | 30 | * O(N$^2$ + N) is O($N^2$) 31 | * O(N + log N) is O(N) 32 | * O(100*2$^2$ + 5000N$^2$) is O(2$^n$) 33 | 34 | ![Complexities - GeeksForGeeks.org](/images/notes/42d971b30d15ec5efd2f8e1238e39424451afd922a0d719fa83811f80aeaf160.png) 35 | 36 | However, have in mind that it's usually not possible to remove *multiple variables*, they still need to be represented in the notation. 37 | 38 | For example, to sort an array of sorted strings the complexity would be *O($a*s$(log a + log s))*, where a - array length, s - longest string length. In such cases, we cannot simplify much further. 39 | 40 | ### O(n) 41 | 42 | The algorithm that reverses an array only going through half of the array does not impact big O time and still has O(n) time complexity. 43 | 44 | ### O(log N) 45 | 46 | An algorithm will likely have an O(log N) runtime when the number of elements in the problem space gets halved at every step. Example - binary search. 47 | 48 | ### O(2$^n$) 49 | 50 | The base of an exponential complexity matters. 51 | 52 | ### O(2$^l$$^o$$^g$$^N$) 53 | 54 | This expression can be simplified to O(n). If we search binary tree making recursive calls the depth is roughly logN so it doesn't turn the recursive function exponential. 55 | 56 | ## Memoization 57 | 58 | Caching previously computed values is an optimization technique called memoization. It is a very common way to optimize exponential time recursive algorithms. 59 | 60 | -------------------------------------------------------------------------------- /Content/notes/Bit Manipulation.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Bit Manipulation 3 | excerpt: Operations 4 | --- 5 | 6 | ``` 7 | X ^ 0s = X 8 | X & 0s = 0 9 | X | 0s = X 10 | 11 | X ^ 1s = !x 12 | X & 1s = X 13 | X | 1s = 1s 14 | 15 | X ^ X = 0 16 | X & X = X 17 | X | X = X 18 | ``` 19 | 20 | **Logical Shift** - we shift the bits and put 0 in the most significant bit. 21 | **Arithmetic Shift** - we shift values to the right but fill new bits with the values of the sign bit. Essentially meaning division by 2. 22 | 23 | ## Example Tasks 24 | 25 | ### Get Bit 26 | 27 | ```swift 28 | func getBit(num: Int, position: Int) -> Bool { 29 | return (num & (1 << position)) != 0 30 | } 31 | 32 | getBit(num: 5, position: 2) // 0101 & 0100 = 0100 != 0 33 | getBit(num: 5, position: 1) // 0101 & 0010 = 0000 == 0 34 | ``` 35 | 36 | ### What does code (n & n-1) == 0 do? 37 | 38 | This logic checks if n is a power of 2 (or if n is 0) 39 | 40 | ### Write a function to determine the number of bits you need to flip to convert integer A to integer B 41 | 42 | ```swift 43 | func bitSwapsRequired(_ a: Int, _ b: Int) -> Int { 44 | var count = 0 45 | 46 | var i = a ^ b 47 | 48 | while i != 0 { 49 | count += 1 50 | i = i & (i - 1) 51 | } 52 | 53 | return count 54 | } 55 | 56 | print(bitSwapsRequired(29, 15)) // 2 57 | ``` -------------------------------------------------------------------------------- /Content/notes/Cheat Sheet of PM.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Cheat Sheet of PM 3 | excerpt: Project Management 4 | --- 5 | 6 | ## Before 7 | 8 | ### Justify The Project 9 | 10 | 1. Define **Project Drivers** - people who benefit from the project and who can define the results and **Project Supporters** who make it posssible. 11 | 2. Confirm that the project fits your organization’s priorities. 12 | 1. Find multiple written sources of confirmation, both primary and secondary sources. 13 | 3. Meet with the key audience to think about the issues and clarify any ambiguities. 14 | 4. Compare written sources, meeting notes, and data. Clarify ambiguities. 15 | 16 | ### Set Objectives 17 | 18 | 1. Focus on a clear outcome, not an activity. 19 | 2. Objectives should be: 20 | 1. **S**pecific 21 | 2. **M**easurable 22 | 3. **A**ggresive 23 | 4. **R**ealistic 24 | 5. **T**ime-sensitive 25 | 3. Use simple and clear language 26 | 4. Each objective needs to have a measure and each measure needs to have a performance target ("Develop x feature until the end of Q3"). 27 | 28 | ### Set schedules 29 | 30 | 1. Identify **all** required activities and b**reak them down** into concrete steps. 31 | 2. Consider **duration** and **interdependencies** (how all activities depend on each other). 32 | 3. Identify how the activities will be performed (a **strategy**). 33 | 4. Identify how many **resources** you have (number of engineering hours for example). 34 | 5. Write down assumptions of scheduling and resources. 35 | 6. Identify and plan for **risks**. 36 | 7. Involve the project's drivers and supporters. 37 | 38 | ## During 39 | 40 | ### Sustaining commitment 41 | 42 | 1. Clarify project benefits for the organization and team members. 43 | 2. Involve team members in the planning process. 44 | 3. Show that the project objectives are achievable. 45 | 4. Address issues and concerns. 46 | 5. Provide feedback and acknowledge contributions. 47 | 48 | ### Hold people accountable 49 | 50 | 1. Be specific about the results, time frames and constraints. 51 | 2. Get the team to commit and write down the commitments. 52 | 3. Have a way to monitor the progress and follow it. 53 | 4. Communicate commitments to others. 54 | 5. Meet your own commitments. 55 | 56 | ## Common pitfalls to avoid 57 | 58 | 1. Vague project objectives. 59 | 2. Overlooked project's drivers and supporters. 60 | 3. Ignoring the question of how likely it is that you;;be able to get the required amounts of time (**backing in**). 61 | 4. Not writing down the commitments. 62 | 5. Not keeping the plan up to date. 63 | 6. Not communicating. -------------------------------------------------------------------------------- /Content/notes/Decision paralysis.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Decision Paralysis 3 | excerpt: Project Management 4 | --- 5 | 6 | Decision paralys can be cause by mulitple factors: 7 | 1. Pefect solution is favored over shipping and learning 8 | 2. No agreed directly responsible individual who can break ties 9 | 3. No one wants to say no and stay polite 10 | 4. People with different levels of experise get the same voice 11 | 5. The goals are not clear 12 | 6. Bikeshedding (the tendency to spend a lot of time on trivial details) 13 | 14 | ## Solutions 15 | 16 | ### Define the decision process beforehand 17 | 18 | 1. What is the goal? 19 | 2. Who makes the decision? 20 | 3. When do we want to make a decision? 21 | 4. Consensus vs consent 22 | 23 | ### Identify the leader 24 | 25 | Depending on the decision, some are harder to make than others, require taking responsibility or deep experise. Anticipate decision paralysis and identify the leader beforehand. -------------------------------------------------------------------------------- /Content/notes/Good Metrics.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Metrics 3 | excerpt: Project Management 4 | --- 5 | 6 | Metrics can aid in making better decisions, but it's important to use established frameworks and be cautious. Keep in mind that metrics can only capture reality and do not explain why users behave a certain way or what actions to take. 7 | 8 | > Any observed statistical regularity will tend to collapse once pressure is placed upon it for control purposes. 9 | > When a measure becomes a target, it ceases to be a good measure. – Goodhart’s law 10 | 11 | If you overvalue the data you are collecting, which will tend to be the easiest, you are likely chasing false positives about what that data is or what it means. 12 | 13 | Be data informed, where you use data to inform your thinking, rather than data-driven, where you use data without questioning it or recognizing its limitations. 14 | 15 | ## Top down 16 | 17 | Focus on the business goals, the metrics should derive from the top. 18 | 19 | ## Practical tips 20 | 21 | - Use guardrails: business metrics designed to indirectly measure business value and provide alerts about any potentially misleading or erroneous results and analysis 22 | - Iterate on metrics 23 | - Making too many changes at the same time 24 | - Using metrics that are in your control 25 | 26 | As example, to lose weight focus on calories/day and workouts/week, not on weight. 27 | 28 | ## Templates 29 | 30 | - [HEART](https://www.productplan.com/glossary/heart-framework/#:~:text=The%20HEART%20framework%20is%20a,to%20five%20user%2Dcentered%20metrics.): Happiness, Engagement, Adoption, Task Success 31 | - [AARRR](https://500hats.typepad.com/500blogs/2007/06/internet-market.html) -------------------------------------------------------------------------------- /Content/notes/K-nearest neighbors.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: k-nearest neighbors 3 | excerpt: Algorithms 4 | --- 5 | 6 | k-nearest neighbors (KNN) algorithm is used for classification. 7 | 8 | ## Feature extraction 9 | 10 | To classify a set of values and find k-nearest neighbors we first need to find some features (like size or color). 11 | 12 | No matter how many features there are, we can calculate the distance by applying formula: **sqrt((a1-a2)^2 + (b1-b2)^2 + (c1-c2)^2 ... + (h1-h2)^2 )**. For a more nuanced result that takes into account how the user rates everything in general **Cosine similarity** is used to find closest neighbors. 13 | 14 | ## Classification 15 | 16 | Categorization into a group. 17 | 18 | ## Regression 19 | 20 | Prediction of a response. 21 | 22 | ## Examples 23 | 24 | ### Optical Character Recognition 25 | 26 | How do understand a text from a photo? One of the ways is to use the KNN algorithm and analyzes different features of the characters (curves, lines). -------------------------------------------------------------------------------- /Content/notes/Linked Lists.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Linked Lists 3 | excerpt: Data Structures 4 | --- 5 | 6 | In a linked list, each node points to the next node in the linked list. In a doubly-linked-list, each node also points to the previous node. 7 | 8 | The benefit of a linked list is that items are added and removed in constant time. 9 | 10 | ## The Runner Technique 11 | 12 | Iterate through the linked list with two pointers simultaneously, one going faster than the other. 13 | 14 | ## Recursion 15 | 16 | Many linked list problems are solved with recursion. The only caveat is that it takes at least O(n) space. 17 | 18 | 19 | ## Example tasks to know how to solve: 20 | 21 | ### Remove nth element from the end 22 | 23 | We could use the 2 runner technique to solve this issue. We can have one pointer always nth the elements behind it. When the first pointer reaches the end, we have a second pointer point to the nth element from the end that we need to remove. 24 | 25 | ### Partition a linked list by value 26 | 27 | It could be done by creating 2 linked lists one with values larger than the given value and the other one with smaller values and in the end, merging those lists. 28 | 29 | ### Check if singly-linked-list values construct a palindrome 30 | 31 | To do this in place with O(1) space complexity we need to work directly on the list. 32 | 33 | - Using the runner technique: fast and slow pointers. When the fast reaches the end, the slow reaches the middle 34 | - Reverse the linked list from the middle 35 | - Compare values one by one, from the start and the middle 36 | 37 | ### Find the intersection of two linked lists 38 | 39 | - A medium solution would be to put nodes into a hashtable and compare 40 | - The best solution is to calculate the lengths of two linked lists and then compare the nodes at the same starting point 41 | 42 | Here's a clever way to find an intersection. The trick is to set the value of one of the current nodes to the head of the other list when the end is reached: 43 | 44 | ```swift 45 | func getIntersectionNode(_ headA: ListNode?, _ headB: ListNode?) -> ListNode? { 46 | var currentA = headA 47 | var currentB = headB 48 | 49 | while currentA !== currentB { 50 | currentA = currentA == nil ? headB : currentA?.next 51 | currentB = currentB == nil ? headA : currentB?.next 52 | } 53 | 54 | return currentA 55 | } 56 | ``` 57 | 58 | ### Detecting a loop in a linked list 59 | 60 | - A medium solution putting nodes into a hashtable (set). Have in mind that in Swift nodes have to be `Hashable` or simply wrapped in the `ObjectIdentifier` so we would compare references 61 | - The best solution is to detect a loop using the runner technique. If there's a loop, they will eventually meet. The harder part to understand is finding **the start of the loop**. It will be exactly between the *head* and the *collision* point. Therefore going step by step from the *head* and the *collision* the next collision will happen at *the start of the loop*. 62 | 63 | ```swift 64 | func colissionNode(_ head: ListNode?) -> ListNode? { 65 | var slow = head 66 | var fast = head 67 | 68 | while fast?.next != nil { 69 | slow = slow?.next 70 | fast = fast?.next?.next 71 | 72 | if slow === fast { 73 | return slow 74 | } 75 | } 76 | 77 | return nil 78 | } 79 | ``` 80 | 81 | If we do the math we can see that F = b, therefore going step by step from the start and from the point h we will reach the start of the loop: 82 | ![LeetCode.com](/images/notes/67ea9a4463080be07ce89fc92ba437d53482bdce56217f6ff1ffe17e021bf200.png) 83 | 84 | ### Merge two sorted lists 85 | 86 | We can do that recursively and iteratively. By doing it iteratively we save space and have constant space complexity. 87 | 88 | The algorithm relies on 3 concepts: 89 | - Creating a prehead, that we use as a beginning of our merged list 90 | - Keeping the previous pointer, that allows merging step by step 91 | - In the end, connect to a non-merged part of a list. It can happen when lists are not of the same size. 92 | 93 | ```swift 94 | // Time Complexity O(n+m) 95 | // Space Complexity O(1) 96 | func mergeTwoLists(_ list1: ListNode?, _ list2: ListNode?) -> ListNode? { 97 | guard let list1 = list1 else { return list2 } 98 | guard let list2 = list2 else { return list1 } 99 | 100 | var list1Ptr: ListNode? = list1 101 | var list2Ptr: ListNode? = list2 102 | var previousPtr: ListNode? 103 | var prehead: ListNode? = ListNode(-1) 104 | 105 | previousPtr = prehead 106 | 107 | while list1Ptr != nil, list2Ptr != nil { 108 | if list1Ptr!.val <= list2Ptr!.val { 109 | previousPtr?.next = list1Ptr 110 | list1Ptr = list1Ptr?.next 111 | } else { 112 | previousPtr?.next = list2Ptr 113 | list2Ptr = list2Ptr?.next 114 | } 115 | 116 | previousPtr = previousPtr?.next 117 | } 118 | 119 | previousPtr?.next = list1Ptr == nil ? list2Ptr : list1Ptr 120 | 121 | return prehead?.next 122 | } 123 | ``` -------------------------------------------------------------------------------- /Content/notes/Math and Logic Puzzles.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Math and Logic Puzzles 3 | excerpt: Algorithms 4 | --- 5 | 6 | ## Popular tasks 7 | 8 | ### Generate a list of prime numbers 9 | 10 | ```swift 11 | // The Sieve of Eeratosthenes is a way to generate a list of primes by recognizing that all non-prime numbers are divisible by a prime number 12 | 13 | // The idea is to cross of numbers that are divisible by the next available prime 14 | 15 | // Example: 13 16 | 17 | // We cross of powers of 2: 4, 6, 8, 10, 12 18 | // Then cross of powers of 3: 9, 12 19 | // We do that until the prime we pass is less than or equal to the square root of the max number 20 | 21 | // We can optimize by only dealing with odd numbers 22 | 23 | func countPrimes(_ n: Int) -> Int { 24 | guard n >= 2 else { return 0 } 25 | 26 | var flags: [Bool] = Array(repeating: true, count: n) 27 | flags[0] = false 28 | flags[1] = false 29 | 30 | var prime = 2 31 | 32 | while prime <= Int(Double(n).squareRoot()) { 33 | crossOff(flags: &flags, prime: prime) 34 | 35 | prime = getNextPrime(flags: flags, prime: prime) 36 | } 37 | 38 | return flags 39 | .filter { $0 } 40 | .count 41 | } 42 | 43 | private func crossOff(flags: inout [Bool], prime: Int) { 44 | for i in stride(from: prime * prime, to: flags.count, by: prime) { 45 | flags[i] = false 46 | } 47 | } 48 | 49 | private func getNextPrime(flags: [Bool], prime: Int) -> Int { 50 | var next = prime + 1 51 | 52 | while next < flags.count && !flags[next] { 53 | next += 1 54 | } 55 | 56 | return next 57 | } 58 | ``` -------------------------------------------------------------------------------- /Content/notes/Object Oriented Design.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Object-Oriented Design 3 | excerpt: Architecture 4 | --- 5 | 6 | When designing a system it's important to know how to: 7 | 8 | 1. Handle Ambiguity. Ask questions about who, what, where, when, who, and why to design a system for a clear purpose. 9 | 2. Define the Core Objects (Person, Table, Meal, etc) 10 | 3. Define Relationships 11 | 4. Investigate Actions -------------------------------------------------------------------------------- /Content/notes/Practical Deep Learning.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Practical Deep Learning 3 | excerpt: AI 4 | --- 5 | 6 | ## Lesson 1 7 | 8 | [Source - course.fast.ai](https://course.fast.ai/Lessons/lesson1.html) 9 | 10 | To do image recognition before neural networks there was a lot of manual work involved by doing feature engineering. Neural networks are able to learn features automatically. For example, features that recognize corners, or features that recognize gradients. Going deeper into the layers, features become more complex and sophisticated. You start with a random neural network, feed it examples, and it will create features by itself. 11 | 12 | ### Myth 13 | 14 | Deep learning requires lots of math, data, and expensive computers. 15 | 16 | ### Truth 17 | 18 | High school math is sufficient, sometimes <50 items of data is enough to get record-breaking results, and usually you get what you need on laptop. 19 | 20 | ### Tools 21 | 22 | [Kaggle](https://www.kaggle.com/) is community platform for data scientists. In the scope of the course, it is used to share notebooks. [Jupyter](https://jupyter.org/) is a notebook interface used for the service. 23 | 24 | ### Comparison 25 | 26 | #### Traditional programming 27 | 28 | **Inputs -> Program -> Results** 29 | 30 | #### Deep learning 31 | 32 | **Inputs + Weights -> Model -> Result**s 33 | 34 | Model is mathematical function that takes inputs and multiplies them by one set of weights and adds them up, then it does the same with the second set of weights and adds them up again. Then it takes all the negative numbers and replaces them with zeros. And then it takes those as inputs to another layer. That is neural network. 35 | 36 | At first weights are random so model doesn't do anything useful. Therefore, when we get the result we evaluate how correct they are and then we update the weights. We do this many times until we get the result we want. Model in the end is a very flexible function. 37 | 38 | Once we got the trained model, then we can use it just as a regular program. 39 | 40 | **Inputs -> Model -> Results** -------------------------------------------------------------------------------- /Content/notes/Product.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Product Thinking 3 | excerpt: Project Management 4 | --- 5 | 6 | ## General 7 | 8 | Product thinking is a set of skills that help you to build products that people want to use. 9 | 10 | - Customer research 11 | - Product management 12 | - User experience design 13 | - Project management 14 | 15 | ### Product management 16 | 17 | Product management is at its core the process of thinking about how the whole product fits together for customers and business. 18 | 19 | #### Four connective skills of product managers 20 | 21 | When you are a product manager, you need to be able to excel at four connective skills, otherwise the projects can get in trouble. 22 | 23 | - Communicate effectively within the team and with stakeholders 24 | - Organize the product team 25 | - Research the market 26 | - Execute and lead daily work 27 | 28 | ### Problems 29 | 30 | #### Are you solving the right problem? 31 | 32 | This is a complex problem that requires a lot of research and thinking. You need to understand the problem and the context in which it occurs. 33 | 34 | Usually it's a combination of customer research ([product discovery](https://href.li/?https://www.productplan.com/glossary/product-discovery/)) and iterative design and engineering processes. Some of the well known approaches including over a dozen user [research methods](https://href.li/?https://www.toptal.com/designers/user-research/guide-to-ux-research-methods), [design sprints](https://href.li/?https://www.gv.com/sprint/), [design thinking](https://href.li/?https://designthinking.ideo.com/), and etc. 35 | 36 | It's important to understand that any of these methods take time, skill and offer guidance, not a clear answer. You need to be able to make decisions and take risks. The goal is to raise probability of success, not to guarantee it. 37 | 38 | ### Prioritization 39 | 40 | One needs to be careful when respoding to user feature requests and have in mind that only the people who are capable of reaching out to you are making requests. There're segments of people who cannot or won't make feature requests and we need to understand which users are not well represented. 41 | 42 | Use feature requests to investigate gaps in the product. Do not act on them directly. Use methods such as [5 whys method](https://href.li/?https://en.wikipedia.org/wiki/Five_whys) to truly understand the issue. 43 | 44 | > People don't want to buy a quarter-inch drill. They want a quarter-inch hole. 45 | 46 | #### Formula 47 | 48 | Before starting the work on any feature request, make sure you can formulate this sentence: 49 | 50 | > If we **add feature X** it **solves problem Y** for **customer group Z** which helps with **roadmap goal V** by **increasing value by Q**. 51 | 52 | ### Build trap 53 | 54 | > “The build trap: companies end up in the build trap when they misunderstand value. Instead of associating value with the outcomes they want to create for their businesses and customers, they measure value by the number of things they produce… most companies I encounter are stuck in output mode, and their entire organization is optimized to increase the output. Their processes are driven by deadlines and by checking off as many features on a list as possible. Teams are rewarded and incentivized to build more.” 55 | 56 | This is a problem that engineering led cultures and tech projects suffer from eventually. The symptoms are building first and figuring out the value later, seeing user research, roadmapping, and business strategy as a waste of time. Sometimes it happens because organizations default to measuring sucess by what's easy to measure, such as number of features shipped. 57 | 58 | #### Product Kata 59 | 60 | [Product Kata is a set of steps that help you to build a product that people want to use:](https://melissaperri.com/blog/2015/07/22/the-product-kata) 61 | 62 | 1. Company Goal, Producct KPI, future state 63 | 2. What are users doing now? 64 | 3. What's the first little goal? 65 | 4. User Research, Product Experiments 66 | 67 | > A great product somehow manages to make something made by 10, 100, or 1000 people feel like it was made by one person who was brilliant, thoughtful and consistent in all the right ways. Good movies and music does it. So do great cities. -------------------------------------------------------------------------------- /Content/notes/Searching.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Searching 3 | excerpt: Algorithms 4 | --- 5 | 6 | ## Binary Search 7 | 8 | In binary search, we look for an element in a sorted array by comparing x to the middle of the array. If x is less we search on the left, if x is more we search on the right. We repeat until we find the x, or there are no more partitions we can make. 9 | 10 | ```swift 11 | func binarySearch(_ array: [Int], _ x: Int) -> Int? { 12 | var low = 0 13 | var high = array.count - 1 14 | var mid = 0 15 | 16 | while low <= high { 17 | mid = low + high / 2 18 | 19 | if array[mid] > x { 20 | high = mid - 1 21 | } else if array[mid] < { 22 | low = mid + 1 23 | } else { 24 | return mid 25 | } 26 | 27 | return nil 28 | } 29 | } 30 | ``` 31 | 32 | ## Quick Select 33 | 34 | Time: average and best - O(n), worst - O(n^2). Space - O(1). 35 | 36 | Used to find the k or kth smallest/largest elements. It is a deviation of a quick sort. 37 | 38 | 1. Pick a pivot (for example mid element) 39 | 2. Add smaller elements to **less** array, increase index **p** every time we find a smaller element 40 | 3. Put the pivot into **p** position 41 | 4. We will have *less* array, pivot and *greater* array 42 | 5. What we know at this point is that an element in **p** position is the pth largest value 43 | 6. If we need to find k smallest values, if k == p, all the elements in **less** array are the smallest values -------------------------------------------------------------------------------- /Content/notes/Stacks and Queues.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Stacks and Queues 3 | excerpt: Data Structures 4 | --- 5 | 6 | ## Stack 7 | 8 | A stack has LIFO ordering. Main operations: 9 | 10 | * pop() - remove the top element 11 | * push(_) - add an item to the top 12 | * peek() - look at the top element 13 | * isEmpty() - true if there're no elements 14 | 15 | ### Usage 16 | * Recursive algorithms 17 | 18 | ## Queue 19 | 20 | A queue has FIFO ordering. Main operations: 21 | 22 | * add(_) - aedd an item to the bottom 23 | * remove() - remove the top element 24 | * peek() - look at the top element 25 | * isEmpty() - true if there're no elements 26 | 27 | ### Usage 28 | * Breadth-first-search 29 | * Implementing a cache 30 | 31 | ## Time complexity 32 | 33 | * O(n) for accessing nth item 34 | * O(1) for adding and removing an item 35 | 36 | ## Example tasks to know how to solve: 37 | 38 | ### Min Stack 39 | 40 | A stack that also can get a minimum value. 41 | 42 | The trick here is to understand that minimum value only changes if the new smaller stack element is added. If this element is removed, we need to come back to an old minimum value. To achieve this we need to save a current min value with each *Node*. As it's a LIFO data structure we sort of have a timeline of minimum values. 43 | 44 | ### Implement Queue using 2 Stacks 45 | 46 | * Since the queue is FIFO and stack is LIFO we can reverse element order by moving elements from one stack to another. Doing it every push operation produces a time complexity of O(n) 47 | * We can do an *amortized* solution with having *old* and *new* stack. Only if the *old* (reversed) element stack is empty, we shift elements from *new* to *old*. This makes the average scenario much more effective than the worst-case scenario. 48 | 49 | ### Stack supporting different types 50 | 51 | If the stack needs to support *popAnyType()*, *popTypeA()* and *popTypeB()* the best solution is to have separate stacks for both typeA and typeB and save a timestamp next to the nodes. When we do *popAnyType()* we can check which stack has the oldest element on top and return that. -------------------------------------------------------------------------------- /Content/notes/Strategic Thinking.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Strategic Thinking 3 | excerpt: Project Management 4 | --- 5 | 6 | Dorie Clark (teaches for Duke University's Fuqua School of Business, and is the author of "Reinventing You," and "Stand Out." Writes frequently for the Harvard Business Review) 7 | 8 | *"Strategic thinking is the ability to think on a big and small scale, long and short term, and into the past and the present. While strategic thinking is a valuable skill for everyone in an organization, it becomes increasingly essential as you ascend the ladder."* 9 | 10 | ### Great vs average strategic thinker 11 | 12 | The difference is the ability to do that under pressure. Train yourself and your team to pause at the right moments. 13 | 14 | ## 5 strategic checks 15 | 16 | ## Gap Check 17 | 18 | Put numbers on it (current vs. goal). 19 | 20 | “What’s the gap between the current state and the desired state? How can we make it measurable?” 21 | 22 | Gap analysis in strategic thinking involves evaluating the current state of a situation against a desired future state to identify discrepancies or "gaps." This allows organizations to focus their resources on bridging these gaps through targeted actions. 23 | 24 | **Lead Indicators**: Predict future outcomes. For, customer inquiries can indicate future sales. 25 | 26 | LEADING INDICATOR QUESTIONS 27 | * What processes can I employ to achieve this goal to higher levels of success? 28 | * What skills can the team improve to better achieve the desired outcome? 29 | * What steps can be taken to speed up product development or process improvement? 30 | 31 | **Lag Indicators:** Measure past performance. E.g., quarterly revenue reflects past actions. 32 | 33 | ## Lens Check 34 | 35 | Diagnose using the 3 Lenses Model. 36 | 37 | A "lens check" usually refers to examining a situation, strategy, or issue from various perspectives to gain a comprehensive understanding. The term can be metaphorical, representing different viewpoints like financial, ethical, or customer-focused lenses. 38 | 39 | Lens check helps give feedback. 40 | 41 | ### 3 Lenses Model 42 | 43 | For example, there's an issue in filling a role in a company. 44 | 45 | - Person issue, Is it skill or will issue? 46 | - Manager issue, expectation, feedback, accountability issue? 47 | - Organizational issue, Is it a value, role models, systems, or constraints issue? 48 | 49 | ## Link Up Check 50 | 51 | Confirm alignment and effectiveness. 52 | 53 | Pick any task you or your team are working on and link it up to the end game. Ask: “What does this link up to?” Double-check for alignment, and effectiveness, and increase motivation by understanding how daily work connects to the big picture. 54 | 55 | ## UC (Unintended consequences) Check 56 | 57 | Mitigate unintended consequences. 58 | 59 | Deliberate risk management. 60 | 61 | Great strategic thinkers think long-term. Help yourself and others do this by asking, “What unintended consequences do we need to look out for?” and “What might cause this plan to fail?” 62 | 63 | Premortem: 64 | - What might cause this project to fail? 65 | 66 | ## Inclusive Planning Check 67 | 68 | Involve the right people at the right time. 69 | 70 | Biggest predictor of strategic failure? Not involving the right people at the right time. 71 | 72 | Take time to map out a project and make sure you are including the right people at the right time. 73 | 74 | # Resources 75 | 76 | How to Measure Anything: Finding the Value of Intangibles in Business 77 | 78 | Measure What Matters: How Google, Bono, and the Gates Foundation Rock the World with OKRs 79 | 80 | Dorie Clark, LinkedIn Learning, Strategic Thinking -------------------------------------------------------------------------------- /Content/notes/Strategy vs Planning.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Strategy vs Planning 3 | excerpt: Project Management 4 | --- 5 | 6 | ## Strategy 7 | 8 | Strategy is an integrative set of choices that positions you on a playing field of your choice in a way that you win. 9 | 10 | Strategy answers why we are on this particular playing field, and how on that playing field we're going to be better than anyone else. A strategic theory mus be coherent and doable. 11 | 12 | - Actual customers are your customers 13 | - You don't control customers 14 | - You don't control revenues 15 | - Uncertain, uncomfortable 16 | 17 | ## Planning 18 | 19 | Planning is the process of thinking regarding the activities required to achieve a desired goal. 20 | 21 | - You control costs 22 | - You are the customer 23 | - Comfortable 24 | 25 | ## Example 26 | 27 | While all the established airlines are busy **planning** their routes, the new upcoming airlines create a **strategy** to disrupt the market by having only shorthaul flights, use the same aircraft for all the routes, and optimize costs, eventually becoming a number one airline. 28 | 29 | ## Planning trap 30 | 31 | Planning can be a comfortable excercise were you can lay down all the steps and predict the outcomes. However, it may not help make significant improvements or change. 32 | 33 | Strategy requires to take risks and accept uncertainty. *If our theory is right about what we can do, and how the market will react, will position ourselves in a great way*. When strategizing, lay down the logic what assumptions need to be true in order for the strategy to work. Observe if those assumptions are true, and if they are not, tweak the strategy. 34 | 35 | Keep the strategy short and clear. 36 | 37 | > Not knowing for sure isn't a bad management. It's great leadership -------------------------------------------------------------------------------- /Content/notes/Strategy.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: A problem-solving flow 3 | excerpt: Interviewing 4 | --- 5 | 6 | ## A problem-solving flow 7 | 8 | 1. Listen and clarify the question. Write down the important bits of information. 9 | 2. Go through the examples and create your own example. Draw if possible. 10 | 3. State a brute-force solution and its time & space complexities 11 | 4. Optimize 12 | 1. Look for bottlenecks, unnecessary work, and duplicated work 13 | 2. Maybe there are unused bits of information from the description? 14 | 3. Try going through the solution with different examples 15 | 4. Try to solve with simplest example and make it bit by bit more complex 16 | 5. Make time vs space tradeoff 17 | 6. Computing some values (like sorting) upfront 18 | 7. Brainstorm all the possible data structures 19 | 8. Think about the best possible runtime and then how to achieve it 20 | 5. Walkthrough the approach in detail 21 | 6. Implement keeping coding standards in mind 22 | 7. Test 23 | 1. Code review 24 | 2. Small test cases 25 | 3. Special cases and edge cases -------------------------------------------------------------------------------- /Content/notes/Strings.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: String manipulation 3 | excerpt: Algorithms 4 | --- 5 | 6 | ## Example problem 7 | 8 | ### Longest Substring Without Repeating Characters 9 | 10 | The **sliding window** approach is most intuitive. We should aim for O(n) time complexity and constant space complexity if the charset is made only from ASCII characters. 11 | 12 | 1. Remember used letters 13 | 2. When the right side of the window encounters the letter that is already used, move the left side of the window to the position after the first occurrence of that letter 14 | 3. The longest substring is the largest distance between the left and the right side of the windows 15 | 16 | ### Longest Repeating Character Replacement 17 | 18 | What is the longest substring with repeating letters, allowing *k* replacements. 19 | 20 | To solve the problem we need to think about *k* replacements as *allowed mistakes* inside a string. 21 | 22 | We can use the same **sliding window** approach. However, we increase *start index* when there are more mistakes than allowed. 23 | 24 | ```swift 25 | func characterReplacement(_ s: String, _ k: Int) -> Int { 26 | var startIndex = 0 27 | var letters = Array(s) 28 | var letterCount = Array(repeating: 0, count: 26) 29 | var longestSubstring = 0 30 | var maxCount = 0 31 | 32 | for (index, letter) in letters.enumerated() { 33 | maxCount = max(maxCount, (letterCount[position(for: letter)] + 1)) 34 | letterCount[position(for: letter)] += 1 35 | 36 | while mistakes(from: startIndex, to: index, max: maxCount) > k { 37 | letterCount[position(for: letters[startIndex])] -= 1 38 | startIndex += 1 39 | } 40 | 41 | longestSubstring = max(longestSubstring, index - startIndex + 1) 42 | } 43 | 44 | return longestSubstring 45 | } 46 | 47 | private func mistakes(from startIndex: Int, to endIndex: Int, max: Int) -> Int { 48 | return endIndex - startIndex + 1 - max 49 | } 50 | 51 | private func position(for letter: Character) -> Int { 52 | return Int(letter.asciiValue! - Character("A").asciiValue!) 53 | } 54 | ``` -------------------------------------------------------------------------------- /Content/notes/System Design and Scalability.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: System Design and Scalability 3 | excerpt: Architecture 4 | --- -------------------------------------------------------------------------------- /Content/notes/Useful Algorithms.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Useful algorithms and data structures 3 | excerpt: Algorithms 4 | --- 5 | 6 | ## The Fourier transform 7 | 8 | - Separate a song into its frequences 9 | - Compress songs and images 10 | - Earthquake prediction 11 | - DNA analysis 12 | 13 | ## Searching, inserting, deleting 14 | 15 | - B-trees 16 | - Red-black trees 17 | - Heaps 18 | - Splay trees 19 | 20 | ## Search Engines 21 | 22 | - Inverted indexes 23 | 24 | ## Parallel algorithms 25 | 26 | - MapReduce (Using it through Apache Hadoop) 27 | 28 | ## Bloom filters and HyperLogLog 29 | 30 | They are used when fast access is needed to a large set of data and hash tables would be just too large. 31 | 32 | - Bloom filters give a probabilistic answer but they take up very little space compared to a hash table 33 | - HyperLogLog approximates the number of unique elements in a set. It doesn't give an exact answer but it takes only a fraction of the memory. 34 | 35 | ## The SHA algorithms 36 | 37 | ### Simhash 38 | 39 | A locality-sensitive hash. Similar values give similar hashes. Used by Google to detect duplicates while crawling the web, it could be used to check if a student was copying an essay from the web or check for copyrighted content. 40 | 41 | ### Diffie-Hellman key exchange 42 | 43 | Allows encrypting a message so it can only be read by the person you sent the message to. 44 | 45 | It uses two keys: public and private. The message is encrypted by a public key but only a private key can decrypt it. 46 | 47 | RSA is a successor of this algorithm. 48 | 49 | ### Linear programming 50 | 51 | Linear programming is used to maximize a result given some constraints. It uses **Simplex** algorithm. All graph problems are just a subset of linear programming. -------------------------------------------------------------------------------- /Content/notes/iOS AV.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Audio & Video 3 | excerpt: iOS 4 | --- 5 | 6 | AVFoundation uses the AVAsset class to progressively download from a remote host, and stream-based media that a host serves using *HTTP Live Streaming*. 7 | 8 | AVFoundation is a wrapper around CoreAudio, CoreMedia, CoreVideo and CoreAnimation. 9 | 10 | Main features: 11 | 1. Inspect 12 | 2. Playback 13 | 3. Export 14 | 4. Capture 15 | 5. Compose 16 | 17 | ## Loading 18 | 19 | `AVAsset` models the static aspects of a media resource. Creating an `AVAsset` does not load the resource, media is not loaded until prompted. 20 | 21 | Asset inspection is also an asynchronous process. We only get what we ask for. 22 | 23 | We load values by providing keys to a loading method. 24 | 25 | ```swift 26 | let url: URL = // A URL to a local or remote media resource. 27 | let asset = AVAsset(url: url) 28 | // Load the value of the asset's duration property asynchronously. 29 | asset.loadValuesAsynchronously(forKeys: ["duration"]) { 30 | var error: NSError? 31 | if asset.statusOfValue(forKey: "duration", error: &error) == .loaded { 32 | // Access the property value synchronously. 33 | presentDuration(asset.duration) // If we call asset.duration before loading, it would block I/O! 34 | } 35 | } 36 | ``` 37 | 38 | Swift 5.5 way. Old way will be deprrecated. 39 | ```swift 40 | func inspectAsset() async throws { 41 | let asset = AVAsset(url: movieURL) 42 | let duration = try await asset.load(.duration) 43 | myFunction(thatUses: duration) 44 | } 45 | 46 | func inspectAsset() async throws { 47 | let asset = AVAsset(url: movieURL) 48 | let (duration, tracks) = try await asset.load(.duration, .tracks) 49 | myFunction(thatUses: duration, and: tracks) 50 | } 51 | ``` 52 | 53 | ![Apple.com](/images/notes/1bccd220960e2615c1c6b0933efea56e88b83393de2c8d325a749f8d37b9e4f6.png) 54 | 55 | 56 | We can export and save files using similar`exportAsynchronouslyWithCompletionHandler`. 57 | 58 | AVFoundation distinguishes between static and dynamic aspects of media: 59 | 1. Static: AVAsset, AVAssetTrack... 60 | 2. Dynamic: AVplayerItem, AVPlayerItemTrack... 61 | 62 | ## Media Playback with AVKit 63 | 64 | `AVKit` is built on top of `AVFoundation`. Allows to reuse intuitive Apple UI, with `AVPlayerViewController` and `AVRoutePickerView`. 65 | 66 | ```swift 67 | import AVKit 68 | 69 | let player = AVPlayer(url: "https://stream.com/video.m3u3") 70 | 71 | let playerViewController = AVPlayerViewController() 72 | playerViewController.player = player 73 | 74 | present(...) 75 | ``` 76 | 77 | ## Time 78 | 79 | Time is presented by `CMTime` or `CMTimeRange` (containing start and end times). 80 | 81 | ## HTTP Live Streaming 82 | 83 | ![picture 3](/images/notes/92fd3d4ecd5caee3c6cc2980d0918499ff0b5588294b07575264314b0f8e47ca.png) 84 | 85 | https://developer.apple.com/streaming/ 86 | 87 | HLS consists of 3 parts: 88 | 1. Server (resposible for encoding, encapsulating in a format suitable for delivery and distribution) 89 | 2. Distribution (web-server or web-caching system that delivers media files or index files over HTTP)/ 90 | 3. Client (begings by fetching the index file, using a URL that identifies the stream) 91 | 92 | AVAssetVariant: 93 | - Bitrate (32.91Mbps) 94 | - Audio attributes (ec-3, channels) 95 | - Video attributes (dvh1, resolution, fps) 96 | 97 | HLS downloads: 98 | - Introduced in 2016 99 | 100 | Streaming tools: 101 | - https://developer.apple.com/documentation/http_live_streaming/using_apple_s_http_live_streaming_hls_tools -------------------------------------------------------------------------------- /Content/notes/iOS Background Tasks.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Background Tasks 3 | excerpt: iOS 4 | --- 5 | 6 | https://developer.apple.com/documentation/backgroundtasks/choosing_background_strategies_for_your_app 7 | 8 | ## Factors affecting runtime 9 | 10 | 1. Critically low batter 11 | 2. Low Power Mode 12 | 3. App usage (AI learns about app usage) 13 | 4. App switcher (if user explicitly kills specific app) 14 | 5. Background App Refresh switch (there's notification to know when switch is changed) 15 | 6. System budgets (every app has a system defined budget) 16 | 7. Rate limiting 17 | 18 | ## Background App Refresh tasks 19 | 20 | ## Background pushes 21 | 22 | Background pushes silently wakes up the app without displaying any alert or playing the sound. 23 | 24 | Once the system delivers the remote notification with application`(_:didReceiveRemoteNotification:fetchCompletionHandler:)`, the app has up to 30 seconds to complete its work. One your app performs the work, call the passed completion handler as soon as possible to conserve power. 25 | 26 | ## URLSession background transfers 27 | 28 | ```swift 29 | 30 | private lazy var urlSession: URLSession = { 31 | let config = URLSessionConfiguration.background(withIdentifier: "MySession") 32 | config.isDiscretionary = true // System waits for optimal conditions to perform the transfer 33 | config.sessionSendsLaunchEvents = true // System wakes up the app when the ask completes and the app is in the background 34 | return URLSession(configuration: config, delegate: self, delegateQueue: nil) 35 | }() 36 | 37 | // System calls this method when the download finishes 38 | // Store the completion handler to call later 39 | func application(_ application: UIApplication, 40 | handleEventsForBackgroundURLSession identifier: String, 41 | completionHandler: @escaping () -> Void) { 42 | backgroundCompletionHandler = completionHandler 43 | } 44 | 45 | func urlSessionDidFinishEvents(forBackgroundURLSession session: URLSession) { 46 | DispatchQueue.main.async { 47 | guard let appDelegate = UIApplication.shared.delegate as? AppDelegate, 48 | let backgroundCompletionHandler = 49 | appDelegate.backgroundCompletionHandler else { 50 | return 51 | } 52 | backgroundCompletionHandler() 53 | } 54 | } 55 | ``` 56 | 57 | ## Notify the user about a background task 58 | 59 | If your app needs to perform a task in the background and show a notification to the user, use a Notification Service Extension. For example, an email app might need to notify a user after downloading a new email. Subclass `UNNotificationServiceExtension` and bundle the system extension with your app. Upon receiving a push notification, your service extension wakes up and obtains background runtime through didReceive(_:withContentHandler:). 60 | When your extension completes its work, it must call the content handler with the content you want to deliver to the user. Your extension has a limited amount of time to modify the content and execute the contentHandler block. 61 | 62 | ## Background processing tasks 63 | 64 | To preserve battery life and performance, you can schedule backgrounds tasks for periods of low activity, such as overnight when the device charges. Use this approach when your app manages heavy workloads, such as training machine learning models or performing database maintenance. 65 | Schedule these types of background tasks using `BGProcessingTask`, and the system decides the best time to launch your background task. -------------------------------------------------------------------------------- /Content/notes/notes.code-workspace: -------------------------------------------------------------------------------- 1 | { 2 | "folders": [ 3 | { 4 | "path": "../.." 5 | }, 6 | { 7 | "path": "." 8 | } 9 | ], 10 | "settings": {} 11 | } -------------------------------------------------------------------------------- /Content/posts/2019-03-11-aerogami_series_part_1.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Building a real-world iOS app (Part 1): Introduction 3 | date: 2019-03-11 12:00 4 | tags: Tutorial, iOS, Swift 5 | excerpt: We'll be creating and releasing an iOS application by showing a real thinking process, going through essential steps and providing the motivation behind them. 6 | --- 7 | 8 | When learning any new technology I find it beneficial to follow a real world example. In this tutorial series we'll be creating and releasing an iOS application. The application will be created by showing a real thinking process, going through essential steps and providing the motivation behind them. Although every single line of code won't be covered, all of it will be always available on [GitHub](https://github.com/staskus/aerogami-ios). 9 | 10 | ## Prerequisites 11 | 12 | Prior knowledge of iOS development and Swift syntax is needed. 13 | 14 | ## Introduction 15 | 16 | ### Our Project 17 | 18 | We'll be creating a flight discovery application. The users of our application should be able to: 19 | 20 | 1. See the _feed_ of _flights_ 21 | 2. See the _date_, _price_, _origin_ and _destination_ of each _flight_ 22 | 3. Book the _flight_. 23 | 24 | In the scope of this project we won't be concerned about the source of information. Our application will use mocked flight information data. However, the structure of the application will support an easy integration with any Rest API. 25 | 26 | ### Our Approach 27 | 28 | Throughout the series we'll cover these topics one-by-one: 29 | 30 | 1. Data Fetching and Parsing 31 | 2. Testing 32 | 3. Code Separation into Frameworks 33 | 4. Design using Sketch 34 | 5. Clean Swift Architecture 35 | 6. Building the UI and Displaying the Data 36 | 7. Release Process 37 | 38 | ### The Final Product 39 | 40 | Here is the sneak peek of how the final product will look like. The full codebase can be found on [GitHub](https://github.com/staskus/aerogami-ios). 41 | 42 | Application Screenshot 43 | 44 | ## High Level View 45 | 46 | Before we start, it's beneficial to understand how we're going to approach the creation of this application. 47 | 48 | ### Separation of Concerns 49 | 50 | Essentially our application should be able to perform 3 main tasks: 51 | 52 | 1. Fetch data 53 | 2. Parse data 54 | 3. Display data 55 | 56 | We'll separate these different concerns into frameworks for our code to be decoupled and flexible. The primitive diagram of the architecture is displayed in the picture bellow. We'll define data models and protocols in `TravelKit`. This framework will contain data fetching protocols, which will be implemented in `TravelDataKit`. DataKit, as its name suggests, will be used for fetching, persisting and providing data. User interface will only know about data models and protocols and won't be concerned about the implementation. We'll call this framework `TravelFeatureKit`. The entry point of our application will initialize the dependencies required for all the frameworks and present the root view described in `TravelFeatureKit`. 57 | 58 | Application Architecture 59 | 60 | In the next part of the series we'll continue by explaining how to create frameworks and setup the base of the application. 61 | -------------------------------------------------------------------------------- /Content/posts/2019-03-20-aerogami_series_part_4.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Building a real-world iOS app (Part 4): Design 3 | date: 2019-03-20 12:00 4 | tags: Tutorial, iOS, Swift 5 | excerpt: We'll see how Sketch can be used to create minimalist application screen design and app icon. 6 | --- 7 | 8 | User experience (UX) and design is an integral part of any application. As a developer, I don't have much knowledge or "feeling" towards good looking designs. Moreover, truly great user experience requires many iterations of development and feedback. In this part we'll see how we can take example from Apple's mobile apps and design guidelines to create a familiar looking application. 9 | 10 | ## Colors 11 | 12 | We'll begin to design by choosing the color palette of our application. One of the best ways to ensure familiarity and simplicity of the app is to have consistent colors throughout the application. I found it a great advice to limit yourself to 1 or 2 colors. 13 | 14 | There are a few tools online to generate color palettes so the colors would fit together nicely. 15 | 16 | Chosen colors should be put in a common place so it could be easily accessible. 17 | 18 | ``` 19 | struct Theme { 20 | static let primary = UIColor(red: 255/255, green: 82/255, blue: 82/255, alpha: 1.0) 21 | static let primaryLight = Theme.primary.withAlphaComponent(0.9) 22 | static let backgroundColor = UIColor(red: 239/255, green: 239/255, blue: 244/255, alpha: 1.0) 23 | } 24 | ``` 25 | 26 | # UI 27 | 28 | Apple provides great resources for getting started. [Human Interface Guidelines](https://developer.apple.com/design/human-interface-guidelines/) is a great starting point for understanding the thinking behind Apple's choices as well as their preferences. Users have certain expectations and habits when using any application and it's important not to distract them with an unexpected behavior. 29 | 30 | We'll take the inspiration from already existing _AppStore_ app. The main screen of this app has a feed that we want to display in our travel application as well. 31 | 32 | App Scren Example 33 | 34 | Apple also provides us with [design resources](https://developer.apple.com/design/resources/) that contain [Sketch](https://www.sketch.com) files with designs of already existing applications. When learning to sketch or design something, I found it really beneficial to have these in front of me. 35 | 36 | After tweaking these screens and applying our color palette we can create the first version of our design. 37 | 38 | Feed Screen 39 | 40 | It displays the essential information such as _origin_, _destination_, _dates_ and _price_. We can also show images which provide visual information about the destination. 41 | 42 | ## App Icon 43 | 44 | Application icon is also a huge part of first impression of any application. We can use same given [design resources](https://developer.apple.com/design/resources/) that include examples of created app icons. 45 | 46 | We can use a little bit of imagination and tweak given icons on Sketch to give it a look of a travel or flight application. 47 | 48 | Making of App Icon 49 | 50 | The resulting icon looks like this. 51 | 52 | App Icon 53 | 54 | We can use [makeappicon.com](https://makeappicon.com) to generate all the necessary sizes of the icon so it could be used for different screen sizes as well as on AppStore. 55 | 56 | ## What's next? 57 | 58 | We saw how it's possible to create a clean design of an application without having much knowledge or spending too much time. Especially for small side projects, it's important to concentrate on main functionality and simply use best practices and examples when creating UIs. 59 | 60 | In the next part of the series we'll shift our attention back to the development of our application. We'll see the approach for creating new screens and keeping the view and its logic cleanly separated. 61 | -------------------------------------------------------------------------------- /Output/CNAME: -------------------------------------------------------------------------------- 1 | www.staskus.io 2 | -------------------------------------------------------------------------------- /Output/about/index.html: -------------------------------------------------------------------------------- 1 | Povilas Staškus - Senior iOS Engineer @Automattic

About

Hey, welcome to my blog! I've been doing software development since 2015, most of it on the iOS platform. Throughout this time I worked as a solo developer, with small and large teams as well as taught iOS development in a coding academy.

When working on my own I got the experience of communicating with clients face to face, formulating requirements, making designs, and eventually releasing applications. The work in larger organizations taught me the importance of clear communication both in real-life and in code. I developed in large and fast-growing codebases that required rethinking, coordination, refactoring, and automation efforts to make them suitable for the work of multiple teams.

I intend to use this blog as a way to share my learnings, my projects or just to fulfill random bursts of creativity.

Feel free to contact me on Twitter, LinkedIn or simply write me an email!

-------------------------------------------------------------------------------- /Output/afterWork/index.html: -------------------------------------------------------------------------------- 1 | Povilas Staškus - Senior iOS Engineer @Automattic

After work

Here I'm sharing projects not related to software development:

-------------------------------------------------------------------------------- /Output/images/Octocat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Output/images/Octocat.png -------------------------------------------------------------------------------- /Output/images/aerogami-tutorial/part1/architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Output/images/aerogami-tutorial/part1/architecture.png -------------------------------------------------------------------------------- /Output/images/aerogami-tutorial/part1/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Output/images/aerogami-tutorial/part1/screenshot.png -------------------------------------------------------------------------------- /Output/images/aerogami-tutorial/part2/project_frameworks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Output/images/aerogami-tutorial/part2/project_frameworks.png -------------------------------------------------------------------------------- /Output/images/aerogami-tutorial/part4/app_icon.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Output/images/aerogami-tutorial/part4/app_icon.gif -------------------------------------------------------------------------------- /Output/images/aerogami-tutorial/part4/app_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Output/images/aerogami-tutorial/part4/app_icon.png -------------------------------------------------------------------------------- /Output/images/aerogami-tutorial/part4/app_screen_example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Output/images/aerogami-tutorial/part4/app_screen_example.png -------------------------------------------------------------------------------- /Output/images/aerogami-tutorial/part4/app_screen_real.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Output/images/aerogami-tutorial/part4/app_screen_real.png -------------------------------------------------------------------------------- /Output/images/aerogami-tutorial/part5/app_demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Output/images/aerogami-tutorial/part5/app_demo.gif -------------------------------------------------------------------------------- /Output/images/app-clip/associated_domains.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Output/images/app-clip/associated_domains.png -------------------------------------------------------------------------------- /Output/images/app-clip/associated_domains_example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Output/images/app-clip/associated_domains_example.png -------------------------------------------------------------------------------- /Output/images/app-clip/hello_app_clip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Output/images/app-clip/hello_app_clip.png -------------------------------------------------------------------------------- /Output/images/app-clip/new_target.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Output/images/app-clip/new_target.png -------------------------------------------------------------------------------- /Output/images/app-clip/new_target_app_clip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Output/images/app-clip/new_target_app_clip.png -------------------------------------------------------------------------------- /Output/images/app-clip/testing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Output/images/app-clip/testing.png -------------------------------------------------------------------------------- /Output/images/app-clip/testing_success.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Output/images/app-clip/testing_success.png -------------------------------------------------------------------------------- /Output/images/archive/aerogami.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Output/images/archive/aerogami.png -------------------------------------------------------------------------------- /Output/images/archive/bemed.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Output/images/archive/bemed.jpg -------------------------------------------------------------------------------- /Output/images/archive/bemed0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Output/images/archive/bemed0.png -------------------------------------------------------------------------------- /Output/images/archive/bukdetektyvas0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Output/images/archive/bukdetektyvas0.png -------------------------------------------------------------------------------- /Output/images/archive/bukdetektyvas1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Output/images/archive/bukdetektyvas1.jpg -------------------------------------------------------------------------------- /Output/images/archive/bukdetektyvas2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Output/images/archive/bukdetektyvas2.jpg -------------------------------------------------------------------------------- /Output/images/archive/bukdetektyvas3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Output/images/archive/bukdetektyvas3.jpg -------------------------------------------------------------------------------- /Output/images/archive/bukdetektyvas4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Output/images/archive/bukdetektyvas4.jpg -------------------------------------------------------------------------------- /Output/images/archive/radistaivillage0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Output/images/archive/radistaivillage0.png -------------------------------------------------------------------------------- /Output/images/archive/radistaivillage1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Output/images/archive/radistaivillage1.jpg -------------------------------------------------------------------------------- /Output/images/archive/summerburst0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Output/images/archive/summerburst0.png -------------------------------------------------------------------------------- /Output/images/archive/summerburst1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Output/images/archive/summerburst1.jpg -------------------------------------------------------------------------------- /Output/images/archive/whatsthescore1.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Output/images/archive/whatsthescore1.PNG -------------------------------------------------------------------------------- /Output/images/archive/whatsthescore2.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Output/images/archive/whatsthescore2.PNG -------------------------------------------------------------------------------- /Output/images/archive/whatsthescore3.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Output/images/archive/whatsthescore3.PNG -------------------------------------------------------------------------------- /Output/images/archive/whatsthescore4.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Output/images/archive/whatsthescore4.PNG -------------------------------------------------------------------------------- /Output/images/archive/whatsthescore5.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Output/images/archive/whatsthescore5.PNG -------------------------------------------------------------------------------- /Output/images/notes/1bccd220960e2615c1c6b0933efea56e88b83393de2c8d325a749f8d37b9e4f6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Output/images/notes/1bccd220960e2615c1c6b0933efea56e88b83393de2c8d325a749f8d37b9e4f6.png -------------------------------------------------------------------------------- /Output/images/notes/42d971b30d15ec5efd2f8e1238e39424451afd922a0d719fa83811f80aeaf160.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Output/images/notes/42d971b30d15ec5efd2f8e1238e39424451afd922a0d719fa83811f80aeaf160.png -------------------------------------------------------------------------------- /Output/images/notes/4b53bbaf1ca1cab5b0a3959afb3ae6aaeefd5c8bf7772fb509f1d80a00ca5492.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Output/images/notes/4b53bbaf1ca1cab5b0a3959afb3ae6aaeefd5c8bf7772fb509f1d80a00ca5492.png -------------------------------------------------------------------------------- /Output/images/notes/67ea9a4463080be07ce89fc92ba437d53482bdce56217f6ff1ffe17e021bf200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Output/images/notes/67ea9a4463080be07ce89fc92ba437d53482bdce56217f6ff1ffe17e021bf200.png -------------------------------------------------------------------------------- /Output/images/notes/7e695531912858f96e685ace9f097d2692be7ebcd2c4e9808388f7a07f171669.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Output/images/notes/7e695531912858f96e685ace9f097d2692be7ebcd2c4e9808388f7a07f171669.png -------------------------------------------------------------------------------- /Output/images/notes/80f6b547b2282e1625e834be09bfa310ff0bb1f97819d40ace9eb9b28633f2e3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Output/images/notes/80f6b547b2282e1625e834be09bfa310ff0bb1f97819d40ace9eb9b28633f2e3.png -------------------------------------------------------------------------------- /Output/images/notes/86b326043320bbd1a5d8d05117e1187489c2d15b285e3a773dd4476c23e2dc14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Output/images/notes/86b326043320bbd1a5d8d05117e1187489c2d15b285e3a773dd4476c23e2dc14.png -------------------------------------------------------------------------------- /Output/images/notes/92fd3d4ecd5caee3c6cc2980d0918499ff0b5588294b07575264314b0f8e47ca.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Output/images/notes/92fd3d4ecd5caee3c6cc2980d0918499ff0b5588294b07575264314b0f8e47ca.png -------------------------------------------------------------------------------- /Output/images/notes/b8daa97dce2af0a8feb01d20e075456e68904da809bc44e9afb26ac5a82ca17e.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Output/images/notes/b8daa97dce2af0a8feb01d20e075456e68904da809bc44e9afb26ac5a82ca17e.png -------------------------------------------------------------------------------- /Output/images/notes/f53df9570974ef456f0347b2fe8bb8e09876c4c0c4910f51a3fb2bfb42ffc5fb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Output/images/notes/f53df9570974ef456f0347b2fe8bb8e09876c4c0c4910f51a3fb2bfb42ffc5fb.png -------------------------------------------------------------------------------- /Output/images/notes/fa7d4a6f8a071d1f4a6f1e3e9572c148813a06ed4f917a948a40f932f719b073.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Output/images/notes/fa7d4a6f8a071d1f4a6f1e3e9572c148813a06ed4f917a948a40f932f719b073.png -------------------------------------------------------------------------------- /Output/images/publish/blog_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Output/images/publish/blog_1.png -------------------------------------------------------------------------------- /Output/images/publish/blog_new_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Output/images/publish/blog_new_1.png -------------------------------------------------------------------------------- /Output/images/publish/blog_new_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Output/images/publish/blog_new_2.png -------------------------------------------------------------------------------- /Output/images/publish/previous_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Output/images/publish/previous_1.png -------------------------------------------------------------------------------- /Output/images/publish/previous_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Output/images/publish/previous_2.png -------------------------------------------------------------------------------- /Output/notes/Big0/index.html: -------------------------------------------------------------------------------- 1 | Povilas Staškus - Senior iOS Engineer @Automattic

Big O

Big O describes the efficiency of algorithms.

Time Complexity

Space Complexity

Space complexity is the amount of memory required by an algorithm.

Recursive calls

In recursive functions, each call is added to the stack and we take this space into account.

Cases

  • Best Case
  • Worst Case
  • Expected Case

The best case is not insightful. The expected case and the worst case are usually the same but not always.

Simplification

Big O is only concerned about the rate of increase and expressed how the runtime scales, thus we can drop the constants and non-dominant terms. O(2N) is just O(N).

  • O(N$^2$ + N) is O($N^2$)
  • O(N + log N) is O(N)
  • O(100*2$^2$ + 5000N$^2$) is O(2$^n$)
Complexities - GeeksForGeeks.org

However, have in mind that it's usually not possible to remove multiple variables, they still need to be represented in the notation.

For example, to sort an array of sorted strings the complexity would be O($as$(log a + log s))*, where a - array length, s - longest string length. In such cases, we cannot simplify much further.

O(n)

The algorithm that reverses an array only going through half of the array does not impact big O time and still has O(n) time complexity.

O(log N)

An algorithm will likely have an O(log N) runtime when the number of elements in the problem space gets halved at every step. Example - binary search.

O(2$^n$)

The base of an exponential complexity matters.

O(2$^l$$^o$$^g$$^N$)

This expression can be simplified to O(n). If we search binary tree making recursive calls the depth is roughly logN so it doesn't turn the recursive function exponential.

Memoization

Caching previously computed values is an optimization technique called memoization. It is a very common way to optimize exponential time recursive algorithms.

-------------------------------------------------------------------------------- /Output/notes/Bit Manipulation/index.html: -------------------------------------------------------------------------------- 1 | Povilas Staškus - Senior iOS Engineer @Automattic

Bit Manipulation

X ^ 0s = X 
 2 | X & 0s = 0 
 3 | X | 0s = X 
 4 | 
 5 | X ^ 1s = !x 
 6 | X & 1s = X 
 7 | X | 1s = 1s 
 8 | 
 9 | X ^ X = 0 
10 | X & X = X 
11 | X | X = X
12 | 

Logical Shift - we shift the bits and put 0 in the most significant bit. Arithmetic Shift - we shift values to the right but fill new bits with the values of the sign bit. Essentially meaning division by 2.

Example Tasks

Get Bit

func getBit(num: Int, position: Int) -> Bool {
13 |     return (num & (1 << position)) != 0
14 | }
15 | 
16 | getBit(num: 5, position: 2) // 0101 & 0100 = 0100 != 0
17 | getBit(num: 5, position: 1) // 0101 & 0010 = 0000 == 0
18 | 

What does code (n & n-1) == 0 do?

This logic checks if n is a power of 2 (or if n is 0)

Write a function to determine the number of bits you need to flip to convert integer A to integer B

func bitSwapsRequired(_ a: Int, _ b: Int) -> Int {
19 |     var count = 0
20 | 
21 |     var i = a ^ b
22 | 
23 |     while i != 0 {
24 |         count += 1
25 |         i = i & (i - 1)
26 |     }
27 | 
28 |     return count
29 | }
30 | 
31 | print(bitSwapsRequired(29, 15)) // 2
32 | 
-------------------------------------------------------------------------------- /Output/notes/Cheat Sheet of PM/index.html: -------------------------------------------------------------------------------- 1 | Povilas Staškus - Senior iOS Engineer @Automattic

Cheat Sheet of PM

Before

Justify The Project

  1. Define Project Drivers - people who benefit from the project and who can define the results and Project Supporters who make it posssible.
  2. Confirm that the project fits your organization’s priorities.
    1. Find multiple written sources of confirmation, both primary and secondary sources.
    2. Meet with the key audience to think about the issues and clarify any ambiguities.
    3. Compare written sources, meeting notes, and data. Clarify ambiguities.

Set Objectives

  1. Focus on a clear outcome, not an activity.
  2. Objectives should be:
    1. Specific
    2. Measurable
    3. Aggresive
    4. Realistic
    5. Time-sensitive
    6. Use simple and clear language
    7. Each objective needs to have a measure and each measure needs to have a performance target ("Develop x feature until the end of Q3").

Set schedules

  1. Identify all required activities and break them down into concrete steps.
  2. Consider duration and interdependencies (how all activities depend on each other).
  3. Identify how the activities will be performed (a strategy).
  4. Identify how many resources you have (number of engineering hours for example).
  5. Write down assumptions of scheduling and resources.
  6. Identify and plan for risks.
  7. Involve the project's drivers and supporters.

During

Sustaining commitment

  1. Clarify project benefits for the organization and team members.
  2. Involve team members in the planning process.
  3. Show that the project objectives are achievable.
  4. Address issues and concerns.
  5. Provide feedback and acknowledge contributions.

Hold people accountable

  1. Be specific about the results, time frames and constraints.
  2. Get the team to commit and write down the commitments.
  3. Have a way to monitor the progress and follow it.
  4. Communicate commitments to others.
  5. Meet your own commitments.

Common pitfalls to avoid

  1. Vague project objectives.
  2. Overlooked project's drivers and supporters.
  3. Ignoring the question of how likely it is that you;;be able to get the required amounts of time (backing in).
  4. Not writing down the commitments.
  5. Not keeping the plan up to date.
  6. Not communicating.
-------------------------------------------------------------------------------- /Output/notes/Decision paralysis/index.html: -------------------------------------------------------------------------------- 1 | Povilas Staškus - Senior iOS Engineer @Automattic

Decision Paralysis

Decision paralys can be cause by mulitple factors: 1. Pefect solution is favored over shipping and learning 2. No agreed directly responsible individual who can break ties 3. No one wants to say no and stay polite 4. People with different levels of experise get the same voice 5. The goals are not clear 6. Bikeshedding (the tendency to spend a lot of time on trivial details)

Solutions

Define the decision process beforehand

  1. What is the goal?
  2. Who makes the decision?
  3. When do we want to make a decision?
  4. Consensus vs consent

Identify the leader

Depending on the decision, some are harder to make than others, require taking responsibility or deep experise. Anticipate decision paralysis and identify the leader beforehand.

-------------------------------------------------------------------------------- /Output/notes/Good Metrics/index.html: -------------------------------------------------------------------------------- 1 | Povilas Staškus - Senior iOS Engineer @Automattic

Metrics

Metrics can aid in making better decisions, but it's important to use established frameworks and be cautious. Keep in mind that metrics can only capture reality and do not explain why users behave a certain way or what actions to take.

Any observed statistical regularity will tend to collapse once pressure is placed upon it for control purposes. When a measure becomes a target, it ceases to be a good measure. – Goodhart’s law

If you overvalue the data you are collecting, which will tend to be the easiest, you are likely chasing false positives about what that data is or what it means.

Be data informed, where you use data to inform your thinking, rather than data-driven, where you use data without questioning it or recognizing its limitations.

Top down

Focus on the business goals, the metrics should derive from the top.

Practical tips

  • Use guardrails: business metrics designed to indirectly measure business value and provide alerts about any potentially misleading or erroneous results and analysis
  • Iterate on metrics
  • Making too many changes at the same time
  • Using metrics that are in your control

As example, to lose weight focus on calories/day and workouts/week, not on weight.

Templates

  • HEART: Happiness, Engagement, Adoption, Task Success
  • AARRR
-------------------------------------------------------------------------------- /Output/notes/K-nearest neighbors/index.html: -------------------------------------------------------------------------------- 1 | Povilas Staškus - Senior iOS Engineer @Automattic

k-nearest neighbors

k-nearest neighbors (KNN) algorithm is used for classification.

Feature extraction

To classify a set of values and find k-nearest neighbors we first need to find some features (like size or color).

No matter how many features there are, we can calculate the distance by applying formula: sqrt((a1-a2)^2 + (b1-b2)^2 + (c1-c2)^2 ... + (h1-h2)^2 ). For a more nuanced result that takes into account how the user rates everything in general Cosine similarity is used to find closest neighbors.

Classification

Categorization into a group.

Regression

Prediction of a response.

Examples

Optical Character Recognition

How do understand a text from a photo? One of the ways is to use the KNN algorithm and analyzes different features of the characters (curves, lines).

-------------------------------------------------------------------------------- /Output/notes/Object Oriented Design/index.html: -------------------------------------------------------------------------------- 1 | Povilas Staškus - Senior iOS Engineer @Automattic

Object-Oriented Design

When designing a system it's important to know how to:

  1. Handle Ambiguity. Ask questions about who, what, where, when, who, and why to design a system for a clear purpose.
  2. Define the Core Objects (Person, Table, Meal, etc)
  3. Define Relationships
  4. Investigate Actions
-------------------------------------------------------------------------------- /Output/notes/Practical Deep Learning/index.html: -------------------------------------------------------------------------------- 1 | Povilas Staškus - Senior iOS Engineer @Automattic

Practical Deep Learning

Lesson 1

Source - course.fast.ai

To do image recognition before neural networks there was a lot of manual work involved by doing feature engineering. Neural networks are able to learn features automatically. For example, features that recognize corners, or features that recognize gradients. Going deeper into the layers, features become more complex and sophisticated. You start with a random neural network, feed it examples, and it will create features by itself.

Myth

Deep learning requires lots of math, data, and expensive computers.

Truth

High school math is sufficient, sometimes <50 items of data is enough to get record-breaking results, and usually you get what you need on laptop. 2 | 3 | ### Tools 4 | 5 | [Kaggle](https://www.kaggle.com/) is community platform for data scientists. In the scope of the course, it is used to share notebooks. [Jupyter](https://jupyter.org/) is a notebook interface used for the service. 6 | 7 | ### Comparison 8 | 9 | #### Traditional programming 10 | 11 | **Inputs -> Program -> Results** 12 | 13 | #### Deep learning 14 | 15 | **Inputs + Weights -> Model -> Result**s 16 | 17 | Model is mathematical function that takes inputs and multiplies them by one set of weights and adds them up, then it does the same with the second set of weights and adds them up again. Then it takes all the negative numbers and replaces them with zeros. And then it takes those as inputs to another layer. That is neural network. 18 | 19 | At first weights are random so model doesn't do anything useful. Therefore, when we get the result we evaluate how correct they are and then we update the weights. We do this many times until we get the result we want. Model in the end is a very flexible function. 20 | 21 | Once we got the trained model, then we can use it just as a regular program. 22 | 23 | **Inputs -> Model -> Results**

-------------------------------------------------------------------------------- /Output/notes/Searching/index.html: -------------------------------------------------------------------------------- 1 | Povilas Staškus - Senior iOS Engineer @Automattic

Searching

Binary Search

In binary search, we look for an element in a sorted array by comparing x to the middle of the array. If x is less we search on the left, if x is more we search on the right. We repeat until we find the x, or there are no more partitions we can make.

func binarySearch(_ array: [Int], _ x: Int) -> Int? {
 2 |     var low = 0
 3 |     var high = array.count - 1
 4 |     var mid = 0
 5 | 
 6 |     while low <= high {
 7 |         mid = low + high / 2
 8 | 
 9 |         if array[mid] > x {
10 |             high = mid - 1
11 |         } else if array[mid] < {
12 |             low = mid + 1
13 |         } else {
14 |             return mid
15 |         }
16 | 
17 |         return nil
18 |     }
19 | }
20 | 

Quick Select

Time: average and best - O(n), worst - O(n^2). Space - O(1).

Used to find the k or kth smallest/largest elements. It is a deviation of a quick sort.

  1. Pick a pivot (for example mid element)
  2. Add smaller elements to less array, increase index p every time we find a smaller element
  3. Put the pivot into p position
  4. We will have less array, pivot and greater array
  5. What we know at this point is that an element in p position is the pth largest value
  6. If we need to find k smallest values, if k == p, all the elements in less array are the smallest values
-------------------------------------------------------------------------------- /Output/notes/Stacks and Queues/index.html: -------------------------------------------------------------------------------- 1 | Povilas Staškus - Senior iOS Engineer @Automattic

Stacks and Queues

Stack

A stack has LIFO ordering. Main operations:

  • pop() - remove the top element
  • push(_) - add an item to the top
  • peek() - look at the top element
  • isEmpty() - true if there're no elements

Usage

  • Recursive algorithms

Queue

A queue has FIFO ordering. Main operations:

  • add(_) - aedd an item to the bottom
  • remove() - remove the top element
  • peek() - look at the top element
  • isEmpty() - true if there're no elements

Usage

  • Breadth-first-search
  • Implementing a cache

Time complexity

  • O(n) for accessing nth item
  • O(1) for adding and removing an item

Example tasks to know how to solve:

Min Stack

A stack that also can get a minimum value.

The trick here is to understand that minimum value only changes if the new smaller stack element is added. If this element is removed, we need to come back to an old minimum value. To achieve this we need to save a current min value with each Node. As it's a LIFO data structure we sort of have a timeline of minimum values.

Implement Queue using 2 Stacks

  • Since the queue is FIFO and stack is LIFO we can reverse element order by moving elements from one stack to another. Doing it every push operation produces a time complexity of O(n)
  • We can do an amortized solution with having old and new stack. Only if the old (reversed) element stack is empty, we shift elements from new to old. This makes the average scenario much more effective than the worst-case scenario.

Stack supporting different types

If the stack needs to support popAnyType(), popTypeA() and popTypeB() the best solution is to have separate stacks for both typeA and typeB and save a timestamp next to the nodes. When we do popAnyType() we can check which stack has the oldest element on top and return that.

-------------------------------------------------------------------------------- /Output/notes/Strategy vs Planning/index.html: -------------------------------------------------------------------------------- 1 | Povilas Staškus - Senior iOS Engineer @Automattic

Strategy vs Planning

Strategy

Strategy is an integrative set of choices that positions you on a playing field of your choice in a way that you win.

Strategy answers why we are on this particular playing field, and how on that playing field we're going to be better than anyone else. A strategic theory mus be coherent and doable.

  • Actual customers are your customers
  • You don't control customers
  • You don't control revenues
  • Uncertain, uncomfortable

Planning

Planning is the process of thinking regarding the activities required to achieve a desired goal.

  • You control costs
  • You are the customer
  • Comfortable

Example

While all the established airlines are busy planning their routes, the new upcoming airlines create a strategy to disrupt the market by having only shorthaul flights, use the same aircraft for all the routes, and optimize costs, eventually becoming a number one airline.

Planning trap

Planning can be a comfortable excercise were you can lay down all the steps and predict the outcomes. However, it may not help make significant improvements or change.

Strategy requires to take risks and accept uncertainty. If our theory is right about what we can do, and how the market will react, will position ourselves in a great way. When strategizing, lay down the logic what assumptions need to be true in order for the strategy to work. Observe if those assumptions are true, and if they are not, tweak the strategy.

Keep the strategy short and clear.

Not knowing for sure isn't a bad management. It's great leadership

-------------------------------------------------------------------------------- /Output/notes/Strategy/index.html: -------------------------------------------------------------------------------- 1 | Povilas Staškus - Senior iOS Engineer @Automattic

A problem-solving flow

A problem-solving flow

  1. Listen and clarify the question. Write down the important bits of information.
  2. Go through the examples and create your own example. Draw if possible.
  3. State a brute-force solution and its time & space complexities
  4. Optimize
    1. Look for bottlenecks, unnecessary work, and duplicated work
    2. Maybe there are unused bits of information from the description?
    3. Try going through the solution with different examples
    4. Try to solve with simplest example and make it bit by bit more complex
    5. Make time vs space tradeoff
    6. Computing some values (like sorting) upfront
    7. Brainstorm all the possible data structures
    8. Think about the best possible runtime and then how to achieve it
    9. Walkthrough the approach in detail
    10. Implement keeping coding standards in mind
    11. Test
    12. Code review
    13. Small test cases
    14. Special cases and edge cases
-------------------------------------------------------------------------------- /Output/notes/System Design and Scalability/index.html: -------------------------------------------------------------------------------- 1 | Povilas Staškus - Senior iOS Engineer @Automattic

System Design and Scalability

-------------------------------------------------------------------------------- /Output/notes/Useful Algorithms/index.html: -------------------------------------------------------------------------------- 1 | Povilas Staškus - Senior iOS Engineer @Automattic

Useful algorithms and data structures

The Fourier transform

  • Separate a song into its frequences
  • Compress songs and images
  • Earthquake prediction
  • DNA analysis

Searching, inserting, deleting

  • B-trees
  • Red-black trees
  • Heaps
  • Splay trees

Search Engines

  • Inverted indexes

Parallel algorithms

  • MapReduce (Using it through Apache Hadoop)

    Bloom filters and HyperLogLog

    They are used when fast access is needed to a large set of data and hash tables would be just too large.

    • Bloom filters give a probabilistic answer but they take up very little space compared to a hash table
    • HyperLogLog approximates the number of unique elements in a set. It doesn't give an exact answer but it takes only a fraction of the memory.

    The SHA algorithms

    Simhash

    A locality-sensitive hash. Similar values give similar hashes. Used by Google to detect duplicates while crawling the web, it could be used to check if a student was copying an essay from the web or check for copyrighted content.

    Diffie-Hellman key exchange

    Allows encrypting a message so it can only be read by the person you sent the message to.

    It uses two keys: public and private. The message is encrypted by a public key but only a private key can decrypt it.

    RSA is a successor of this algorithm.

    Linear programming

    Linear programming is used to maximize a result given some constraints. It uses Simplex algorithm. All graph problems are just a subset of linear programming.

    -------------------------------------------------------------------------------- /Output/notes/index.html: -------------------------------------------------------------------------------- 1 | Povilas Staškus - Senior iOS Engineer @Automattic

    Notes

    AI

    Algorithms

    Architecture

    Data Structures

    Interviewing

    Operations

    Project Management

    Soft Skills

    iOS

    -------------------------------------------------------------------------------- /Output/posts/index.html: -------------------------------------------------------------------------------- 1 | Povilas Staškus - Senior iOS Engineer @Automattic

    Posts

    -------------------------------------------------------------------------------- /Output/tags/app-clip/index.html: -------------------------------------------------------------------------------- 1 | Povilas Staškus - Senior iOS Engineer @Automattic

    App Clip posts

    App Clips: A first glance at the new way to access an iOS app

    iOS 14 introduces App Clips that allows making some of our app’s functionality available to users who don’t have the full app installed. In this article we take a first glance at this new feature.

    -------------------------------------------------------------------------------- /Output/tags/index.html: -------------------------------------------------------------------------------- 1 | Povilas Staškus - Senior iOS Engineer @Automattic
    -------------------------------------------------------------------------------- /Output/tags/ios-14/index.html: -------------------------------------------------------------------------------- 1 | Povilas Staškus - Senior iOS Engineer @Automattic

    Ios 14 posts

    App Clips: A first glance at the new way to access an iOS app

    iOS 14 introduces App Clips that allows making some of our app’s functionality available to users who don’t have the full app installed. In this article we take a first glance at this new feature.

    -------------------------------------------------------------------------------- /Output/tags/web/index.html: -------------------------------------------------------------------------------- 1 | Povilas Staškus - Senior iOS Engineer @Automattic

    Web posts

    Migrating from Jekyll to Publish: A site generator for Swift developers

    Swift community is growing and so is the variety of tools that are being created. In this blog article we'll go through the creation of a blog using a static site generator Publish.

    -------------------------------------------------------------------------------- /Output/webfonts/fa-brands-400.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Output/webfonts/fa-brands-400.eot -------------------------------------------------------------------------------- /Output/webfonts/fa-brands-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Output/webfonts/fa-brands-400.ttf -------------------------------------------------------------------------------- /Output/webfonts/fa-brands-400.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Output/webfonts/fa-brands-400.woff -------------------------------------------------------------------------------- /Output/webfonts/fa-brands-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Output/webfonts/fa-brands-400.woff2 -------------------------------------------------------------------------------- /Output/webfonts/fa-regular-400.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Output/webfonts/fa-regular-400.eot -------------------------------------------------------------------------------- /Output/webfonts/fa-regular-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Output/webfonts/fa-regular-400.ttf -------------------------------------------------------------------------------- /Output/webfonts/fa-regular-400.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Output/webfonts/fa-regular-400.woff -------------------------------------------------------------------------------- /Output/webfonts/fa-regular-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Output/webfonts/fa-regular-400.woff2 -------------------------------------------------------------------------------- /Output/webfonts/fa-solid-900.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Output/webfonts/fa-solid-900.eot -------------------------------------------------------------------------------- /Output/webfonts/fa-solid-900.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Output/webfonts/fa-solid-900.ttf -------------------------------------------------------------------------------- /Output/webfonts/fa-solid-900.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Output/webfonts/fa-solid-900.woff -------------------------------------------------------------------------------- /Output/webfonts/fa-solid-900.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Output/webfonts/fa-solid-900.woff2 -------------------------------------------------------------------------------- /Package.resolved: -------------------------------------------------------------------------------- 1 | { 2 | "object": { 3 | "pins": [ 4 | { 5 | "package": "Codextended", 6 | "repositoryURL": "https://github.com/johnsundell/codextended.git", 7 | "state": { 8 | "branch": null, 9 | "revision": "8d7c46dfc9c55240870cf5561d6cefa41e3d7105", 10 | "version": "0.3.0" 11 | } 12 | }, 13 | { 14 | "package": "Files", 15 | "repositoryURL": "https://github.com/johnsundell/files.git", 16 | "state": { 17 | "branch": null, 18 | "revision": "22fe84797d499ffca911ccd896b34efaf06a50b9", 19 | "version": "4.1.1" 20 | } 21 | }, 22 | { 23 | "package": "Ink", 24 | "repositoryURL": "https://github.com/johnsundell/ink.git", 25 | "state": { 26 | "branch": null, 27 | "revision": "a9a1a0190aaacc9058a2bfbdcd831785eac26f43", 28 | "version": "0.3.0" 29 | } 30 | }, 31 | { 32 | "package": "Plot", 33 | "repositoryURL": "https://github.com/johnsundell/plot.git", 34 | "state": { 35 | "branch": null, 36 | "revision": "c27f6857deeb4c4623db294172a8ec572790a9be", 37 | "version": "0.10.0" 38 | } 39 | }, 40 | { 41 | "package": "Publish", 42 | "repositoryURL": "https://github.com/johnsundell/publish.git", 43 | "state": { 44 | "branch": null, 45 | "revision": "1402af3cbe18df03fb6df701fdcf51471f98d0ff", 46 | "version": "0.8.0" 47 | } 48 | }, 49 | { 50 | "package": "ShellOut", 51 | "repositoryURL": "https://github.com/johnsundell/shellout.git", 52 | "state": { 53 | "branch": null, 54 | "revision": "e1577acf2b6e90086d01a6d5e2b8efdaae033568", 55 | "version": "2.3.0" 56 | } 57 | }, 58 | { 59 | "package": "Splash", 60 | "repositoryURL": "https://github.com/johnsundell/splash.git", 61 | "state": { 62 | "branch": null, 63 | "revision": "2d55b33529e1a3a354d5ef9a5437d4abd842a5a3", 64 | "version": "0.11.1" 65 | } 66 | }, 67 | { 68 | "package": "SplashPublishPlugin", 69 | "repositoryURL": "https://github.com/johnsundell/splashpublishplugin", 70 | "state": { 71 | "branch": null, 72 | "revision": "34bb50bd83b2a40c63afc35f090c76619dc149ce", 73 | "version": "0.1.0" 74 | } 75 | }, 76 | { 77 | "package": "Sweep", 78 | "repositoryURL": "https://github.com/johnsundell/sweep.git", 79 | "state": { 80 | "branch": null, 81 | "revision": "801c2878e4c6c5baf32fe132e1f3f3af6f9fd1b0", 82 | "version": "0.4.0" 83 | } 84 | } 85 | ] 86 | }, 87 | "version": 1 88 | } 89 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.1 2 | 3 | import PackageDescription 4 | 5 | let package = Package( 6 | name: "Blog", 7 | products: [ 8 | .executable(name: "Blog", targets: ["Blog"]) 9 | ], 10 | dependencies: [ 11 | .package(url: "https://github.com/johnsundell/publish.git", from: "0.8.0"), 12 | .package(url: "https://github.com/johnsundell/splashpublishplugin", from: "0.1.0") 13 | ], 14 | targets: [ 15 | .target( 16 | name: "Blog", 17 | dependencies: ["Publish", "SplashPublishPlugin"] 18 | ) 19 | ] 20 | ) 21 | -------------------------------------------------------------------------------- /Resources/CNAME: -------------------------------------------------------------------------------- 1 | www.staskus.io 2 | -------------------------------------------------------------------------------- /Resources/images/Octocat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Resources/images/Octocat.png -------------------------------------------------------------------------------- /Resources/images/aerogami-tutorial/part1/architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Resources/images/aerogami-tutorial/part1/architecture.png -------------------------------------------------------------------------------- /Resources/images/aerogami-tutorial/part1/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Resources/images/aerogami-tutorial/part1/screenshot.png -------------------------------------------------------------------------------- /Resources/images/aerogami-tutorial/part2/project_frameworks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Resources/images/aerogami-tutorial/part2/project_frameworks.png -------------------------------------------------------------------------------- /Resources/images/aerogami-tutorial/part4/app_icon.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Resources/images/aerogami-tutorial/part4/app_icon.gif -------------------------------------------------------------------------------- /Resources/images/aerogami-tutorial/part4/app_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Resources/images/aerogami-tutorial/part4/app_icon.png -------------------------------------------------------------------------------- /Resources/images/aerogami-tutorial/part4/app_screen_example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Resources/images/aerogami-tutorial/part4/app_screen_example.png -------------------------------------------------------------------------------- /Resources/images/aerogami-tutorial/part4/app_screen_real.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Resources/images/aerogami-tutorial/part4/app_screen_real.png -------------------------------------------------------------------------------- /Resources/images/aerogami-tutorial/part5/app_demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Resources/images/aerogami-tutorial/part5/app_demo.gif -------------------------------------------------------------------------------- /Resources/images/app-clip/associated_domains.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Resources/images/app-clip/associated_domains.png -------------------------------------------------------------------------------- /Resources/images/app-clip/associated_domains_example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Resources/images/app-clip/associated_domains_example.png -------------------------------------------------------------------------------- /Resources/images/app-clip/hello_app_clip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Resources/images/app-clip/hello_app_clip.png -------------------------------------------------------------------------------- /Resources/images/app-clip/new_target.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Resources/images/app-clip/new_target.png -------------------------------------------------------------------------------- /Resources/images/app-clip/new_target_app_clip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Resources/images/app-clip/new_target_app_clip.png -------------------------------------------------------------------------------- /Resources/images/app-clip/testing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Resources/images/app-clip/testing.png -------------------------------------------------------------------------------- /Resources/images/app-clip/testing_success.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Resources/images/app-clip/testing_success.png -------------------------------------------------------------------------------- /Resources/images/archive/aerogami.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Resources/images/archive/aerogami.png -------------------------------------------------------------------------------- /Resources/images/archive/bemed.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Resources/images/archive/bemed.jpg -------------------------------------------------------------------------------- /Resources/images/archive/bemed0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Resources/images/archive/bemed0.png -------------------------------------------------------------------------------- /Resources/images/archive/bukdetektyvas0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Resources/images/archive/bukdetektyvas0.png -------------------------------------------------------------------------------- /Resources/images/archive/bukdetektyvas1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Resources/images/archive/bukdetektyvas1.jpg -------------------------------------------------------------------------------- /Resources/images/archive/bukdetektyvas2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Resources/images/archive/bukdetektyvas2.jpg -------------------------------------------------------------------------------- /Resources/images/archive/bukdetektyvas3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Resources/images/archive/bukdetektyvas3.jpg -------------------------------------------------------------------------------- /Resources/images/archive/bukdetektyvas4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Resources/images/archive/bukdetektyvas4.jpg -------------------------------------------------------------------------------- /Resources/images/archive/radistaivillage0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Resources/images/archive/radistaivillage0.png -------------------------------------------------------------------------------- /Resources/images/archive/radistaivillage1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Resources/images/archive/radistaivillage1.jpg -------------------------------------------------------------------------------- /Resources/images/archive/summerburst0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Resources/images/archive/summerburst0.png -------------------------------------------------------------------------------- /Resources/images/archive/summerburst1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Resources/images/archive/summerburst1.jpg -------------------------------------------------------------------------------- /Resources/images/archive/whatsthescore1.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Resources/images/archive/whatsthescore1.PNG -------------------------------------------------------------------------------- /Resources/images/archive/whatsthescore2.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Resources/images/archive/whatsthescore2.PNG -------------------------------------------------------------------------------- /Resources/images/archive/whatsthescore3.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Resources/images/archive/whatsthescore3.PNG -------------------------------------------------------------------------------- /Resources/images/archive/whatsthescore4.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Resources/images/archive/whatsthescore4.PNG -------------------------------------------------------------------------------- /Resources/images/archive/whatsthescore5.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Resources/images/archive/whatsthescore5.PNG -------------------------------------------------------------------------------- /Resources/images/notes/1bccd220960e2615c1c6b0933efea56e88b83393de2c8d325a749f8d37b9e4f6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Resources/images/notes/1bccd220960e2615c1c6b0933efea56e88b83393de2c8d325a749f8d37b9e4f6.png -------------------------------------------------------------------------------- /Resources/images/notes/42d971b30d15ec5efd2f8e1238e39424451afd922a0d719fa83811f80aeaf160.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Resources/images/notes/42d971b30d15ec5efd2f8e1238e39424451afd922a0d719fa83811f80aeaf160.png -------------------------------------------------------------------------------- /Resources/images/notes/4b53bbaf1ca1cab5b0a3959afb3ae6aaeefd5c8bf7772fb509f1d80a00ca5492.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Resources/images/notes/4b53bbaf1ca1cab5b0a3959afb3ae6aaeefd5c8bf7772fb509f1d80a00ca5492.png -------------------------------------------------------------------------------- /Resources/images/notes/67ea9a4463080be07ce89fc92ba437d53482bdce56217f6ff1ffe17e021bf200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Resources/images/notes/67ea9a4463080be07ce89fc92ba437d53482bdce56217f6ff1ffe17e021bf200.png -------------------------------------------------------------------------------- /Resources/images/notes/7e695531912858f96e685ace9f097d2692be7ebcd2c4e9808388f7a07f171669.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Resources/images/notes/7e695531912858f96e685ace9f097d2692be7ebcd2c4e9808388f7a07f171669.png -------------------------------------------------------------------------------- /Resources/images/notes/80f6b547b2282e1625e834be09bfa310ff0bb1f97819d40ace9eb9b28633f2e3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Resources/images/notes/80f6b547b2282e1625e834be09bfa310ff0bb1f97819d40ace9eb9b28633f2e3.png -------------------------------------------------------------------------------- /Resources/images/notes/86b326043320bbd1a5d8d05117e1187489c2d15b285e3a773dd4476c23e2dc14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Resources/images/notes/86b326043320bbd1a5d8d05117e1187489c2d15b285e3a773dd4476c23e2dc14.png -------------------------------------------------------------------------------- /Resources/images/notes/92fd3d4ecd5caee3c6cc2980d0918499ff0b5588294b07575264314b0f8e47ca.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Resources/images/notes/92fd3d4ecd5caee3c6cc2980d0918499ff0b5588294b07575264314b0f8e47ca.png -------------------------------------------------------------------------------- /Resources/images/notes/b8daa97dce2af0a8feb01d20e075456e68904da809bc44e9afb26ac5a82ca17e.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Resources/images/notes/b8daa97dce2af0a8feb01d20e075456e68904da809bc44e9afb26ac5a82ca17e.png -------------------------------------------------------------------------------- /Resources/images/notes/f53df9570974ef456f0347b2fe8bb8e09876c4c0c4910f51a3fb2bfb42ffc5fb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Resources/images/notes/f53df9570974ef456f0347b2fe8bb8e09876c4c0c4910f51a3fb2bfb42ffc5fb.png -------------------------------------------------------------------------------- /Resources/images/notes/fa7d4a6f8a071d1f4a6f1e3e9572c148813a06ed4f917a948a40f932f719b073.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Resources/images/notes/fa7d4a6f8a071d1f4a6f1e3e9572c148813a06ed4f917a948a40f932f719b073.png -------------------------------------------------------------------------------- /Resources/images/publish/blog_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Resources/images/publish/blog_1.png -------------------------------------------------------------------------------- /Resources/images/publish/blog_new_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Resources/images/publish/blog_new_1.png -------------------------------------------------------------------------------- /Resources/images/publish/blog_new_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Resources/images/publish/blog_new_2.png -------------------------------------------------------------------------------- /Resources/images/publish/previous_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Resources/images/publish/previous_1.png -------------------------------------------------------------------------------- /Resources/images/publish/previous_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Resources/images/publish/previous_2.png -------------------------------------------------------------------------------- /Resources/webfonts/fa-brands-400.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Resources/webfonts/fa-brands-400.eot -------------------------------------------------------------------------------- /Resources/webfonts/fa-brands-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Resources/webfonts/fa-brands-400.ttf -------------------------------------------------------------------------------- /Resources/webfonts/fa-brands-400.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Resources/webfonts/fa-brands-400.woff -------------------------------------------------------------------------------- /Resources/webfonts/fa-brands-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Resources/webfonts/fa-brands-400.woff2 -------------------------------------------------------------------------------- /Resources/webfonts/fa-regular-400.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Resources/webfonts/fa-regular-400.eot -------------------------------------------------------------------------------- /Resources/webfonts/fa-regular-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Resources/webfonts/fa-regular-400.ttf -------------------------------------------------------------------------------- /Resources/webfonts/fa-regular-400.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Resources/webfonts/fa-regular-400.woff -------------------------------------------------------------------------------- /Resources/webfonts/fa-regular-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Resources/webfonts/fa-regular-400.woff2 -------------------------------------------------------------------------------- /Resources/webfonts/fa-solid-900.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Resources/webfonts/fa-solid-900.eot -------------------------------------------------------------------------------- /Resources/webfonts/fa-solid-900.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Resources/webfonts/fa-solid-900.ttf -------------------------------------------------------------------------------- /Resources/webfonts/fa-solid-900.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Resources/webfonts/fa-solid-900.woff -------------------------------------------------------------------------------- /Resources/webfonts/fa-solid-900.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/staskus/Blog/8115fdfccec1a1694abc1e48a1f5e769561af9f9/Resources/webfonts/fa-solid-900.woff2 -------------------------------------------------------------------------------- /Sources/Blog/Blog.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Blog.swift 3 | // 4 | // 5 | // Created by Povilas Staskus on 1/26/20. 6 | // 7 | 8 | import Foundation 9 | import Publish 10 | import Plot 11 | 12 | struct Blog: Website { 13 | enum SectionID: String, WebsiteSectionID { 14 | case posts 15 | case about 16 | case notes 17 | case archive 18 | case afterWork 19 | 20 | var name: String { 21 | switch self { 22 | case .posts: return "Posts" 23 | case .notes: return "Notes" 24 | case .archive: return "Archive" 25 | case .about: return "About" 26 | case .afterWork: return "After work" 27 | } 28 | } 29 | } 30 | 31 | struct ItemMetadata: WebsiteItemMetadata { 32 | var excerpt: String 33 | var topic: String { 34 | return excerpt 35 | } 36 | } 37 | 38 | var url = URL(string: "https://www.staskus.io")! 39 | var title = "staskus.io" 40 | var name = "Povilas Staškus" 41 | var description = "Senior iOS Engineer @Automattic" 42 | var language: Language { .english } 43 | var imagePath: Path? { nil } 44 | var socialMediaLinks: [SocialMediaLink] { [.location, .email, .linkedIn, .github, .twitter] } 45 | } 46 | -------------------------------------------------------------------------------- /Sources/Blog/BlogTheme/BlogDateFormatter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BlogDateFormatter.swift 3 | // 4 | // 5 | // Created by Povilas Staskus on 1/26/20. 6 | // 7 | 8 | import Foundation 9 | 10 | extension DateFormatter { 11 | static var blog: DateFormatter = { 12 | let formatter = DateFormatter() 13 | formatter.dateStyle = .long 14 | return formatter 15 | }() 16 | } 17 | -------------------------------------------------------------------------------- /Sources/Blog/BlogTheme/BlogHTMLFactory.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BlogHTMLFactory.swift 3 | // 4 | // 5 | // Created by Povilas Staskus on 1/26/20. 6 | // 7 | 8 | import Publish 9 | import Plot 10 | 11 | struct BlogHTMLFactory: HTMLFactory { 12 | func makeIndexHTML(for index: Index, context: PublishingContext) throws -> HTML { 13 | HTML( 14 | .lang(context.site.language), 15 | .head(for: context.site), 16 | .body( 17 | .grid( 18 | .header(for: context.site), 19 | .sidebar(for: context.site), 20 | .posts( 21 | for: context 22 | .allItems( 23 | sortedBy: \.date, 24 | order: .descending 25 | ) 26 | .filter { $0.sectionID == .posts }, 27 | on: context.site, 28 | title: "Recent posts" 29 | ), 30 | .footer(for: context.site) 31 | ) 32 | ) 33 | ) 34 | } 35 | 36 | func makeSectionHTML(for section: Section, context: PublishingContext) throws -> HTML { 37 | HTML( 38 | .lang(context.site.language), 39 | .head(for: context.site), 40 | .body( 41 | .grid( 42 | .header(for: context.site), 43 | .sidebar(for: context.site), 44 | .pageContent(.h1(.text(section.title))), 45 | .footer(for: context.site) 46 | ) 47 | ) 48 | ) 49 | } 50 | 51 | func makeItemHTML(for item: Item, context: PublishingContext) throws -> HTML { 52 | HTML( 53 | .lang(context.site.language), 54 | .head(for: context.site), 55 | .body( 56 | .grid( 57 | .header(for: context.site), 58 | .sidebar(for: context.site), 59 | .item(for: item, on: context.site), 60 | .footer(for: context.site) 61 | ) 62 | 63 | ) 64 | ) 65 | } 66 | 67 | func makePageHTML(for page: Page, context: PublishingContext) throws -> HTML { 68 | HTML( 69 | .lang(context.site.language), 70 | .head(for: context.site), 71 | .body( 72 | .grid( 73 | .header(for: context.site), 74 | .sidebar(for: context.site), 75 | .page(for: page, context: context), 76 | .footer(for: context.site) 77 | ) 78 | ) 79 | ) 80 | } 81 | 82 | func makeTagListHTML(for page: TagListPage, context: PublishingContext) throws -> HTML? { 83 | HTML( 84 | .lang(context.site.language), 85 | .head(for: context.site), 86 | .body( 87 | .grid( 88 | .header(for: context.site), 89 | .sidebar(for: context.site), 90 | .pageContent( 91 | .tagList(for: page, on: context.site) 92 | ), 93 | .footer(for: context.site) 94 | ) 95 | ) 96 | ) 97 | } 98 | 99 | func makeTagDetailsHTML(for page: TagDetailsPage, context: PublishingContext) throws -> HTML? { 100 | HTML( 101 | .lang(context.site.language), 102 | .head(for: context.site), 103 | .body( 104 | .grid( 105 | .header(for: context.site), 106 | .sidebar(for: context.site), 107 | .posts( 108 | for: context.items( 109 | taggedWith: page.tag, 110 | sortedBy: \.date, 111 | order: .descending 112 | ), 113 | on: context.site, 114 | title: "\(page.tag.string.capitalized) posts" 115 | ), 116 | .footer(for: context.site) 117 | ) 118 | ) 119 | ) 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /Sources/Blog/BlogTheme/Nodes/Node+Footer.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Node+Footer.swift 3 | // 4 | // 5 | // Created by Povilas Staskus on 1/26/20. 6 | // 7 | 8 | import Foundation 9 | import Plot 10 | 11 | extension Node where Context == HTML.BodyContext { 12 | static func footer(for site: Blog) -> Node { 13 | let currentYear = Calendar.current.component(.year, from: Date()) 14 | return .div( 15 | .class("footer pure-u-1"), 16 | .div( 17 | .class("pure-u-1"), 18 | .text("© \(currentYear) \(site.name)") 19 | ), 20 | .div( 21 | .class("pure-u-1"), 22 | .text("Generated using "), 23 | .a( 24 | .text("Publish"), 25 | .href("https://github.com/johnsundell/publish") 26 | ) 27 | ), 28 | .div( 29 | .class("pure-u-1"), 30 | .a( 31 | .text("RSS feed"), 32 | .href("/feed.rss") 33 | ) 34 | ) 35 | ) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Sources/Blog/BlogTheme/Nodes/Node+Grid.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Node+Grid.swift 3 | // 4 | // 5 | // Created by Povilas Staskus on 1/26/20. 6 | // 7 | 8 | import Plot 9 | 10 | extension Node where Context == HTML.BodyContext { 11 | static func grid(_ nodes: Node...) -> Node { 12 | .div( 13 | .id("layout"), 14 | .class("pure-g"), 15 | .group(nodes) 16 | ) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Sources/Blog/BlogTheme/Nodes/Node+Head.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Node+Head.swift 3 | // 4 | // 5 | // Created by Povilas Staskus on 1/26/20. 6 | // 7 | 8 | import Plot 9 | 10 | extension Node where Context == HTML.DocumentContext { 11 | static func head(for site: Blog) -> Node { 12 | return Node.head( 13 | .title("\(site.name) - \(site.description)"), 14 | .meta( 15 | .charset(.utf8), 16 | .name("viewport"), 17 | .content("width=device-width, initial-scale=1") 18 | ), 19 | .link( 20 | .rel(.stylesheet), 21 | .href("https://unpkg.com/purecss@1.0.1/build/pure-min.css"), 22 | .init(name: "integrity", value: "sha384-oAOxQR6DkCoMliIh8yFnu25d7Eq/PHS21PClpwjOTeU2jRSq11vu66rf90/cZr47"), 23 | .init(name: "crossorigin", value: "anonymous") 24 | ), 25 | .link( 26 | .rel(.stylesheet), 27 | .href("https://unpkg.com/purecss@1.0.1/build/grids-responsive-min.css") 28 | ), 29 | .link( 30 | .rel(.stylesheet), 31 | .href("/Pure/styles.css") 32 | ), 33 | .link( 34 | .rel(.stylesheet), 35 | .href("/all.css") 36 | ) 37 | ) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Sources/Blog/BlogTheme/Nodes/Node+Header.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Node+Header.swift 3 | // 4 | // 5 | // Created by Povilas Staskus on 1/26/20. 6 | // 7 | 8 | import Plot 9 | 10 | extension Node where Context == HTML.BodyContext { 11 | private static var sections: [Blog.SectionID] { [.about, .archive, .afterWork] } 12 | 13 | static func header(for site: Blog) -> Node { 14 | return .div( 15 | .div( 16 | .class("pure-menu pure-menu-horizontal pure-u-1-1 top-header"), 17 | .a( 18 | .class("pure-menu-heading"), 19 | .text(site.title), 20 | .href("/") 21 | ), 22 | .ul( 23 | .class("pure-menu-list"), 24 | .forEach(sections, { section in 25 | .li( 26 | .class("pure-menu-item"), 27 | .a( 28 | .class("pure-menu-link"), 29 | .text(section.name), 30 | .href(site.path(for: section)) 31 | ) 32 | ) 33 | }) 34 | ) 35 | ) 36 | ) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Sources/Blog/BlogTheme/Nodes/Node+Icon.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Node+Icon.swift 3 | // 4 | // 5 | // Created by Povilas Staskus on 1/26/20. 6 | // 7 | 8 | import Plot 9 | 10 | extension Node where Context == HTML.AnchorContext { 11 | static func icon(_ text: String) -> Node { 12 | return .element(named: "i", attributes: [.class(text + " l-box social-icon")]) 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Sources/Blog/BlogTheme/Nodes/Node+Item.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import Plot 3 | import Publish 4 | 5 | extension Node where Context == HTML.BodyContext { 6 | static func item(for item: Item, on site: Blog) -> Node { 7 | if item.path.absoluteString.contains(Blog.SectionID.notes.rawValue) { 8 | return .notePage(for: item, on: site) 9 | } else { 10 | return .post(for: item, on: site) 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Sources/Blog/BlogTheme/Nodes/Node+Page.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Node+Page.swift 3 | // 4 | // 5 | // Created by Povilas Staskus on 1/26/20. 6 | // 7 | 8 | import Foundation 9 | import Plot 10 | import Publish 11 | 12 | extension Node where Context == HTML.BodyContext { 13 | static func page(for page: Page, context: PublishingContext) -> Node { 14 | switch page.path.string { 15 | case Blog.SectionID.notes.rawValue: return .notesPage(for: page, context: context) 16 | default: return .defaultPage(for: page, on: context.site) 17 | } 18 | 19 | } 20 | 21 | static func defaultPage(for page: Page, on site: Blog) -> Node { 22 | return .pageContent( 23 | .h2( 24 | .class("post-title"), 25 | .text(page.title) 26 | ), 27 | .div( 28 | .class("post-description"), 29 | .div( 30 | .contentBody(page.body) 31 | ) 32 | ) 33 | ) 34 | } 35 | } 36 | 37 | -------------------------------------------------------------------------------- /Sources/Blog/BlogTheme/Nodes/Node+PageContent.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Node+PageContent.swift 3 | // 4 | // 5 | // Created by Povilas Staskus on 1/26/20. 6 | // 7 | 8 | import Publish 9 | import Plot 10 | 11 | extension Node where Context == HTML.BodyContext { 12 | static func pageContent(_ nodes: Node...) -> Node { 13 | return .div( 14 | .class("content pure-u-1 pure-u-md-3-5 pure-u-xl-6-10"), 15 | .group(nodes) 16 | ) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Sources/Blog/BlogTheme/Nodes/Node+Post.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Node+Post.swift 3 | // 4 | // 5 | // Created by Povilas Staskus on 1/26/20. 6 | // 7 | 8 | import Foundation 9 | import Plot 10 | import Publish 11 | 12 | extension Node where Context == HTML.BodyContext { 13 | static func post(for item: Item, on site: Blog) -> Node { 14 | return .pageContent( 15 | .h2( 16 | .class("post-title"), 17 | .a( 18 | .href(item.path), 19 | .text(item.title) 20 | ) 21 | ), 22 | .p( 23 | .class("post-meta"), 24 | .text(DateFormatter.blog.string(from: item.date)) 25 | ), 26 | .tagList(for: item, on: site), 27 | .div( 28 | .class("post-description"), 29 | .div( 30 | .contentBody(item.body) 31 | ) 32 | ) 33 | ) 34 | } 35 | } 36 | 37 | -------------------------------------------------------------------------------- /Sources/Blog/BlogTheme/Nodes/Node+PostExcerpt.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Node+PostExcerpt.swift 3 | // 4 | // 5 | // Created by Povilas Staskus on 1/26/20. 6 | // 7 | 8 | import Foundation 9 | import Publish 10 | import Plot 11 | 12 | extension Node where Context == HTML.BodyContext { 13 | static func postExcerpt(for item: Item, on site: Blog) -> Node { 14 | return .section( 15 | .class("post"), 16 | .header( 17 | .class("post-header"), 18 | .h2( 19 | .class("post-title"), 20 | .a( 21 | .href(item.path), 22 | .text(item.title) 23 | ) 24 | ), 25 | .p( 26 | .class("post-meta"), 27 | .text(DateFormatter.blog.string(from: item.date)), 28 | tagList(for: item, on: site) 29 | ) 30 | ), 31 | .div( 32 | .class("post-description"), 33 | .p(.text(item.metadata.excerpt)) 34 | ) 35 | ) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Sources/Blog/BlogTheme/Nodes/Node+Posts.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Node+Posts.swift 3 | // 4 | // 5 | // Created by Povilas Staskus on 1/26/20. 6 | // 7 | 8 | import Plot 9 | import Publish 10 | 11 | extension Node where Context == HTML.BodyContext { 12 | static func posts(for items: [Item], on site: Blog, title: String) -> Node { 13 | return .pageContent( 14 | .div( 15 | .class("posts"), 16 | .h1(.class("content-subhead"), .text(title)), 17 | .forEach(items) { item in 18 | .postExcerpt(for: item, on: site) 19 | } 20 | ) 21 | ) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Sources/Blog/BlogTheme/Nodes/Node+Sidebar.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Node+Sidebar.swift 3 | // 4 | // 5 | // Created by Povilas Staskus on 1/26/20. 6 | // 7 | 8 | import Plot 9 | 10 | extension Node where Context == HTML.BodyContext { 11 | static func sidebar(for site: Blog) -> Node { 12 | return .div( 13 | .class("sidebar pure-u-1 pure-u-md-1-4"), 14 | .div( 15 | .class("header"), 16 | .grid( 17 | .div( 18 | .class("pure-u-md-1-1 pure-u-1-4"), 19 | .class("author__avatar"), 20 | .img( 21 | .src("https://avatars0.githubusercontent.com/u/4062343?s=460&v=4") 22 | ) 23 | ), 24 | .div( 25 | .class("pure-u-md-1-1 pure-u-3-4"), 26 | .h1( 27 | .class("brand-title"), 28 | .text(site.name) 29 | ), 30 | .h3( 31 | .class("brand-tagline"), 32 | .text(site.description) 33 | ) 34 | ) 35 | ), 36 | .grid( 37 | .forEach(site.socialMediaLinks, { link in 38 | .div( 39 | .class("pure-u-md-1-1"), 40 | .a( 41 | .href(link.url), 42 | .icon(link.icon), 43 | .a( 44 | .class("social-media"), 45 | .href(link.url), 46 | .text(link.title) 47 | ) 48 | ) 49 | ) 50 | }) 51 | ) 52 | ) 53 | ) 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Sources/Blog/BlogTheme/Nodes/Node+TagList.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Node+TagList.swift 3 | // 4 | // 5 | // Created by Povilas Staskus on 1/26/20. 6 | // 7 | 8 | import Publish 9 | import Plot 10 | 11 | extension Node where Context == HTML.BodyContext { 12 | static func tagList(for tags: [Tag], on site: Blog) -> Node { 13 | return .div(.class("post-tags"), .forEach(tags) { tag in 14 | .a( 15 | .class("post-category post-category-\(tag.string.lowercased())"), 16 | .href(site.path(for: tag)), 17 | .text(tag.string) 18 | ) 19 | }) 20 | } 21 | 22 | static func tagList(for item: Item, on site: Blog) -> Node { 23 | return .tagList(for: item.tags, on: site) 24 | 25 | } 26 | 27 | static func tagList(for page: TagListPage, on site: Blog) -> Node { 28 | return .tagList(for: Array(page.tags), on: site) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Sources/Blog/BlogTheme/Nodes/Notes/Node+NotePage.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import Plot 3 | import Publish 4 | 5 | extension Node where Context == HTML.BodyContext { 6 | static func notePage(for item: Item, on site: Blog) -> Node { 7 | return .pageContent( 8 | .h2( 9 | .class("post-title"), 10 | .a( 11 | .href(item.path), 12 | .text(item.title) 13 | ) 14 | ), 15 | .p( 16 | .class("post-meta"), 17 | .text("Last modified: " + DateFormatter.blog.string(from: item.lastModified)) 18 | ), 19 | .div( 20 | .class("post-description"), 21 | .div( 22 | .contentBody(item.body) 23 | ) 24 | ) 25 | ) 26 | } 27 | } 28 | 29 | -------------------------------------------------------------------------------- /Sources/Blog/BlogTheme/Nodes/Notes/Node+NotesPage.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import Plot 3 | import Publish 4 | 5 | extension Node where Context == HTML.BodyContext { 6 | static func notesPage(for page: Page, context: PublishingContext) -> Node { 7 | return .pageContent( 8 | .h2( 9 | .class("post-title"), 10 | .text(page.title) 11 | ), 12 | .forEach(Topic.group(items: context.allItems( 13 | sortedBy: \.title, 14 | order: .ascending 15 | ) 16 | .filter { $0.sectionID == .notes })) { topic in 17 | .div( 18 | .h2(.text(topic.name)), 19 | .noteList(for: topic.items, on: context.site) 20 | ) 21 | } 22 | ) 23 | } 24 | 25 | private static func noteList(for items: [Item], on site: Blog) -> Node { 26 | return .div( 27 | .forEach(items) { item in 28 | .noteItem(for: item, on: site) 29 | } 30 | ) 31 | } 32 | 33 | private static func noteItem(for item: Item, on _: Blog) -> Node { 34 | return .section( 35 | .ul( 36 | .li( 37 | .a( 38 | .href(item.path), 39 | .text(item.title) 40 | ) 41 | ) 42 | ) 43 | ) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Sources/Blog/BlogTheme/Nodes/Notes/Topic.swift: -------------------------------------------------------------------------------- 1 | import Publish 2 | import Foundation 3 | 4 | struct Topic { 5 | let name: String 6 | var items: [Item] 7 | } 8 | 9 | extension Topic { 10 | static func group(items: [Item]) -> [Topic] { 11 | var topicsByName: [String: Topic] = [:] 12 | 13 | for item in items { 14 | let topicIdentifier = item.metadata.topic.lowercased() 15 | if topicsByName[topicIdentifier] == nil { 16 | topicsByName[topicIdentifier] = Topic(name: item.metadata.topic, items: [item]) 17 | } else { 18 | topicsByName[topicIdentifier]!.items.append(item) 19 | } 20 | } 21 | 22 | return topicsByName 23 | .map { $1 } 24 | .sorted { $0.name < $1.name } 25 | } 26 | } -------------------------------------------------------------------------------- /Sources/Blog/BlogTheme/Theme+Blog.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Theme+Blog.swift 3 | // 4 | // 5 | // Created by Povilas Staskus on 1/26/20. 6 | // 7 | 8 | import Publish 9 | import Plot 10 | 11 | extension Theme where Site == Blog { 12 | static var blog: Self { 13 | Theme(htmlFactory: BlogHTMLFactory()) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Sources/Blog/SocialMediaLink.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SocialMediaLink.swift 3 | // 4 | // 5 | // Created by Povilas Staskus on 1/26/20. 6 | // 7 | 8 | import Foundation 9 | 10 | struct SocialMediaLink { 11 | let title: String 12 | let url: String 13 | let icon: String 14 | } 15 | 16 | extension SocialMediaLink { 17 | static var location: SocialMediaLink { 18 | return SocialMediaLink( 19 | title: "Vilnius, Lithuania", 20 | url: "https://en.wikipedia.org/wiki/Vilnius", 21 | icon: "fas fa-map-marker-alt" 22 | ) 23 | } 24 | 25 | static var linkedIn: SocialMediaLink { 26 | return SocialMediaLink( 27 | title: "LinkedIn", 28 | url: "https://www.linkedin.com/in/povilas-staškus-6b10528b", 29 | icon: "fab fa-linkedin" 30 | ) 31 | } 32 | 33 | static var email: SocialMediaLink { 34 | return SocialMediaLink( 35 | title: "Email", 36 | url: "mailto:povilas@staskus.io", 37 | icon: "fas fa-envelope-open-text" 38 | ) 39 | } 40 | 41 | static var github: SocialMediaLink { 42 | return SocialMediaLink( 43 | title: "GitHub", 44 | url: "https://github.com/staskus", 45 | icon: "fab fa-github-square" 46 | ) 47 | } 48 | 49 | static var twitter: SocialMediaLink { 50 | return SocialMediaLink( 51 | title: "Twitter", 52 | url: "https://twitter.com/PovilasStaskus", 53 | icon: "fab fa-twitter-square" 54 | ) 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Sources/Blog/main.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import Publish 3 | import Plot 4 | import SplashPublishPlugin 5 | 6 | try Blog().publish(using: [ 7 | .installPlugin(.splash(withClassPrefix: "")), 8 | .addMarkdownFiles(), 9 | .copyResources(), 10 | .generateHTML(withTheme: .blog), 11 | .generateRSSFeed(including: [.posts]), 12 | .generateSiteMap(), 13 | .deploy(using: .gitHub("staskus/staskus.github.io")), 14 | ]) 15 | 16 | --------------------------------------------------------------------------------