Skip to main content

β€’ Loading...

I worked as a full-time Mini App researcher intern at Karrot (Korean Unicorn Company πŸ‡°πŸ‡·πŸ¦„). This is what I found and learned from it.

πŸ“± Mini Apps​

Mini Apps are a collection of third-party services that run on top of a native Super App.

info

Imagine the Shopify app hosting thousands of small shopping mall web apps. You sign in once, and you can access all the apps. No need to log in, no need to download, no need to update; it goes beyond Shop Pay, which simply provides a payment gateway. There could be a Game Super App that hosts thousands of mini-games, a Shopping Super App that hosts thousands of mini-shopping malls, a Social Super App that hosts thousands of mini-social networks, and so on.

How is this different from the status quo? You can get the best of both worlds; deploy it as an app (gets the best retention and metrics) with making a web (simple JavaScript development)

At the same time, you can use Super App's complete account and wallet information (no need to sign up or bother to enter data)

Therefore,

  • it is faster than making an app
  • it reaches more demographic than making a web
  • it can target more user base than making an app
  • it guarantees unparalleled reachability, retention, and payment conversions.

The so-called BAT (Baidu, Alibaba, and Tencent) is already dominating the Chinese market. WeChat, the first player in the market, already has a Mini App ecosystem of 400 million active daily users and 900 million active monthly users. Apple and Google are struggling to maintain their platform power in the Chinese market because of these Mini Apps. For Chinese users, the App Store and the Play Store are like Internet Explorer. Just as IE only exists to download Chrome, so the App Store and the Play Store are simply gateways for downloading WeChat.

Of course, international businesspeople have reacted by replicating this outside of China. Snap tried to create Snap Mini, and Line tried to implement Line Mini Apps. Karrot, a Korean Unicorn company that has 60% of Korean citizens as their user base, also wants to become a Super App and create a Mini App environment. Offering more information on the Mini App system is out of the scope of this post; please refer to Google's in-depth review on Mini Apps.

πŸ’‘So far
  • A Mini App is easy to make (web-like developer experience) while having powerful business effects (app-like user experience).
  • Karrot wants its internal and external partners to provide service through the Mini App within the Karrot App.
  • Karrot thinks that all Super Apps will want to make Mini App Systems and that there will be repeated work and fragmented developer experience if all the Super Apps make their own Mini App systems.
  • Goal. Figure out a Mini App Model that will succeed in Korea, Japan, United States, United Kingdom, and so on. (Karrot's business regions)

πŸ”₯ For Thriving Ecosystems​

The previously mentioned BAT have created their proprietary languages and browsers, seemingly inspired by the web. These three companies possess immense platform power; they can ask whatever they want from the developers. However, most Super App services cannot justify developers following their demands, like asking devs to use non-standard SDKs or asking for logical branching for detecting a Mini App environment. In that case, developers will give up creating a Mini App to spend that effort on creating an iOS and Android app (which has a much higher chance of success). If you have other thoughts, why is PWA still stagnating? Therefore, a standard Mini App should follow the web standard. Developers should deploy their web app as a Mini App with little to no change.

😻 For Beautiful Interfaces​

Having a pretty design is much more important than you think. This statement is especially true for permission request screens. If, for example, a service requires location without context, the user will likely decline, affecting the service's stability. I mean that permission requests should make sense, for which we require persuasive interfaces and designs. Therefore, it needs to be pretty.

Let us take Starbucks as an example. The following image shows permission requests from Starbucks Web, App, and Mini App. Which one do you think you will grant? Which one will you decline?

Web

Web

Mini App

Mini App

App

App

Most users will likely grant our request as we go to the right, given more details. A standard Mini App should at least provide the context level of the middle screenshot.

πŸ“¨ For Prettier Permission Requests​

The geolocation permission requests mentioned above display whenever JavaScript calls the Geolocation API. It's not magic β€” executing the following code will prompt the permission request.

navigator.geolocation.getCurrentPosition()

Based on backgrounds 1 and 2, we would need to provide a more persuasive and prettier permission request when we execute the above code, based on the Web Standards.

🌐 But Isn't That the Browser's Job?​

Yes, displaying such a request screen falls under the browser's responsibility. Therefore, we will meet the above permission request if we call the Geolocation API inside a Web View (specifically, WKWebView for iOS). This behavior also happens inside Karrot Mini, an intermediary version of the Mini App system built by Karrot. So, how can we solve this? Do we plan on making a new browser?

Even worse, an unknown URL can urge people to deny such a request.

Even worse, an unknown URL can urge people to deny such a request.

🎭 We don't care who's who​

For web apps, 99.99% don't care who's who. They call the function wherever they need it. So, what if we make a fake navigator like the following?

const navigator = {
geolocation: {
getCurrentPosition(success, error) {
// do some random stuff...
},
},
}

JavaScript does not check for the authenticity of the navigator. Therefore, we can inject whatever behavior we want. This methodology is called Shim.

In computer programming, a shim is a library that transparently intercepts API calls and changes the arguments passed, handles the operation itself, or redirects the operation elsewhere. β€” Shim (computing) - Wikipedia

I have created a demo website where a cat gif asks for location permission.

Default behavior

Default behavior

Injected behavior

Injected behavior

If we advance this methodology and implement the Document Object Model in JavaScript, we can inject all behaviors that are deemed suitable for Mini Apps.

πŸ—Ώ For Consistent Experiences​

A Mini App is all about a consistent experience. It's akin to universal components like Refresh, Favorite, or Close buttons not changing in browsers when you navigate different websites. For more information on consistent experiences, please refer to Google's Mini App User Experiences document. Of course, this consistency will require us to inject standard components.

⚑️ For Snappy Experiences​

Opening and closing different Mini Apps should at least be faster than websites, if not faster than their app versions. For this, we would need prefetching policies for Mini Apps. We also want data persistency when opening and closing apps so we can contain the Mini App inside an iframe and delegate the managing to the Super App's web view. This procedure will also require implementing crossOriginIsolated, Cross-Origin-Opener-Policy, and Cross-Origin-Embedder-Policy headers so that the codes inside the iframes will not have access to data outside.

πŸ₯Ά How'd You Solve the Icing Problem?​

Super App force-quitting frozen Mini App

Super App force-quitting frozen Mini App

There's another problem here: The iframe works on a single thread, so when the Mini App freezes, the entire Super App will also freeze, including the quit button.

πŸ•Έ Multi-threaded Web​

πŸ€”Isn't JavaScript Single-Threaded?

Correct and wrong.

  • JavaScript inside a browser is single-threaded.
  • We can, however, create multiple threads with web workers.

Then, if we run our iframe inside the web worker, the Super App will effectively solve the icing problem.

πŸ§‘β€πŸ”§ No DOM APIs in Workers​

Web workers do not have access to DOM APIs. However, just like our shimming the Geolocation API, the DOM API is also an Object Model written in JavaScript. Therefore, we would effectively solve this problem if we could provide the fake DOM API inside the web worker and mirror the manipulations to the real DOM. Also, we can police the manipulations between the two DOM APIs by verifying if this operation is permitted or not.

πŸ‘» Mission Impossible​

In the film Mission Impossible 4, the protagonist, Ethan, acts like each other in between two terrorist groups, negotiating them in Ethan's favor.

In the film Mission Impossible 4, the protagonist, Ethan, acts like each other in between two terrorist groups, negotiating them in Ethan's favor.

Luckily, there is previous research conducted. Google created WorkerDOM for their Accelerated Mobile Pages, and BuilderIO created Partytown to separate 3rd-party codes from web workers. However, none of them is fully appropriate for Mini Apps. Google started WorkerDOM when Spectre security vulnerability was a thing and did not utilize SharedArrayBuffer and Atomics. Therefore, WorkerDOM cannot make synchronous data transfers (elaborated later). Partytown cannot Event Prevent Default. But fundamentally, we can use this Mission Impossible model to isolate and quarantine third-party codes.

πŸ’½ No Synchronous Data Transfer​

Web Workers do not have synchronous data transfer by default. Synchronous data transfer is essential for many places; for example, drawing animations or displaying a map on the screen requires it because we need to calculate the pixels on the screen to render the next frame. However, since we do not have synchronous DOM APIs inside of Workers, all of the animation codes will not respond.

🀝 Then Make It Synchronous!​

JavaScript was meant to be asynchronous from the beginning due to user interactions. That is why we have the notorious triumvirate: callbacks, promise, async/await. Synchronously performing such asynchronous JavaScript means that if I call a specific function, the entire operation will sit there and wait until it gets the response.

We can make this synchronous using the following two methods.

  1. Synchronous XMLHttpRequest
  2. SharedArrayBuffer and Atomics
    • SharedArrayBuffer is a shared data channel between Web Worker and the main thread. The Atomics operation ensures thread safety in such mutual operations. At the same time, it means we can pause the Worker thread, harnessing the power of Atomics. Mini Apps already use Web Workers, so using SharedArrayBuffer and Atomics seems more suitable.

βœ‚οΈ Oops, You Got Disconnected​

We cannot access the regular web environment offline. For example, if we have a calculator Mini App, we expect it to work without network access. This condition also tightly relates to initial loading speeds. Although we can use progressive web apps to cache the website offline, it also requires plenty of initial network requests to cache it, deeming it inefficient.

πŸ“¦ Pack it up!​

Source: web.dev/web-bundles

Source: web.dev/web-bundles

There is also a solution. Google is already experimenting with WebBundle, based on the CBOR file format. WebBundle contains all the necessary files for the web, including HTML, CSS, JS, and images, into one file. WebBundle is already enabled in Chrome, and Google is experimenting with this technology in various ways. But sadly, Google's hidden goal is to disarm and bypass URL-based adblocking technologies. Related Thread.

🦠 What if it gets malicious code?​

A perfectly fine code on GitHub can suddenly become an attacking code in NPM. For example, UAParser.js, a popular library marking 40M+ monthly downloads, once got hacked and distributed malicious codes. Accident Records.

Such a trustful library with big names can suddenly hit you back.

Such a trustful library with big names can suddenly hit you back.

Essential in any way, the Super App provider should get the package from Mini App providers, audit them, and host by themselves so that others cannot swap out codes. However, there is very little to say because this part of the system is developed almost wholly.

😊 Conclusion.​

If we solve all the abovementioned problems, we can finally construct a proper Mini App environment. However, as you can tell, each issue exhibits a vast range of technical and administrative challenges. I focused on problems #2 and #3 during my internship, but the resource was extremely scarce since it delved into such a niche area of interest. I imagine seeing a Mini App environment that is β‘  internationally accessible β‘‘ scalable β‘’ interoperable with Web Standards β‘£ and maximizing values for creators and users without being confined to a specific geographic region like China.

But the challenges will only delay our joyful union.

β€’ Loading...

tossface.cho.sh

tossface.cho.sh

info

I would like to thank @sudosubin and the Tossface team for reviving Korean emojis with Unicode PUA!

Background​

Tossface is an emoji font face a Korean (almost) Decacorn company, Viva Republica, created. Tossface initially included a series of intentionally divergent emoji designs, replacing culturally specific Japanese emojis with designs representing related Korean concepts and outdated technologies with contemporary technologies.

Tossface's first release. Toss: "Right Now, The Right Us (Hinting Modern & Korean Values)"

Tossface's first release. Toss: "Right Now, The Right Us (Hinting Modern & Korean Values)"

Unfortunately, these replacements caused backlash from multiple stakeholders, and Viva Republica had to remove the emojis.

Unicode Private Use Area​

However, there is a hidden secret in Unicode; There is a unused, hidden area from U+E000-F8FF, U+F0000-FFFFD, U+100000-10FFFD, which is known as Unicode Private Use Area. This area will remain unassigned for standard emojis, and companies can use it at their own will.

Regrettably, those letters with Korean and contemporary style in a clean and neat tone and manners disappeared into history. Therefore, I have proposed returning the emojis using a standard technology known as Unicode Private Area.

@toss/tossface/issues/4

@toss/tossface/issues/4

After about three months, Viva Republica accepted the request. They redistributed those emojis in Tossface v1.3, from PUA U+E10A to U+E117.

But how shall I type?​

However, these emojis remained uncharted in the Unicode standard. PUA U+E10A to U+E117 cannot be inputted with the standard keyboard, nor does it appear on the emoji chart. Ironic that we finally got the glyphs back but can't type.

So I have created a small website where you can check the glyphs and copy them. I call these Microprojects. They're perfect for trying out new technologies; I wanted to try Astro, but it kept giving me unrecognizable errors primarily because the platform was still in an early stage, so I used Next.js, Vercel, and Tailwind.

Now, it somehow became a Museum of Korean Culture​

After creating the website, it now looked like a Museum of Korean Culture, so I added some text in English and shared it publicly.

Page View Nationality Break Down

Page View Nationality Break Down

Postmortem​

It was a fast and fun project before the beginning of school!

β€’ Loading...

Overview​

It's more about how to take thorough notes habitually.

It is about optimizing a system outside yourself, a system not subject to your limitations and constraints, leaving you happily unoptimized and free to roam, to wonder, to wander toward whatever makes you feel alive here and now in each moment.

The origin goes back to the commonplace book used by ancient scholars. They always carried a commonplace book, taking notes like a canvas synced with their brain. The so-called second brain is recreating the same concept on a digital device. Then, we can use such notes as cheat sheets for our lives. But in the real world, you can never expect what type of exam you'll face, what topics it will cover, and what answer it will require. This book gives one methodology for such a problem.

Functions​

A second brain can:

  • Detail ideas.
  • Interrelate ideas.
  • Incubate ideas.
  • Sharpen perspectives.

Methodology​

  • Author suggests CODE procedure.

Capture​

  • Create my knowledge repository.
  • Each knowledge unit can take multiple formats. Posts, pictures, bookmarks, voice recordings, meeting notes, etc.
  • Make 12 questions that revolve around you.
  • When capturing, find relations with the 12 questions.
    • Ex: What does moving from mindless consumption to mindful creation look like?
  • Do not over-collect.
  • Do not collect what you already know. Beware of the confirmation bias.

Organize​

  • Do not over-organize.
  • You don't need a sophisticated structure for sophisticated work.
    • For example, tagging takes too much effort.
  • Author suggests PARA. Refer to the note.

Organizing was similar to Data Structures in Computer Science. If you sort too less, it costs too much to search. If you optimize too much for search, sorting takes too long. It would be best if you had a middle ground. I am skeptical on PARA. Area and Resource feel redundant. I simplified it into Projects, Research, and Readings. The author claimed that classifying such things as Readings and Quotes as their own is like organizing food ingredients by their color. However, I think it makes sense to occasionally separate Readings.

Distill​

  • Keep the essence, remove everything else
  • Remove redundancy and details
  • You can always fall back on the source. Have no regret; remove them brutally.

Express​

  • Take advantage of Intermediate Packets. Notes, projects, docs, and plans serves as nutrition for your creative activity

Habits for creation​

  • Creative process is ancient and unchanging.
  • Use Intermediate Packets to overcome the fear of blank paper.
  • Convert yesterday's momentum into today's momentum.
  • Make wrap-up rituals.
    • Post-mortem questions. What did you learn? What did it leave? What can you improve?
    • Talk with stakeholders.
    • Numeric your success.
    • Celebrate
  • Regularly review notes.
  • Start today.

β€’ Loading...

After a few years of technical writing, I felt limitations on writing platforms that hindered me from writing the best-class articles. Technological knowledge is dynamic and intertwined in that none of the current formats – academic papers, lecture videos, code examples, or straightforward posts – can best represent the knowledge. I have examined and observed some attempts that addressed this issue, namely, stuff called the second brain or digital gardens, but none of them seemed to correctly solve the problem. Therefore, I have distilled my inconveniences into this huge mega-post and imagined what I would've done if I had created the new incarnations of digital brains.

Update 2022-06-12

Since this post, I have extensively studied non-linear PKM software, such as Roam, Obsidian, Logseq, and Foam. I acknowledge that I misunderstood the concept of manual linking; that PKM software performs a fuzzy search to intelligently identify linked and unlinked references. I found some PKM software with automatic linkings, such as Saga or Weavit. But none of them worked how I expected. Manual linking helps refine the database. So, even if I make a Next-gen digital brain, I will not remove the linking process.

Update 2022-07-01

Well, you're now watching my next-gen digital brain! For the past two weeks, I have worked on the WWW project that built this website. It checks off almost all of the marks detailed in this post!

TL;DR
  • Create an aesthetic-interactive-automatic pile of code-image-repo-text that organizes-presents-pitches itself.
  • There is no manual tagging, linking, or image processing, etc., etc.
  • You just throw a random knowledge; creating a knowledge mesh network.
  • The algorithm operates everything. It will be contained, processed, organized, and distributed all around the world in different languages.
  • You don't tend knowledge. The algorithm penalizes outdated content (you can mark the post as evergreen to avoid this.)

So what's the issue?

  • Apart from popular belief, I noticed the best method for managing a digital garden is not tending it. Instead, try to make a digital jungle – you don't take care of it; nature will automatically raise it.
  • In other words, the digital brain should make as less friction as possible.
  • The less you tend, the more you write.

Especially,​

  • I despise the [[keyword]] pattern prevalent in so-called second brains (obsidian, dendron, ...).
  • Not to mention it performs poorly for non-alphabetical documents,
  • It is manual – creates a lot of friction.
  • The fact that you must explicitly wrap them with brackets doesn't make sense... What if you realize you want to make a linkage to a term you've been writing for 200 posts?
  • Do you go back and link them all one by one?
  • No! The solution must lie in algorithmic keyword extraction.

#1 Organizing Contents

Interconnected entities​

  • Practical knowledge does not exist in simple posts (though they might be straightforward). Create a knowledge bundle that interconnects GitHub Repository, Codes, GitHub README, and other posts in the same brain network.
  • Examine how Victor's post has rich metadata for the paper, dataset, demo, and post. This is what I see as interconnected entities.

Interactive Contents & Animations​

victordibia.com. Seems like using MDX.

victordibia.com. Seems like using MDX.

bluewings.github.io. Confirmed using MDX.

bluewings.github.io. Confirmed using MDX.

pomb.us. Reacts to user scroll.

pomb.us. Reacts to user scroll.

qubit.donghwi.dev. This isn't a blog; it's a web app that demonstrates key concepts of Quantum Computers. But still interesting.

qubit.donghwi.dev. This isn't a blog; it's a web app that demonstrates key concepts of Quantum Computers. But still interesting.

Unorganized Graphing.​

  • Trust me, manually fiddling with tag sucks.

  • Necessarily tagging posts and organizing posts into subdirectories resembles organizing your computer.

  • However, you wouldn't want to do this if you have thousands of posts; also the border gets loose. What if the post has two properties? What becomes the primary tag and what becomes the secondary tag?

  • Students who grew up with search engines might change STEM education forever

  • Notable trends. Gen Z's don't organize folders anymore!

  • Recent trends, I would say, are dumping everything into a mega folder and searching up things whenever needed.

  • I also used to organize folders a lot more, but recently as searches like Spotlight and Alfred improve, I don't see the need to manage them all by hand, considering I always pull up those search commands to open a file.

  • You don't need to manually organize all of the files when algorithms can read all the texts and organize them for you!

  • Use algorithmic inspections to analyze how the posts may interrelate with each other properly.

Velog.io, the Korean version of dev.to, links relevant posts for every post.

Velog.io, the Korean version of dev.to, links relevant posts for every post.

Example of backlinking from Dendron

Example of backlinking from Dendron
  • I agree with the importance of interlinking knowledge crumbles, but I can't entirely agree with their method.
  • Manually linking posts are inconsistent and troublesome; it can only be done on a massive communal scale, like Wikipedia.
  • You cannot apply the same logic to individual digital brain systems.

#2 SEO and Open Graphs

Precis Bots for Meta description​

  • I can apply the above technique for crosslinking to TL;DR bots for meta tag descriptions.

Automatic Open Graph Image Insertion​

  • For example, GitHub creates automatic open graph images with their metadata.

Example open graph image from GitHub

Example open graph image from GitHub
  • There are quite some services using this technique.
  • GitHub wrote an excellent post on implementing this feature.
  • I also tried to implement this on top of Ghost CMS, which I gave up after figuring out the Ghost Core Engine should support this. However, I have created a fork that I can extend later. http://og-image.cho.sh/

GitHub - anaclumos/cho-sh-og-image: Open Graph Image as a Service - generate cards for Twitter, Facebook, Slack, etc

#3 Multilanguage

Proper multilanguage support​

  • Automatic Langauge Detection. The baseline is to reduce the workload, that I write random things, and the algorithm will automatically organize corresponding data.
  • hreflang tags and HTTP content negotiations. I found none of the services which use this trick properly (outside of megacorporate i18n products)

Translations​

  • At this point, I might write one English post and let Google Translate do the heavy lifting.
  • Also, I can get contributions from GitHub.

While supporting multilanguage and translations, I want to put some 3D WebGL globe graphics. Remember infrastructure.aws in 2019? It used to show an awesome 3D graphic of AWS's global network.

I kind of want this back too. Meanwhile, this looks nice:

Also made some contributions...

Fonts and Emoji​

  • I want to go with the standard SF Pro series with a powerful new font Pretendard.
font-family: ui-sans-serif, -apple-system, BlinkMacSystemFont,
'Apple SD Gothic Neo', Pretendard, system-ui -system-ui,
sans-serif, 'Apple Color Emoji';
  • However, I am exploring other options.
  • I liked TossFace's bold attempt to infuse Korean values into the Japan-based emoji system for emoji. (lol, but they canceled it.)

Tossface Original Emojis

Tossface Original Emojis

#4 Domains and Routes

URL Structures​

  • Does URL Structure matter for SEO? I don't think so if the exhaustive domain list is provided through sitemap.xml.
  • For SEO purposes (although I still doubt the effectiveness), automatically inserting the URLified titles at the end might help (like Notion)

Nameless routes​

I don't like naming routes like cho.sh/blog/how-to-make-apple-music-clone. What if I need to update the title and want to update the URL Structure?

  • Changing URL structure affects SEO, so I would need to stick to the original domain even after changing the entity title to maintain the SEO. But then the title and URL would be inconsistent.
  • Therefore, I would give the entity a UID that would be a hash for each interconnected entity. Maybe the randomized hash UID could be a color hex that could be the theme color for the entity?
  • Emoji routes seem cool, aye? I would also need Web Share API since Chrome doesn't support copying Unicode URLs.
  • Some candidates I am thinking of:
  • cho.sh/β™₯/e5732f/ko
  • cho.sh/🧠/e5732f/en

Also found that Twitter doesn't support Unicode URLs.

Also found that Twitter doesn't support Unicode URLs.

#5 Miscellany

Headline for Outdated Posts​

  • There should be a method to penalize old posts; they should exist in the database but wouldn't appear as much on the data chain. i.e., put a lifespan or "valid until" for posts.

홍민희 λΈ”λ‘œκ·Έ

홍민희 λΈ”λ‘œκ·Έ

Kat Huang

Kat Huang

Footnotes​

  • An excellent addition. But not necessary.
  • If I ever have to make a footnote system, I want to make it hoverable, which namu.wiki did a great job. I do not want to make it jump down to the bottom and put a cringy ↩️ icon to link back.

ToC​

  • A nice addition. But not necessary.

Comments​

  • Will go with Giscus.

This also looks cool for MD/MDX

β€’ Loading...
  • Imagine there is a function bool doesItHalt({function f, input i}) that returns if the parameter function f(i) halts or not.
  • Now consider the following functions:
pair duplicator(input i) {
return {i, i}
}

bool invertHalt(bool b) {
if(b) {
while(true); // hangs forever
return 0;
} else {
return 0;
}
}
  • Essentially, if f(i) halts, the invertHalt will hang (i.e., wouldn't halt), and if f(i) hangs, the invertHalt will halt.
  • Let us consider the composition of the two functions:
bool unknown(input i) {
auto a = duplicator(i) // a = {i, i}
auto b = doesItHalt(a) // does i(i) halt?
auto c = invertHalt(b) // hangs if i(i) halts and vice versa.
}
  • Will unknown(unknown) halt? What should doesItHalt({unknown, unknown}) return?
  • Let us suppose it will return true. Then, it means that doesItHalt({unknown, unknown}) returned false because invertHalt(b) would've hung otherwise. Therefore, this contradicts our supposition that doesItHalt({unknown, unknown}) returns true.
  • Let us suppose it will return false. Then, it means that doesItHalt({unknown, unknown}) would return true because invertHalt wouldn't hang otherwise. Therefore, this contradicts our supposition that doesItHalt({unknown, unknown}) returns false.
  • Therefore, unknown cannot hang nor halt; therefore, no such doesItHalt can exist.

β€’ Loading...

Path for Karabiner Advanced Settings​

~/.config/karabiner/assets/complex_modifications/keyboard.json
tip

See https://github.com/anaclumos/karabiner.json/ for more up-to-date configs.

// `keyboard.json`
{
"title": "Caps Lock β†’ Hyper Key (control+shift+option) (F16 if alone)",
"rules": [
{
"description": "Caps Lock β†’ Hyper Key (control+shift+option) (F16 if alone)",
"manipulators": [
{
"from": {
"key_code": "caps_lock"
},
"to": [
{
"key_code": "left_shift",
"modifiers": ["left_control", "left_option"]
}
],
"to_if_alone": [
{
"key_code": "f16"
}
],
"type": "basic"
}
]
}
]
}
// `hyper.json`
{
"title": "Hyper Key Combinations",
"rules": [
{
"description": "Use Hyper + D to F13",
"manipulators": [
{
"type": "basic",
"from": {
"key_code": "d",
"modifiers": {
"mandatory": ["left_shift", "left_control"]
}
},
"to": [
{
"key_code": "f13"
}
]
}
]
},
{
"description": "Use Hyper + E to control + up_arrow",
"manipulators": [
{
"type": "basic",
"from": {
"key_code": "e",
"modifiers": {
"mandatory": ["left_shift", "left_control"]
}
},
"to": [
{
"key_code": "up_arrow",
"modifiers": ["left_control"]
}
]
}
]
}
]
}
// `language.json`
{
"title": "Multilingual Input Methods",
"rules": [
{
"description": "R Command to Gureum Han2",
"manipulators": [
{
"type": "basic",
"from": {
"key_code": "right_command",
"modifiers": {
"optional": ["any"]
}
},
"to": [
{
"key_code": "right_command",
"lazy": true
}
],
"to_if_alone": [
{
"select_input_source": {
"input_source_id": "org.youknowone.inputmethod.Gureum.han2"
}
}
]
}
]
},
{
"description": "L Command to Gureum Roman",
"manipulators": [
{
"type": "basic",
"from": {
"key_code": "left_command",
"modifiers": {
"optional": ["any"]
}
},
"to": [
{
"key_code": "left_command",
"lazy": true
}
],
"to_if_alone": [
{
"select_input_source": {
"input_source_id": "org.youknowone.inputmethod.Gureum.system"
}
}
]
}
]
}
]
}

Then I configured a bunch of shortcuts to fly through my Mac. Remember βŒƒβŒ₯⇧ is the so-called Hyper Key that I made, which uses the Caps Lock key or ν•œ/영 ν‚€ (Korean-English Key). That is, because, I never use the Caps Lock key (I use shift) and I click the right command key to type Korean and click the left command key to type English, inspired by the Japanese Apple keyboard's Kana (かγͺ) and English Key (θ‹±ζ•°).

Rectangle.app

Rectangle.app

Keyboard Maestro.app

Keyboard Maestro.app

gureum.app

gureum.app

β€’ Loading...

P: Poly-time Solvable​

  • Class of solvable and verifiable problems in polynomial time by a deterministic Turing machine.

NP: Nondeterministic Polynomial Time​

  • Class of problems that are not sure if it's solvable in polynomial time but verifiable in polynomial time.
  • To prove that a problem is in NP, we need an efficient certification: a certificate (a potential solution to the problem) and a certifier (a way to verify the answer in polynomial time).

NP-Hard: Nondeterministic Polynomial Time-Hard​

  • It means "at least as hard as the hardest problems in NP."
  • Not sure if it's solvable in poly-time.
  • Not sure if it's verifiable in poly-time.
  • To prove that a problem is NP-hard, we need to show that it is poly-time reducible to another NP-hard problem. That is, reduce another NP-hard problem in it.

NP-Complete​

Both NP and NP-Hard.

β€’ Loading...

One way that doesn't work: Using environment variables​

  • If you click the app name from the top bar in Xcode, you can edit scheme.

edit scheme

edit scheme
  • You can try settings values at Run β†’ Arguments β†’ Environment Variables and access them through ProcessInfo.processInfo.environment["KEY"].

ProcessInfo.processInfo.environment["KEY"]

ProcessInfo.processInfo.environment["KEY"

One possible but unsafe way: xcconfig​

  • Create .xcconfig and add them to app build settings.
  • Is it safe? No!

Another possible buy unsafe way: .gitignore​

  • I just made a .gitignore that ignores all *Credentials.swift file.
  • Is it safe? No!
  • However, I am using LinkedIn API that makes a network request.
  • Anyone who will take the effort to decompile the app and extract the API key data will attack the network request and extract the key.
  • I concluded security beyond not disclosing them through the source control system is meaningless for my use case.

One possible and safe way: Secure Enclaves.​

Another possible (and probably the correct) way​

  • Just don't store that level of sensitive information on the client.

Another another possible way that might be worth exploring​

Advanced Readings​

β€’ Loading...

I recently saw this Gist and Interactive Page, so I thought it would be cool to update it for the 2020s. This can serve as a visualization of how fast a modern computer is.

How to read this calendar​

Imagine 1 CPU cycle took 1 second. Compared to that, A modern 4.0 GHz CPU has a CPU cycle of 0.25 ns approx. That's 4,000,000,000 times difference. Now, imagine how that CPU would feel one second in real life.

ActionPhysical TimeCPU Time
1 CPU Cycle0.25ns1 second
L1 cache reference1ns4 seconds
Branch mispredict3ns12 seconds
L2 cache reference4ns16 seconds
Mutex lock17ns68 seconds
Send 2KB44ns2.93 minutes
Main memory reference100ns6.67 minutes
Compress 1KB2ΞΌs2.22 hours
Read 1MB from memory3ΞΌs3.33 hours
SSD random read16ΞΌs17.78 hours
Read 1MB from SSD49ΞΌs2.27 days
Round trip in the same data center500ΞΌs23.15 days
Read 1MB from the disk825ΞΌs38.20 days
Disk seek2ms92.60 days
Packet roundtrip from California to Seoul200ms25.35 years
OS virtualization reboot5s633 years
SCSI command timeout30s3,802 years
Hardware virtualization reboot40s5,070 years
Physical system reboot5m38,026 years