{"version":"https://jsonfeed.org/version/1","title":"Memories Mapped to Web Pages","home_page_url":"https://mmap.page/","feed_url":"https://mmap.page/feed.json","items":[{"id":"https://mmap.page/thoughts/hakuraku/","url":"https://mmap.page/thoughts/hakuraku/","title":"Following the Map to Find a Horse","content_html":"<h1>Following the Map to Find a Horse</h1>\n<p>People say, \"Only when there is Hakuraku<sup><a href=\"https://mmap.page/thoughts/hakuraku/#user-content-fn-0\" id=\"user-content-fnref-0\" data-footnote-ref aria-describedby=\"footnote-label\">1</a></sup> in the world can there be chollima<sup><a href=\"https://mmap.page/thoughts/hakuraku/#user-content-fn-1\" id=\"user-content-fnref-1\" data-footnote-ref aria-describedby=\"footnote-label\">2</a></sup>,\" which suggests that \"chollima\" is Hakuraku's invention.\nIf horses had consciousness, they would probably despise the concept of chollima.\nThe fortunate horses gallop freely in the wilderness, expressing their true nature; the unfortunate ones, though confined to stables, at least preserve their lives.\nHowever, the \"chollima\" favored by Hakuraku must follow generals on campaigns, facing constant dangers and extraordinary hardships.\nWhen they finally die, if their rider has some conscience and plans a grand burial, he might even be dissuaded:<br>\n\"The sage Confucius did not concern himself with horses.\nIf you, my lord, lavishly bury a horse, it will dishearten the people<sup><a href=\"https://mmap.page/thoughts/hakuraku/#user-content-fn-2\" id=\"user-content-fnref-2\" data-footnote-ref aria-describedby=\"footnote-label\">3</a></sup> who follow you.\nBetter to cut it into small pieces and distribute the meat to everyone—let the iron pot serve as the coffin and stomachs as graves.<br>\nThis is the proper funeral for a horse.\"</p>\n<p>Therefore, \"Hakuraku is not always present\" is truly a stroke of luck.\nIf Hakuraku were always around, who knows how many more \"chollima\" would die unnatural deaths?\nJust as the Literary Chinese idiom \"懷才不遇\" (having talent but not having an opportunity) also describes a stroke of luck.\nWealth comes after talents,\nas in Literary Chinese the kanji \"才\" (talent) can be used as the kanji \"財\" (wealth), so the Literary Chinese idiom \"懷才不遇\" (having talent but not having an opportunity)\ncan be interpreted as \"懷財不遇(盜)\" (having wealth but not having an opportunity to be robbed).\nIf someone carries a fortune and walks alone in the dark of night without meeting robbers or thieves, that is indeed fortunate.</p>\n<p>If one is incompetent, they are even more lucky.\nIf a horse is incompetent, even when Hakuraku approaches, it need not fear.\nIt's like a poor person walking at night—those who would rob for wealth have nothing to target.<sup><a href=\"https://mmap.page/thoughts/hakuraku/#user-content-fn-3\" id=\"user-content-fnref-3\" data-footnote-ref aria-describedby=\"footnote-label\">4</a></sup></p>\n<p>In the 7th volume of <em>Planting Seeds in Forests and Cultivating Virgin Soil in Mountains</em>,<sup><a href=\"https://mmap.page/thoughts/hakuraku/#user-content-fn-4\" id=\"user-content-fnref-4\" data-footnote-ref aria-describedby=\"footnote-label\">5</a></sup> there is a story about \"following the map to find a horse\":</p>\n<blockquote>\n<p>Hakuraku's <em>Manual of Horse Evaluation</em> contains the phrase \"a high forehead, a pair of big and round eyes,<sup><a href=\"https://mmap.page/thoughts/hakuraku/#user-content-fn-5\" id=\"user-content-fnref-5\" data-footnote-ref aria-describedby=\"footnote-label\">6</a></sup> big and regular hooves.\"\nHis son went to search for horses based on the <em>Manual</em>.\nWhen he saw a large toad, he told his father: \"I found a horse that closely matches the description, except the hooves are a bit irregular.\"\nKnowing his son's foolishness, Hakuraku turned his anger into laughter and said: \"This horse is too good at jumping to ride on.\"</p>\n</blockquote>\n<p>Hakuraku's son, following his father's <em>Manual</em>, found a toad.\nI prefer to believe this was his way of expressing to Hakuraku that he refused to evaluate horses.\nHaving spent his life evaluating horses, Hakuraku's son probably grew up in the company of horses.\nAs a child, he might not have understood what \"thousand-li ability\" meant.\nWhat the child saw were one adorable horse after another, one horse after another that was kept for a while and then sent away, and one horse after another that perished on battlefields and buried in human bellies.\nNaturally, he could not approve of what Hakuraku has done and certainly did not wish to evaluate horses himself.\nSo he found a toad instead.\nThis was Hakuraku's son's foolishness.\nHakuraku had once recommended another famous horse tamer Nonapath<sup><a href=\"https://mmap.page/thoughts/hakuraku/#user-content-fn-6\" id=\"user-content-fnref-6\" data-footnote-ref aria-describedby=\"footnote-label\">7</a></sup> to Duke of Cin <sup><a href=\"https://mmap.page/thoughts/hakuraku/#user-content-fn-7\" id=\"user-content-fnref-7\" data-footnote-ref aria-describedby=\"footnote-label\">8</a></sup>, showing that he was also skilled at evaluating people, so he understood his son's intention.\nThat's why he \"turned his anger into laughter.\"\nFirst came anger, then helpless, bitter laughter.\n\"This horse is too good to ride on\" was his metaphor showing that he understood his son's meaning—horses are by nature unruly and out of human control.</p>\n<p><em>English translation by GPT-4.1 and proofread by Gemini 2.5 Pro and weakish.</em></p>\n<h1>按圖索驥</h1>\n<p>人道「世有伯樂，然後有千里馬」，可見「千里馬」是伯樂的發明。\n「千里」云云，馬若有知，恐不以爲然。\n馬之幸者，馳騁於曠野，盡其天性；不幸者，雖處槽櫪之間，猶得全生。\n然而被伯樂相中的「千里馬」，卻是隨將帥四處出征，危機四伏，艱險異常。\n最後死了，主人有點良心，打算厚葬，說不定還會遭到謀士的勸阻：</p>\n<blockquote>\n<p>「孔聖人不問馬，主公您厚葬馬，會讓跟隨您的士人寒心呀。\n不如割成小塊，分給大家吃了，鐵鍋作棺槨，腸胃爲墓地，這纔是馬該有的葬禮呀。」</p>\n</blockquote>\n<p>所以「伯樂不常有」，實在是幸事。\n倘若伯樂常有，不知又會有多少「千里馬」死於非命。<br>\n就像「懷才不遇」也是幸事。\n「才」通「財」，「懷才不遇」，便是「懷財不遇盜」。\n若是一人攜帶巨款暗夜獨行，沒碰上強盜小偷，那實在是幸事。</p>\n<p>若是無能，那就更幸運。馬若無能，伯樂走到跟前，也不懼。\n好比窮醜之婦夜行，劫財劫色者皆無從下手。</p>\n<p>明楊慎《藝林伐山》卷七裏有一個「按圖索驥」的故事：</p>\n<blockquote>\n<p>伯樂《相馬經》有「隆顙蛈日，蹄如累麴」之語，其子執《馬經》以求馬，\n出見大蟾蜍，謂其父曰：「得一馬，略與相同；但蹄不如累麴爾。」\n伯樂知其子之愚，但轉怒為笑曰：「此馬好跳，不堪御也。」</p>\n</blockquote>\n<p>伯樂的兒子根據老爸的《馬經》，找到了一枚癩蛤蟆。\n我願意相信，這其實是在向伯樂表態自己不相馬。\n伯樂一生相馬，伯樂之子小時候大抵是與馬爲伴，千里之能什麼的，小孩未必明白。\n小孩眼裏看到的，是一匹又一匹可愛的馬兒，是一匹又一匹養了一段時間就被送走的馬兒，是一匹又一匹喪生沙場、葬於人腹的馬兒。</p>\n<p>因此自然無法認同伯樂的行爲，自己當然更不願相馬。所以便找了一個癩蛤蟆。\n這是伯樂之子的愚處。伯樂曾經推薦九方皋給秦穆公，可見他也善相人，自然明白了其子的意圖，\n所以說是「伯樂知其子之愚，但轉怒為笑」。起初是怒，後來是無奈苦笑。\n「此馬好跳，不堪御也。」便是表明自己心知其子之意，癩蛤蟆是個隱喻——馬性跳脫，不堪爲人所御。</p>\n<section data-footnotes class=\"footnotes\"><h2 class=\"sr-only\" id=\"footnote-label\">Footnotes</h2>\n<ol>\n<li id=\"user-content-fn-0\">\n<p>Hakuraku is the on'yomi (the approximated pronunciations, using Japanese consonants and vowels, of kanji) of 伯樂, a famous horse tamer for the Duke of Cin. His name can also be romanized as Po-le, Po Lo, or Bo Le. <a href=\"https://mmap.page/thoughts/hakuraku/#user-content-fnref-0\" data-footnote-backref=\"\" aria-label=\"Back to reference 1\" class=\"data-footnote-backref\">↩</a></p>\n</li>\n<li id=\"user-content-fn-1\">\n<p>A chollima is a Sino-Korean word 千里馬 which literally means \"horse of the thousand-mile\", refers to a fine steed. <a href=\"https://mmap.page/thoughts/hakuraku/#user-content-fnref-1\" data-footnote-backref=\"\" aria-label=\"Back to reference 2\" class=\"data-footnote-backref\">↩</a></p>\n</li>\n<li id=\"user-content-fn-2\">\n<p>The original text 士 (shi) refers to a special class in the Spring and Autumn period. The English translation simplies this to \"people\" so the reader does not need to understand the role of this class, which is irrelevant to the main idea of this essay. <a href=\"https://mmap.page/thoughts/hakuraku/#user-content-fnref-2\" data-footnote-backref=\"\" aria-label=\"Back to reference 3\" class=\"data-footnote-backref\">↩</a></p>\n</li>\n<li id=\"user-content-fn-3\">\n<p>The original text \"窮醜之婦夜行，劫財劫色者皆無從下手\" literally means an ugly and poor woman walking at night will not be targeted by robbers or rapists. But rape is sexual violence not necessarily targeting women and associated with sexual attraction. Therefore the translation made some adjustments. <a href=\"https://mmap.page/thoughts/hakuraku/#user-content-fnref-3\" data-footnote-backref=\"\" aria-label=\"Back to reference 4\" class=\"data-footnote-backref\">↩</a></p>\n</li>\n<li id=\"user-content-fn-4\">\n<p>\"Planting Seeds in Forests\" and \"Cultivating Virgin Soil in Mountains\" are literal translation of \"藝林\" and \"伐山\". And in Literary Chinese, both \"藝林\" and \"伐山\" are often used as metaphors. \"藝林\" refers to libraries with a huge collection of classical books where knowledgable people gather, and \"伐山\" refers to uncommon classical allusions. Therefore, the title 藝林伐山, a book composed by Youshin (楊慎), refers to uncommon allusions or stories in the classical literature. <a href=\"https://mmap.page/thoughts/hakuraku/#user-content-fnref-4\" data-footnote-backref=\"\" aria-label=\"Back to reference 5\" class=\"data-footnote-backref\">↩</a></p>\n</li>\n<li id=\"user-content-fn-5\">\n<p>The original text 蛈日 is cited from current revision of the book 藝林伐山, where 蛈 (a kanji used in the word 蛈蜴, a species of spider) is probably a typo of a similar kanji 蚨 (refers to copper coins), and 日(sun) is probably a typo of a similar kanji 目 (eye). 蚨目 literally means eyes like copper coins (big and round). <a href=\"https://mmap.page/thoughts/hakuraku/#user-content-fnref-5\" data-footnote-backref=\"\" aria-label=\"Back to reference 6\" class=\"data-footnote-backref\">↩</a></p>\n</li>\n<li id=\"user-content-fn-6\">\n<p>The famous horse tamper's name is 九方皋 or 九方湮. To avoid confusion, the English translation refers to him with his surname 九方. Nonapath is a word constructed by me (weakish) to translate the surname 九方, inspired by the translation of 八方 to Octopath for the game Octopath Traveler (八方旅人). <a href=\"https://mmap.page/thoughts/hakuraku/#user-content-fnref-6\" data-footnote-backref=\"\" aria-label=\"Back to reference 7\" class=\"data-footnote-backref\">↩</a></p>\n</li>\n<li id=\"user-content-fn-7\">\n<p>I chose to translate 秦穆公 as Duke of Cin, since 穆 is his posthumous name and I think omitting it does not change the meaning of the text. <a href=\"https://mmap.page/thoughts/hakuraku/#user-content-fnref-7\" data-footnote-backref=\"\" aria-label=\"Back to reference 8\" class=\"data-footnote-backref\">↩</a></p>\n</li>\n</ol>\n</section>","date_published":"Sat, 26 Jul 2025 05:04:12 GMT","date_modified":"Sat, 26 Jul 2025 05:04:12 GMT"},{"id":"https://mmap.page/coding-style/html/","url":"https://mmap.page/coding-style/html/","title":"Less HTML","content_html":"<h1>Less HTML</h1>\n<h2>HTML is a Text Markup Language</h2>\n<p>HTML stands for HyperText Markup Language.\nAs the name suggests, HTML is used to mark up text, not to describe user interfaces.\nAlthough it has been extended over time, it still doesn't excel at expressing user interfaces due to compatibility with its original design.</p>\n<p>Of course, JavaScript was originally intended to decorate pages, for creating some sparkly little widgets.\nBut regardless, JavaScript is still a general-purpose programming language, and JavaScript updates at a much faster pace than HTML.\nSo when choosing between two evils, we'd rather write JavaScript than HTML.</p>\n<p>In fact, frameworks that use pure HTML are not common.\nBecause HTML is too unwieldy, frameworks that use HTML usually need to add some extras,\nsuch as <code>*ng</code> (Angular) and <code>v-</code> (Vue) attributes, or JSX (React).\nOtherwise, they create a template language similar to HTML.</p>\n<p>Actually, this patching approach is not as straightforward as directly writing JavaScript.</p>\n<h2>The Kotlin and Ceylon Approach</h2>\n<p>Some newer languages directly use native structures to express HTML.</p>\n<p>For example, in Kotlin, HTML is written like this:</p>\n<pre><code class=\"language-kotlin\"><span class=\"pl-k\">fun</span> <span class=\"pl-en\">result</span>(<span class=\"pl-smi\">args</span><span class=\"pl-k\">:</span> <span class=\"pl-c1\">Array</span>&#x3C;<span class=\"pl-c1\">String</span>>) <span class=\"pl-k\">=</span>\n    html {\n        head {\n            title {<span class=\"pl-k\">+</span><span class=\"pl-s\"><span class=\"pl-pds\">\"</span>XML encoding with Kotlin<span class=\"pl-pds\">\"</span></span>}\n        }\n        body {\n            h1 {<span class=\"pl-k\">+</span><span class=\"pl-s\"><span class=\"pl-pds\">\"</span>XML encoding with Kotlin<span class=\"pl-pds\">\"</span></span>}\n            a(href <span class=\"pl-k\">=</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>http://kotlinlang.org<span class=\"pl-pds\">\"</span></span>) {<span class=\"pl-k\">+</span><span class=\"pl-s\"><span class=\"pl-pds\">\"</span>Kotlin<span class=\"pl-pds\">\"</span></span>}\n            p {\n                <span class=\"pl-k\">for</span> (arg <span class=\"pl-k\">in</span> args)\n                    <span class=\"pl-k\">+</span>arg\n            }\n        }\n    }\n</code></pre>\n<p>This is not some template language. This is Kotlin, native Kotlin.</p>\n<p>Kotlin provides this syntactic sugar:</p>\n<pre><code class=\"language-kotlin\">f({ <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>an anonymous function<span class=\"pl-pds\">\"</span></span> })\n</code></pre>\n<p>can be written as</p>\n<pre><code class=\"language-kotlin\">f { <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>an anonymous function<span class=\"pl-pds\">\"</span></span> }\n</code></pre>\n<p>So <code>html { ... }</code> is a Kotlin function call,\nand the other HTML elements inside <code>{}</code> work the same way.</p>\n<p>The <code>html</code> function is defined roughly like this:</p>\n<pre><code class=\"language-kotlin\"><span class=\"pl-k\">fun</span> <span class=\"pl-en\">html</span>(<span class=\"pl-en\">init</span>: <span class=\"pl-en\">HTML</span>.() <span class=\"pl-k\">-></span> <span class=\"pl-c1\">Unit</span>): <span class=\"pl-en\">HTML</span> {\n    <span class=\"pl-k\">val</span> html <span class=\"pl-k\">=</span> <span class=\"pl-en\">HTML</span>()\n    html.<span class=\"pl-en\">init</span>()\n    <span class=\"pl-k\">return</span> html\n}\n</code></pre>\n<p>Essentially, it initializes an HTML instance.</p>\n<p>The corresponding HTML class definition:</p>\n<pre><code class=\"language-kotlin\"><span class=\"pl-k\">class</span> <span class=\"pl-en\">HTML</span> : <span class=\"pl-en\">TagWithText</span>(<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>html<span class=\"pl-pds\">\"</span></span>) {\n    <span class=\"pl-k\">fun</span> <span class=\"pl-en\">head</span>(<span class=\"pl-en\">init</span>: <span class=\"pl-en\">Head</span>.() <span class=\"pl-k\">-></span> <span class=\"pl-c1\">Unit</span>) <span class=\"pl-k\">=</span> initTag(<span class=\"pl-en\">Head</span>(), <span class=\"pl-en\">init</span>)\n    <span class=\"pl-k\">fun</span> <span class=\"pl-en\">body</span>(<span class=\"pl-en\">init</span>: <span class=\"pl-en\">Body</span>.() <span class=\"pl-k\">-></span> <span class=\"pl-c1\">Unit</span>) <span class=\"pl-k\">=</span> initTag(<span class=\"pl-en\">Body</span>(), <span class=\"pl-en\">init</span>)\n}\n</code></pre>\n<p>Using native Kotlin language to express HTML means we can use all of Kotlin's native language features,\nand no longer need to worry about the limited expressiveness or strange syntax of HTML template languages.\nAt the same time, this naturally ensures type safety for HTML templates.</p>\n<p>Similarly, in Ceylon, HTML is written like this:</p>\n<pre><code class=\"language-ceylon\"><span class=\"pl-en\">Html</span> {\n    <span class=\"pl-smi\">doctype</span> = <span class=\"pl-smi\">html5</span>;\n    <span class=\"pl-en\">Head</span> {\n        <span class=\"pl-smi\">title</span> = <span class=\"pl-s\">\"Ceylon: home page\"</span>;\n    };\n    <span class=\"pl-en\">Body</span> {\n        <span class=\"pl-en\">H1</span> { <span class=\"pl-s\">\"Hello ``</span> <span class=\"pl-smi\">req</span>.<span class=\"pl-smi\">queryParameter</span>(<span class=\"pl-s\">\"name\"</span>) <span class=\"pl-k\">else</span> <span class=\"pl-s\">\"World\"</span> <span class=\"pl-s\">`` !\"</span> }\n    };\n}\n</code></pre>\n<p>This uses Ceylon's syntactic sugar for named parameters, equivalent to:</p>\n<pre><code class=\"language-ceylon\"><span class=\"pl-en\">Html</span>(<span class=\"pl-smi\">doctype</span> = <span class=\"pl-smi\">html5</span>, <span class=\"pl-en\">Head</span>(...), <span class=\"pl-en\">Body</span>(...))\n</code></pre>\n<p><code>Html</code> is a class provided by the standard library, <code>Html { ... }</code> is initialization,\n(Ceylon directly constructs class instances through <code>C()</code>, no need for <code>new</code>)\nThis is also native Ceylon.\nThe approach is similar to Kotlin's.</p>","date_published":"Fri, 25 Jul 2025 16:41:35 GMT","date_modified":"Fri, 25 Jul 2025 17:00:45 GMT"},{"id":"https://mmap.page/coding-style/python/","url":"https://mmap.page/coding-style/python/","title":"Coding Style for Python","content_html":"<h1>Coding Style for Python</h1>\n<p>The design of Python is well considered.\nAlso, the community tends to adhere PEP 8.</p>\n<p>Python dose have some flaws, but most of them are fixed by type hints.\nFor example, Python does not have the capability to define a constant variable,\nbut PEP 591 introduces <code>Final</code>.</p>\n<p>Personally I put a semicolon at the end of a mutation, e.g. <code>a.append(1)</code>.\nThis is inspired by the distinguished coding style used by \"A Little Java, A Few Patterns\".</p>\n<pre><code class=\"language-java\"><span class=\"pl-smi\">Pie</span> p <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> <span class=\"pl-smi\">Crust</span>();\n<span class=\"pl-smi\">Pie</span> p <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> <span class=\"pl-smi\">Top</span>(<span class=\"pl-k\">new</span> <span class=\"pl-smi\">Anchovy</span>(), p)\n; <span class=\"pl-c\">// the future begins, i.e. from this line on, references to `p` reflect the change</span>\n</code></pre>\n<p>However, this does not work with popular auto formatting tools such as <a href=\"https://black.readthedocs.io/en/stable/\">black</a>.\nTherefore, I do not adhere to this rule in some projects.</p>","date_published":"Fri, 25 Jul 2025 15:54:06 GMT","date_modified":"Fri, 25 Jul 2025 15:54:06 GMT"},{"id":"https://mmap.page/coding-style/kotlin/","url":"https://mmap.page/coding-style/kotlin/","title":"Kotlin coding style","content_html":"<h1>Kotlin coding style</h1>\n<h2>Use <code>when</code> expressions for cases, avoid other usage of <code>when</code></h2>\n<p>Avoid use <code>when</code> statement, which is not exhausted.\nJust use <code>if ... else if ...</code>.</p>\n<p>Kotlin uses <code>when</code> for both <code>case</code> and <code>cond</code>, which is confusing.\nThus avoid use <code>when</code> expression for <code>cond</code>.</p>\n<h2>Avoid variadic functions</h2>\n<p>Kotlin uses <code>Array&#x3C;T></code> for <code>vararg p: T</code> underhood\nbut special array types for basic types, e.g. <code>IntArray</code> for <code>vararg p: Int</code>.</p>\n<p>However, <code>p: Array&#x3C;T></code> and <code>vararg p: T</code> behaves differently.\nIn other words, given a function <code>Array&#x3C;T> -> Unit</code>,\nwe do not know how to invoke it just from its signature.</p>\n<p><code>Array&#x3C;T> -> Unit</code> may be an infix function,\nbut all infix functions can be invoked as normal functions.</p>\n<h2>Avoid <code>object.invoke</code></h2>\n<p>Without define <code>invoke</code> method for objects,\nevery time I see <code>CapsName(something)</code>,\nI am sure it will return an instance of <code>CapsName</code>,\nnothing else.</p>\n<p>If we use lower case for object name,\nthen once we see <code>lowerCase(something)</code>,\nwe may think it is a function.\nBut we can pass neither <code>lowerCase</code> nor <code>::lowerCase</code> to a higher-order function.</p>\n<h2>Avoid <code>return</code> in lambda.</h2>\n<p>Control flow <code>return</code> in lambda returns the outer function.\nThis is confusing.</p>\n<h2>Reduce using component object</h2>\n<p>Kotlin supports top level functions, often cleaner than component objects.</p>\n<h2>Reduce using normal function</h2>\n<p>They are not first-class:</p>\n<ul>\n<li>They have to be referred as <code>::f</code>.</li>\n<li>And invoking them requires intermediate variable (<code>::f()</code> won't walk).</li>\n<li>Only <code>Foo::bar</code> is referable. <a href=\"https://github.com/Kotlin/KEEP/issues/5\"><code>foo:bar</code> is not supported.</a></li>\n</ul>\n<p>Use <code>val f = fun()...</code> except for:</p>\n<ul>\n<li><code>main</code></li>\n<li><code>inline</code> for reified generics</li>\n<li><code>tailrec</code></li>\n</ul>\n<h2>Annotate <code>@Throws</code></h2>\n<ul>\n<li>for documentation</li>\n<li>for calling in try catch clause from Java</li>\n</ul>\n<h2>Overload operators consistently</h2>\n<p>Overloading an operator should be consistent to all types supporting the operator.</p>\n<h2>Reduce using infix functions</h2>\n<p>Infix functions provide a new syntax for function calls, similar to operators.</p>\n<p>Only use infix functions when they are obviously cleaner than non infix form.</p>","date_published":"Fri, 25 Jul 2025 15:54:06 GMT","date_modified":"Fri, 25 Jul 2025 15:54:06 GMT"},{"id":"https://mmap.page/coding-style/general/","url":"https://mmap.page/coding-style/general/","title":"General coding style for programming","content_html":"<h1>General coding style for programming</h1>\n<h2>The goal of coding style is readability</h2>\n<p>If there is a good reason to go against the style,\njust do it.</p>\n<h2>Avoid regression</h2>\n<blockquote>\n<p>So we don't fix bugs by introducing new problems.\nThat way lies madness,\nand nobody ever knows if you actually make any real progress at all.\nIs it two steps forwards, one step back,\nor one step forward and two steps back?</p>\n</blockquote>\n<p>-- <a href=\"https://lwn.net/Articles/243460/\">Linus Torvalds</a></p>\n<h2>Prefer small functions</h2>\n<ul>\n<li>Extract small functions from a complex function.</li>\n<li>One function should only do one thing.</li>\n</ul>\n<h2>Avoid top level variables</h2>\n<ul>\n<li>Prefer passing parameter to function.</li>\n<li>Local variable is fine.</li>\n<li>Top level immutable value is fine.</li>\n</ul>\n<h2>More documentation comments but less inline comments</h2>\n<p>Programming languages are clearer than natural languages.\nSo in most cases try to express as much as possible in programming language itself.\nAlso, a compiler cannot warn you that comments is outdated.\nAnd an outdated comment can be very misleading.</p>\n<ul>\n<li>Use meaningful function and variable/value name.</li>\n<li>Declare local variable near its usage.</li>\n<li>Avoid deep nested function call expression. Extract meaningful immediate value declaration.</li>\n</ul>\n<p>Here 'commenting' mainly refers to inline comments,\ni.e. comments explaining implementation details.\nDoc annotation of public modules and functions on their usage is fine.</p>\n<h2>Break long line of parameters logically</h2>\n<p>A simple approach is break for one, break for all.\nTo save lines, related parameters may be grouped in one line.</p>\n<h2>Prefer readability to testability</h2>\n<p>The main audience of code is human beings, not tests.</p>\n<p>Improving testability should not harm readability.</p>\n<p>Obscuring code to improve testability may bring in potential bugs not caught by tests.</p>\n<h2>Prefer <code>snake_case</code> to <code>camelCase</code></h2>\n<p><code>camelCaseAreHardToReadIfThereAreMoreThanThreeWords</code></p>\n<p><code>snake_case_is_much_easier_to_read</code></p>\n<p>Exceptions:</p>\n<ul>\n<li><code>TypeName</code> since <code>TypeNamesWithMoreThanThreeWords</code> should be avoided.</li>\n<li><code>FooBar fooBar</code> so wherever we see <code>fooBar</code>, we know it is of type <code>FooBar</code>.</li>\n<li>Keep a balance between preference on snake case and consistency with existing code in the project and/or the community.</li>\n</ul>\n<h2>Prefer explicit else branch</h2>\n<p>Some languages make the else clause of <code>if</code> mandated.\nThis is a good design.</p>\n<p>For other languages,\nprefer explicit else branch over fall through control flow.</p>\n<p>For example:</p>\n<pre><code class=\"language-ceylon\"><span class=\"pl-en\">Boolean</span> <span class=\"pl-smi\">if_else</span>(<span class=\"pl-en\">Integer</span> <span class=\"pl-smi\">x</span>) {\n    <span class=\"pl-k\">if</span> (<span class=\"pl-smi\">x</span> > <span class=\"pl-c1\">0</span>) {\n        <span class=\"pl-k\">if</span> (<span class=\"pl-smi\">x</span> &#x3C; <span class=\"pl-c1\">10</span>) {\n            <span class=\"pl-k\">return</span> <span class=\"pl-smi\">false</span>;\n        }\n    } <span class=\"pl-k\">else</span> <span class=\"pl-k\">if</span> (<span class=\"pl-smi\">x</span> &#x3C; <span class=\"pl-c1\">-10</span>) {\n        <span class=\"pl-k\">return</span> <span class=\"pl-smi\">false</span>;\n    }\n    <span class=\"pl-k\">return</span> <span class=\"pl-smi\">true</span>;\n}\n</code></pre>\n<p>It is short, but difficult to figure out the control flow.</p>\n<p>Rewrite it more explicitly, without omitting else branch:</p>\n<pre><code class=\"language-ceylon\"><span class=\"pl-en\">Boolean</span> <span class=\"pl-smi\">if_else</span>(<span class=\"pl-en\">Integer</span> <span class=\"pl-smi\">x</span>) {\n    <span class=\"pl-k\">if</span> (<span class=\"pl-smi\">x</span> > <span class=\"pl-c1\">0</span>) {\n        <span class=\"pl-c\">// This is for demonstration only.</span>\n        <span class=\"pl-c\">// `if (x > 0, x &#x3C; 10)` is clearer.</span>\n        <span class=\"pl-c\">// Pretend there were more complex branching here.</span>\n        <span class=\"pl-k\">if</span> (<span class=\"pl-smi\">x</span> &#x3C; <span class=\"pl-c1\">10</span>) {\n            <span class=\"pl-k\">return</span> <span class=\"pl-smi\">false</span>;\n        } <span class=\"pl-k\">else</span> {\n            <span class=\"pl-k\">return</span> <span class=\"pl-smi\">true</span>;\n        }\n    } <span class=\"pl-k\">else</span> <span class=\"pl-k\">if</span> (<span class=\"pl-smi\">x</span> &#x3C; <span class=\"pl-c1\">-10</span>) {\n        <span class=\"pl-k\">return</span> <span class=\"pl-smi\">false</span>;\n    } <span class=\"pl-k\">else</span> {\n        <span class=\"pl-k\">return</span> <span class=\"pl-smi\">true</span>;\n    }\n}\n</code></pre>\n<p>Also, avoid using <code>variable</code> to save else branch.</p>\n<p>For example:</p>\n<pre><code class=\"language-ceylon\"><span class=\"pl-k\">variable</span> <span class=\"pl-en\">Integer</span> <span class=\"pl-smi\">x</span> = <span class=\"pl-c1\">0</span>;\n<span class=\"pl-k\">if</span> (<span class=\"pl-smi\">condition</span>) {\n    <span class=\"pl-smi\">x</span> = <span class=\"pl-c1\">1</span>\n    ;\n}\n</code></pre>\n<p>can be rewritten to</p>\n<pre><code class=\"language-ceylon\"><span class=\"pl-en\">Integer</span> <span class=\"pl-smi\">x</span>;\n<span class=\"pl-k\">if</span> (<span class=\"pl-smi\">condition</span>) {\n    <span class=\"pl-smi\">x</span> = <span class=\"pl-c1\">1</span>;\n} <span class=\"pl-k\">else</span> {\n    <span class=\"pl-smi\">x</span> = <span class=\"pl-c1\">0</span>;\n}\n</code></pre>\n<h2>Only use <code>i++</code> to increase <code>i</code></h2>\n<p><code>y=i++</code> and <code>y=++i</code> is really confusing to me.</p>\n<p>If the language allows <code>++</code> operators,\nonly use <code>i++</code> to increase <code>i</code>, i.e. just the statement <code>i++;</code>.\nI think a meaningful evaluated value of <code>i++</code> should be <code>void</code>\nif a programming language allows <code>++</code>.</p>\n<p>The same applies to <code>i--</code> and <code>--i</code>.</p>\n<h2>Do not use return value of assignment statement</h2>\n<p>Similarly to usage of <code>i++</code>,\nif assignment statements of the language return value,\ndo not use them.</p>\n<h2>Test against true/false</h2>\n<p>Condition tests should accept a boolean value.\nSo we do not need to remember rules for truthy and falsy values.\nFor example, in Ruby only <code>false</code> and <code>nil</code> are false,\nbut in Python, <code>''</code>, <code>0</code>, <code>()</code>, <code>[]</code>, and <code>{}</code> are also <code>false</code>.</p>\n<p>Prefer</p>\n<pre><code class=\"language-ruby\"><span class=\"pl-k\">if</span> <span class=\"pl-k\">not</span> a.nil?\n  <span class=\"pl-c\"># do something</span>\n<span class=\"pl-k\">end</span>\n</code></pre>\n<p>over</p>\n<pre><code class=\"language-ruby\"><span class=\"pl-k\">if</span> a\n  <span class=\"pl-c\"># do something</span>\n<span class=\"pl-k\">end</span>\n</code></pre>\n<h3>Prefer explicit type annotation</h3>\n<p>Some languages allow you to use <code>auto</code>, <code>var</code>, etc.\nto let the compiler infer the variable type for you.\nUse this feature sparingly.\nExplicit type annotation serves as documentation.\nOmitting them may reduce readability of code.</p>\n<p>Exceptions:</p>\n<p>Prefer</p>\n<pre><code class=\"language-ceylon\"><span class=\"pl-k\">value</span> <span class=\"pl-smi\">variable_name</span> = <span class=\"pl-en\">ClassInterface</span>&#x3C;<span class=\"pl-en\">TypeParameter</span>>();\n<span class=\"pl-k\">value</span> <span class=\"pl-smi\">variable_name</span> = <span class=\"pl-en\">ClassInterface</span>()\n</code></pre>\n<p>to</p>\n<pre><code class=\"language-ceylon\"><span class=\"pl-en\">ClassInterface</span>&#x3C;<span class=\"pl-en\">TypeParameter</span>> <span class=\"pl-smi\">variable_name</span> = <span class=\"pl-en\">ClassInterface</span>&#x3C;<span class=\"pl-en\">TypeParameter</span>>();\n<span class=\"pl-en\">ClassInterface</span> <span class=\"pl-smi\">variable_name</span> = <span class=\"pl-en\">ClassInterface</span>();\n</code></pre>\n<p>Think long and hard when you want to omit type annotation under other conditions.</p>\n<p>Also, for languages where variable declarations and assignments are indistinguishable in syntax, e.g. Python, type annotation helps to distinguish them.</p>\n<h3>Use semicolons to remark mutation</h3>\n<p>\"A Little Java, A Few Patterns\" uses a special coding style to remark mutation:</p>\n<pre><code class=\"language-java\"><span class=\"pl-k\">class</span> <span class=\"pl-en\">PutSemicolonOnItsOwnLineForMutability</span>\n{\n    <span class=\"pl-smi\">Pie</span> p <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> <span class=\"pl-smi\">Crust</span>();\n    <span class=\"pl-smi\">Pie</span> p <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> <span class=\"pl-smi\">Top</span>(<span class=\"pl-k\">new</span> <span class=\"pl-smi\">Anchovy</span>(), p)\n    ; <span class=\"pl-c\">// the future begins, i.e. from this line on, references to `p` reflect the change</span>\n    <span class=\"pl-smi\">Pie</span> yy <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> <span class=\"pl-smi\">Bottom</span>();\n    yy.<span class=\"pl-en\">addTop</span>(<span class=\"pl-v\">new</span> <span class=\"pl-smi\">Anchovy</span>())\n    ; <span class=\"pl-c\">// same as above</span>\n}\n</code></pre>\n<p>This is a brilliant idea.\nIn languages semicolons are not mandatory, a semicolon can be used at the end of the line to remark mutability.</p>","date_published":"Fri, 25 Jul 2025 15:54:06 GMT","date_modified":"Fri, 25 Jul 2025 15:54:06 GMT"},{"id":"https://mmap.page/coding-style/formatting/","url":"https://mmap.page/coding-style/formatting/","title":"Code Formatting","content_html":"<h1>Code Formatting</h1>\n<p>Formatting style does not affect AST and thus is unlikely to affect readability of code.\nIf they do, it can be automatically adjusted via tools.</p>\n<p>Use the official formatter if the language tool chain includes it, for example:</p>\n<ul>\n<li><code>go fmt</code> for Go</li>\n<li><code>deno fmt</code> for Deno</li>\n<li><code>rustfmt</code> for Rust</li>\n</ul>\n<p>Since different contributors may have different formatting preferences configured in their editor/IDE,\nwith different rules or formatters,\nformatting should be configured at the project level,\nenforced by commit hook automatically.\nThis is the best practice.</p>\n<p>If formatting is not configured at the project level,\nit is a good idea to only commit in non-whitespace changes,\nto avoid formatting changes pollute repository history.\nFor example, with Git:</p>\n<pre><code class=\"language-sh\">git diff -w <span class=\"pl-k\">></span> changes\n<span class=\"pl-c\"># review changes, run tests, etc.</span>\ngit reset --hard\npatch <span class=\"pl-k\">&#x3C;</span> changes\n<span class=\"pl-c\"># stage and commit</span>\n</code></pre>\n<p>If the project does not configure auto formatting,\nand you need to review someone else's commits with a lot of formatting changes,\nyou can use <code>git diff -w</code> to ignore whitespace,\nor use similar options in other tools,\nsuch as \"Hide whitespace changes\" in GitHub's \"Diff settings\".</p>","date_published":"Fri, 25 Jul 2025 15:54:06 GMT","date_modified":"Fri, 25 Jul 2025 15:54:06 GMT"},{"id":"https://mmap.page/coding-style/ceylon/","url":"https://mmap.page/coding-style/ceylon/","title":"Ceylon coding style","content_html":"<h1>Ceylon coding style</h1>\n<p>Eclipse <a href=\"https://projects.eclipse.org/projects/technology.ceylon\">archived</a> the Ceylon project.</p>\n<blockquote>\n<p>(Ceylon) failed its transition to Eclipse and the community gave up.</p>\n<p>-- <a href=\"https://gitlab.eclipse.org/eclipsefdn/emo-team/emo/-/issues/443#note_1097289\">Eclipse Ceylon Termination Review</a></p>\n</blockquote>\n<h2>Avoid <code>... then ... else ...</code></h2>\n<p>I feel <code>A then B else C</code> confusing.</p>\n<p>Readers may think <code>A then B else C</code> means <code>A ? B : C</code> in other languages, but they are <strong>not the same</strong>:</p>\n<ol>\n<li>\n<p><code>A then B else C</code> is actually <code>(A then B) else C</code>:</p>\n<ul>\n<li><code>A then B</code> evaluates to <code>B</code> if <code>A</code> is not <code>null</code>, otherwise evaluates to <code>null</code>.</li>\n<li><code>X else Y</code> evaluates to <code>X</code> if <code>X</code> is not <code>null</code>, otherwise evaluates to <code>Y</code>.</li>\n</ul>\n</li>\n<li>\n<p>Thus the type of <code>B</code> is <code>T given T satisfies Object</code>, i.e. requires to not be <code>null</code>.</p>\n</li>\n</ol>\n<h2>Avoid <code>foo { \"bar\"; }</code></h2>\n<p>In Ceylon, <code>foo { \"bar\"; }</code> and <code>foo { \"bar\" }</code> are semantically different,\nwhich may be confusing.</p>\n<p>Either write <code>foo(\"bar\")</code> or <code>foo { parameter = \"bar\"; }</code>, never write <code>foo { \"bar\"; }</code>.</p>\n<p>Occasionally, <code>foo {\"bar\"}</code> may be used. But <code>foo({\"bar\"})</code> is often preferred.</p>\n<h2>Prefer switch case over if else.</h2>\n<p>Cases in <code>switch</code> need to be both disjoint and exhausted.\nUsing a strict form helps to reduce chances to miss corner cases.</p>\n<p>For example, suppose we have the following code:</p>\n<pre><code class=\"language-ceylon\"><span class=\"pl-en\">Path</span> <span class=\"pl-smi\">path</span> = <span class=\"pl-smi\">current</span>;\n<span class=\"pl-k\">if</span> (<span class=\"pl-k\">is</span> <span class=\"pl-en\">Directory</span> <span class=\"pl-smi\">path</span>) { <span class=\"pl-c\">// typo, should be `path.resource`.</span>\n    <span class=\"pl-c\">// ...</span>\n} <span class=\"pl-k\">else</span> { <span class=\"pl-c\">// dead code</span>\n    <span class=\"pl-c\">// ...</span>\n}\n</code></pre>\n<p>There is a typo in the above code, <code>path</code> should be <code>path.resource</code>.\nSo the above code will never go into the else branch,\nsince a Path is always not a Directory.</p>\n<p>However, if we use switch with explicit cases:</p>\n<pre><code class=\"language-ceylon\"><span class=\"pl-k\">switch</span> (<span class=\"pl-smi\">path</span>)\n<span class=\"pl-k\">case</span> (<span class=\"pl-k\">is</span> <span class=\"pl-en\">Directory</span>) {\n    <span class=\"pl-c\">// ...</span>\n}\n<span class=\"pl-k\">case</span> (<span class=\"pl-k\">is</span> <span class=\"pl-en\">File</span>|<span class=\"pl-en\">Link</span>|<span class=\"pl-en\">Nil</span>) {\n    <span class=\"pl-c\">// ...</span>\n}\n</code></pre>\n<p>The compiler will refuse to compile, saying cases are not exhausted.</p>\n<p><code>switch</code> can also be used as a workaround of Ceylon's assignment returnning assigned value:</p>\n<pre><code class=\"language-ceylon\"><span class=\"pl-k\">variable</span> <span class=\"pl-en\">Boolean</span> <span class=\"pl-smi\">b</span> = <span class=\"pl-smi\">false</span>;\n<span class=\"pl-k\">if</span> (<span class=\"pl-smi\">b</span> = <span class=\"pl-smi\">true</span>) {\n    <span class=\"pl-smi\">print</span>(<span class=\"pl-s\">\"typo in the above line: `=` should be `==`\"</span>);\n} <span class=\"pl-k\">else</span> {\n    <span class=\"pl-smi\">print</span>(<span class=\"pl-s\">\"Use switch to avoid this mistake.\"</span>);\n}\n\n<span class=\"pl-k\">switch</span> (<span class=\"pl-smi\">b</span>)\n<span class=\"pl-k\">case</span> (<span class=\"pl-smi\">true</span>) {\n    <span class=\"pl-smi\">print</span>(<span class=\"pl-s\">\"Avoid typo of `==`.\"</span>);\n}\n<span class=\"pl-k\">case</span> (<span class=\"pl-smi\">false</span>) {\n    <span class=\"pl-smi\">print</span>(<span class=\"pl-s\">\"assignment should not return a value in Ceylon.\"</span>);\n}\n</code></pre>\n<h2>Pay attention to compiler warnings</h2>\n<p>If necessary, use annotation to suppress false positive warnings.</p>\n<p>For example:</p>\n<pre><code class=\"language-ceylon\"><span class=\"pl-s\">\"The ultimate exception handler.\"</span>\n<span class=\"pl-k\">suppressWarnings</span>(<span class=\"pl-s\">\"expressionTypeNothing\"</span>)\n<span class=\"pl-k\">shared</span> <span class=\"pl-k\">void</span> <span class=\"pl-smi\">run</span>() {\n    <span class=\"pl-k\">try</span> {\n        <span class=\"pl-smi\">main</span>();\n    } <span class=\"pl-k\">catch</span> (<span class=\"pl-en\">UsageError</span> <span class=\"pl-smi\">e</span>) {\n        <span class=\"pl-smi\">process</span>.<span class=\"pl-smi\">writeErrorLine</span>(<span class=\"pl-smi\">e</span>.<span class=\"pl-smi\">message</span>);\n        <span class=\"pl-smi\">process</span>.<span class=\"pl-smi\">exit</span>(<span class=\"pl-smi\">e</span>.<span class=\"pl-smi\">exit_code</span>);\n    }\n}\n</code></pre>\n<h2>Failures</h2>\n<p>Use exceptions for failures that are unrecoverable by immediate calling code,\nlike bugs in program logic, network failure, and so on.\nSo they can be handled by some centric infrastructure code.</p>\n<p>Use return values (union types) for recoverable failures.</p>\n<p>Be careful with side-effect functions.\nThey are not type safe as side-effect functions with checked exceptions in Java.\nThe ceylon compiler does not force you to check function's return value\nwhen invoking functions as side-effects.\nFor example, when getting return value from <code>result = f();</code>\nwhere <code>f</code> is <code>Result?()</code>,\nCeylon does force you to check whether <code>result</code> is <code>null</code> or not.\nHowever, invoking <code>f</code> as side-effects <code>f();</code> will silently ignore its return value,\nwithout checking for failures.</p>","date_published":"Fri, 25 Jul 2025 15:50:48 GMT","date_modified":"Fri, 25 Jul 2025 15:50:48 GMT"},{"id":"https://mmap.page/coding-style/go/","url":"https://mmap.page/coding-style/go/","title":"Go Coding Style","content_html":"<h1>Go Coding Style</h1>\n<h2>Be careful when indexing slice</h2>\n<p>Index out of bounds are not checked at compile time\nfor slices (including strings, a.k.a. slices of bytes).</p>\n<p>You may consider using the <a href=\"https://github.com/weakish/gosugar/blob/master/slice.go\">indexing functions</a> from the gosugar package instead,\nwhich will automatically check slice length for you.</p>\n<h2>Functions, interfaces, pointers may be <code>nil</code></h2>\n<p>The compiler does not check nullability for functions, interfaces, and pointers.</p>\n<p>Thus, any function taking a function, an interface, or a pointer,\nneeds to check whether input is <code>nil</code> itself.\nSince all methods implicitly accept a pointer,\nall methods should check whether their receiver is <code>nil</code> or not.\nThough, if you are careful enough, you may omit checking nullability in unexported functions.</p>\n<p>You can use the <a href=\"https://github.com/weakish/goaround/blob/master/null.go\">RequireNonNull</a> function from the goaround package\nto check every non-nullable parameter,\nwhich will panic if the parameter passed in is <code>nil</code>.</p>\n<h2>Explicitly check type implementing interface at compile time</h2>\n<p>Use the <code>var _ Interface = (*Type)(nil)</code> trick.</p>\n<h2>Stay clear. Stay explicit.</h2>\n<ul>\n<li>Use naked return sparingly, e.g. in very short functions with single exit point. Alternatively, always use explicit return.</li>\n<li>Do not omit top level type names in map literals.</li>\n</ul>\n<h2>Only use head statement in <code>if</code> to declare variables</h2>\n<p>Like <code>for</code>, the <code>if</code> statement can start with a short statement to execute before the condition.\nThis often harms readability thus it should only be used to declare variables to limit their scope.</p>\n<p>The same applies to <code>switch</code>.</p>\n<h2>Only use switch for cases</h2>\n<p>In Go, <code>switch</code> can be used for both <code>case</code> and <code>cond</code>.\nTo avoid confusion, I always use <code>switch</code> for <code>case</code>.\nI use <code>if ... else if</code> instead of <code>switch</code> for <code>cond</code>.</p>\n<h2>Only use defer for cleanups</h2>\n<p>Use <code>defer</code> carefully.</p>\n<h2>Do not rely on zero values</h2>\n<p>Do not rely on Go's default initialized value.\nInitialize it explicitly instead if the value is intended to be used later.</p>\n<p>Similarly, always check presence when retrieving elements from a map.</p>\n<p>Similarly, always check presentence when retrieving elements from a map.\nFor example, if you want to retrieve an integer from a map,\nand use <code>0</code> if the key is missing:</p>\n<pre><code class=\"language-go\"><span class=\"pl-smi\">element</span> <span class=\"pl-k\">:=</span> m[<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>id<span class=\"pl-pds\">\"</span></span>]\n</code></pre>\n<p>The above code utilizes the zero value of missing keys.\nThis makes the code shorter,\nbut less clear (The value is absent? The value happens to be zero?)</p>\n<p>Verbose and explicit code is preferred:</p>\n<pre><code class=\"language-go\"><span class=\"pl-smi\">element</span>, <span class=\"pl-smi\">present</span> <span class=\"pl-k\">:=</span> m[<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>id<span class=\"pl-pds\">\"</span></span>]\n<span class=\"pl-k\">if</span> present {\n    <span class=\"pl-k\">return</span> element\n} <span class=\"pl-k\">else</span> {\n    <span class=\"pl-k\">return</span> <span class=\"pl-c1\">0</span>\n}\n</code></pre>\n<p>Since Go will always initialize zero value on declaration,\nthe compiler will not complain declaration without initialization.\nThus, we should initialize variable on declaration whenever possible.</p>\n<p>For example:</p>\n<pre><code class=\"language-go\"><span class=\"pl-k\">var</span> <span class=\"pl-smi\">s</span> <span class=\"pl-k\">string</span>\n<span class=\"pl-k\">if</span> x &#x3C; <span class=\"pl-c1\">0</span> {\n    s = <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>0<span class=\"pl-pds\">\"</span></span>\n} <span class=\"pl-k\">else</span> {\n    s = <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>1<span class=\"pl-pds\">\"</span></span>\n}\n</code></pre>\n<p>We can extract it as a function:</p>\n<pre><code class=\"language-go\"><span class=\"pl-k\">func</span> <span class=\"pl-en\">f</span>(<span class=\"pl-v\">x</span> <span class=\"pl-v\">int</span>) <span class=\"pl-v\">string</span> {\n    <span class=\"pl-k\">if</span> x &#x3C; <span class=\"pl-c1\">0</span> {\n        <span class=\"pl-k\">return</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>0<span class=\"pl-pds\">\"</span></span>\n    } <span class=\"pl-k\">else</span> {\n        <span class=\"pl-k\">return</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>1<span class=\"pl-pds\">\"</span></span>\n    }\n}\n\n<span class=\"pl-k\">var</span> <span class=\"pl-smi\">s</span> <span class=\"pl-k\">string</span> = <span class=\"pl-c1\">f</span>(<span class=\"pl-c1\">5</span>)\n</code></pre>\n<p>The compiler will check the function returns on all branches.</p>\n<h2>Do not use <code>%#q</code> in <code>printf</code></h2>\n<p>There are more good things to remember than the special rules of <code>%#q</code>.</p>","date_published":"Fri, 25 Jul 2025 15:40:12 GMT","date_modified":"Fri, 25 Jul 2025 15:40:12 GMT"},{"id":"https://mmap.page/coding-style/c/","url":"https://mmap.page/coding-style/c/","title":"C coding style","content_html":"<h1>C coding style</h1>\n<h2>Include files</h2>\n<blockquote>\n<p>Simple rule: include files should never include include files.\nIf instead they state (in comments or implicitly)\nwhat files they need to have included first,\nthe problem of deciding which files to include is pushed to the user\n(programmer) but in a way that's easy to handle and that, by construction,\navoids multiple inclusions.</p>\n<p>There's a little dance involving <code>#ifdef</code>'s\nthat can prevent a file being read twice,\nbut it's usually done wrong in practice -\nthe <code>#ifdef</code>'s are in the file itself,\nnot the file that includes it.\nThe result is often thousands of needless lines of code\npassing through the lexical analyzer,\nwhich is (in good compilers) the most expensive phase.</p>\n</blockquote>\n<p>-- Rob Pike <a href=\"http://doc.cat-v.org/bell_labs/pikestyle\">Notes on Programming in C</a></p>\n<p>The real problem is C does not have a proper package or module system.\nLeaving the user to manually composite include file list is a workaround.</p>\n<h2>Reduce macros</h2>\n<blockquote>\n<p>As a general rule,\n<code>#ifdef</code> use should be confined to header files whenever possible.\nConditionally-compiled code can be confined to functions\nwhich, if the code is not to be present, simply become empty.\nThe compiler will then quietly optimize out the call to the empty function.</p>\n</blockquote>\n<blockquote>\n<p>C preprocessor macros present a number of hazards,\nincluding possible multiple evaluation of expressions with side effects\nand no type safety.\nIf you are tempted to define a macro,\nconsider creating an inline function instead.\nThe code which results will be the same,\nbut inline functions are easier to read,\ndo not evaluate their arguments multiple times,\nand allow the compiler to perform type checking on the arguments and return value.</p>\n</blockquote>\n<p>-- <a href=\"https://www.kernel.org/doc/Documentation/process/4.Coding.rst\">Linux kernel coding style</a></p>\n<h2>Reduce inline functions</h2>\n<blockquote>\n<p>Since their code is replicated at each call site,\nthey end up bloating the size of the compiled kernel.\nThat, in turn, creates pressure on the processor's memory caches,\nwhich can slow execution dramatically.</p>\n<p>More recent compilers take an increasingly active role in deciding\nwhether a given function should actually be inlined or not.</p>\n</blockquote>\n<p>-- <a href=\"https://www.kernel.org/doc/Documentation/process/4.Coding.rst\">Linux kernel coding style</a></p>\n<h2>Prototypes should have parameter names</h2>\n<p>Prototypes do not require parameter names.\nBut writing them out helps to understand the usage of functions.</p>\n<p>Do omit parameter names when it is obvious, for example,</p>\n<pre><code class=\"language-c\"><span class=\"pl-k\">int</span> <span class=\"pl-en\">plus</span>(<span class=\"pl-k\">int</span>, <span class=\"pl-k\">int</span>);\n</code></pre>\n<p>is preferred to</p>\n<pre><code class=\"language-c\"><span class=\"pl-k\">int</span> <span class=\"pl-en\">plus</span>(<span class=\"pl-k\">int</span> adder, <span class=\"pl-k\">int</span> addee);\n</code></pre>\n<h2>Comment <code>FALLTHROUGH</code> in cases</h2>\n<p>Non default cases in switch statements should end with\neither <code>break</code> or <code>FALLTHROUGH</code> comment.</p>\n<h2>Mark non-return</h2>\n<p>Mark a function never returns (always abort) with <code>__dead</code>.</p>\n<p>To be compatible with different operating systems, use a shim:</p>\n<pre><code class=\"language-c\"><span class=\"pl-c\">/*</span>\n<span class=\"pl-c\"> * Public domain</span>\n<span class=\"pl-c\"> * sys/cdefs.h compatibility shim</span>\n<span class=\"pl-c\"> */</span>\n\n#include_next &#x3C;sys/cdefs.h>\n\n#<span class=\"pl-k\">if</span> !defined(HAVE_ATTRIBUTE__DEAD) &#x26;&#x26; !defined(__dead)\n#<span class=\"pl-k\">define</span> <span class=\"pl-en\">__dead</span>          <span class=\"pl-en\">__attribute__</span>((__noreturn__))\n#endif\n</code></pre>\n<p>This is based on the code at <a href=\"https://github.com/openntpd-portable/openntpd-portable/blob/master/include/sys/cdefs.h\">openntpd</a>, with <code>#ifndef</code> and <code>__pure</code> removed.</p>\n<h2>Standards</h2>\n<ul>\n<li>Lua still sticks to ANSI C (C89, <code>gcc -ansi</code>).\nBut for most programs, I think, a more recent version is more convinient.\nFor example, C17 without extension, <code>-std=c17 -pedantic</code>.</li>\n<li>Use <a href=\"https://pubs.opengroup.org/onlinepubs/9699919799/toc.htm\">POSIX.1-2008/POSIX.1-2017</a>, <code>#define _XOPEN_SOURCE 700</code>.</li>\n</ul>","date_published":"Thu, 24 Jul 2025 12:16:07 GMT","date_modified":"Thu, 24 Jul 2025 12:16:07 GMT"},{"id":"https://mmap.page/movies/","url":"https://mmap.page/movies/","title":"Recently Watched Movies","content_html":"","date_published":"Tue, 27 Aug 2024 12:51:28 GMT","date_modified":"Tue, 15 Jul 2025 04:09:47 GMT"},{"id":"https://mmap.page/dive-into/gemini/","url":"https://mmap.page/dive-into/gemini/","content_html":"<h1>Gemini</h1>\n<br />\n<p>Gemini is a protocol &quot;in between Gopher and the web&quot;*, but for me, Gopher is more like FTP, and Gemini is more like HTTP. Gemini does have some pitfalls in its design+, but it is still a good enough alternative to Web with an active community.#</p>\n<br />\n<div><a href=\"https://geminiprotocol.net/history/\">* History of Project Gemini</a></div>\n<div><a href=\"https://daniel.haxx.se/blog/2023/05/28/the-gemini-protocol-seen-by-this-http-client-person/\">+ Daniel Stenberg (author of curl) on the Gemini protocol</a></div>\n<div><a href=\"https://github.com/kr1sp1n/awesome-gemini\"># Awesome Gemini</a></div>\n<br />\n<h2>Gemini Text</h2>\n<br />\n<p>If Gemini is to HTTP, then Gemini text is to HTML. It's a line-oriented minimalistic hypertext markup language inspired by Markdown and gophermaps. It has link lines and preformatted text lines. Optionally, it supports three levels of headings, unsorted lists, and quote lines.</p>\n<p>There is no syntax for escaping special markers. In other words, it assumes no normal text line will starts with =&gt;, ```, *, #, or &gt;. And no lines in preformatted text block will start with ```.</p>\n<br />\n<div><a href=\"https://geminiprotocol.net/docs/specification.gmi\">Gemini Speculative Specification</a></div>","date_published":"Thu, 28 Dec 2023 14:49:32 GMT","date_modified":"Thu, 28 Dec 2023 14:49:32 GMT"},{"id":"https://mmap.page/web/markdown/","url":"https://mmap.page/web/markdown/","title":"Markdown Markdown","content_html":"<h1>Markdown Markdown</h1>\n<h2>A Bit of History</h2>\n<p>Setext (Structure Enhanced Text) aims to be easily readable\nwithout any parsing or special software.\nThis inspires both ReStrucuterdText and Markdown.</p>\n<p>The idea of Markdown is</p>\n<blockquote>\n<p>to make writing simple web pages, and especially weblog entries,\nas easy as writing an email</p>\n<p>-- <a href=\"http://www.aaronsw.com/weblog/001189\">Aaron Swartz</a></p>\n</blockquote>\n<p>At that time, ReStrucuterdText seems too complex:</p>\n<blockquote>\n<p>Is there a Perl implementation of reST, or a Movable Type single-file plug-in wrapper?\nAs far as I’m aware, no.\nSo, even without any arguments about reST’s syntax,\nI just don’t see how one could argue that I could have just used reST.</p>\n<p>And if I was going to write my own code,\nthere was no way I was going to write code to re-implement reST’s rather large feature set.\nI’m much too lazy.</p>\n<p>-- <a href=\"http://www.aaronsw.com/weblog/001189#c755\">John Gruber</a></p>\n</blockquote>\n<p>What Gruber and Swartz could have done was to implement a subset of ReStrucuterdText.\nBut they decided to \"develop the perfect format\".</p>\n<p>Partly due to its simplicity, Markdown became popular.\nThen, people want more and add more.\nToday Markdown turns out to be as complex, if not more complex than, ReStrucuterdText.\nAnd unlike ReStrucuterdText, Markdown is inconsistent among applications and platforms.</p>\n<p>Maybe I should not get surprised.\nAfter all, HTML was extremely simple at the time of Setext.</p>\n<h2>Common Markup Among Setext, ReStrucuterdText, and Markdown</h2>\n<blockquote>\n<p>To me, the best parts of reST are the parts it borrowed from Setext.</p>\n<p>-- <a href=\"http://www.aaronsw.com/weblog/001189#c755\">John Gruber</a></p>\n</blockquote>\n<p>However, there are few common markup among Setext, ReStrucuterdText, and Markdown.</p>\n<pre><code class=\"language-markdown\">Heading\n<span class=\"pl-mh\">=======</span>\n\nSub-heading\n<span class=\"pl-ms\">-----------</span>\n\n<span class=\"pl-s\">**</span>bold<span class=\"pl-s\">**</span>\n\n<span class=\"pl-v\">*</span> bullet list\n<span class=\"pl-v\">*</span> another item\n</code></pre>\n<p>And the bullet list markup seems to be the most pervasive one.\nIt is the only common markup among Setext, ReStrucuterdText, Markdown, <a href=\"http://www.usemod.com/cgi-bin/wiki.pl?TextFormattingRules\">Usemod wiki</a>,\nand <a href=\"https://go.dev/doc/comment\">godoc comment</a>.</p>","date_published":"Sat, 29 Apr 2023 13:15:00 GMT","date_modified":"Thu, 14 Sep 2023 09:22:18 GMT"},{"id":"https://mmap.page/dive-into/preact-signal/","url":"https://mmap.page/dive-into/preact-signal/","title":"Preact Signal and Svelte","content_html":"<h1>Preact Signal and Svelte</h1>\n<p>Compared to Svelte Reactive Blocks, Preact Signal feels more verbose but less surprising to me.</p>\n<p>Svelte advertises itself as bringing reactivity to JavaScript itself:</p>\n<pre><code class=\"language-svelte\">&#x3C;<span class=\"pl-ent\">script</span>>\n\t<span class=\"pl-k\">let</span> x <span class=\"pl-k\">=</span> <span class=\"pl-c1\">0</span>\n\t<span class=\"pl-k\">let</span> y <span class=\"pl-k\">=</span> <span class=\"pl-c1\">0</span>\n\t$<span class=\"pl-k\">:</span> total <span class=\"pl-k\">=</span> x <span class=\"pl-k\">+</span> y\n&#x3C;/<span class=\"pl-ent\">script</span>>\n\n&#x3C;<span class=\"pl-ent\">div</span>>\n&#x3C;<span class=\"pl-ent\">p</span>>{<span class=\"pl-smi\">x</span>} + {<span class=\"pl-smi\">y</span>} = {<span class=\"pl-smi\">total</span>}&#x3C;/<span class=\"pl-ent\">p</span>>\n&#x3C;<span class=\"pl-ent\">button</span> <span class=\"pl-e\">on:click</span>={() <span class=\"pl-k\">=></span> <span class=\"pl-smi\">x</span><span class=\"pl-k\">++</span>}>Increase X&#x3C;/<span class=\"pl-ent\">button</span>>&#x3C;<span class=\"pl-ent\">br</span> />\n&#x3C;<span class=\"pl-ent\">button</span> <span class=\"pl-e\">on:click</span>={() <span class=\"pl-k\">=></span> <span class=\"pl-smi\">y</span><span class=\"pl-k\">++</span>}>Increase Y&#x3C;/<span class=\"pl-ent\">button</span>>\n&#x3C;/<span class=\"pl-ent\">div</span>>\n</code></pre>\n<p>Brief. Short. And except for <code>$:</code>, every token is intuitive.</p>\n<p>In the above code, <code>$:</code> means <code>total</code> depends on the value of <code>x</code> and <code>y</code>.\nThus, when either button is pressed, the <code>{total}</code> part will be rerendered automatically.</p>\n<p>However, in the following code sample, <code>total</code> will only get updated when <code>x</code> changes, <em>not</em> when <code>y</code> changes!</p>\n<pre><code class=\"language-js\"><span class=\"pl-k\">function</span> <span class=\"pl-en\">yPlusAValue</span>(<span class=\"pl-smi\">value</span>) {\n  <span class=\"pl-k\">return</span> value <span class=\"pl-k\">+</span> y;\n}\n\n$<span class=\"pl-k\">:</span> total <span class=\"pl-k\">=</span> <span class=\"pl-en\">yPlusAValue</span>(x);\n</code></pre>\n<p>This surprising behavior is because the Svelte compiler is not smart enought to figure out that yPlusAValue involves the value of<code>y</code>.\nAs <a href=\"https://svelte.dev/docs#component-format-script-3-$-marks-a-statement-as-reactive\">Svelte documentation</a> mentioned:</p>\n<blockquote>\n<p>reactive blocks are ordered via simple static analysis at compile time,\nand all the compiler looks at are the variables that are assigned to and used within the block itself,\nnot in any functions called by them.</p>\n</blockquote>\n<p>Now, let's port this to Preact Signal:</p>\n<pre><code class=\"language-js\"><span class=\"pl-k\">import</span> { <span class=\"pl-smi\">render</span> } <span class=\"pl-k\">from</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>preact<span class=\"pl-pds\">\"</span></span>;\n<span class=\"pl-k\">import</span> { <span class=\"pl-smi\">useSignal</span>, <span class=\"pl-smi\">useComputed</span> } <span class=\"pl-k\">from</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>@preact/signals<span class=\"pl-pds\">\"</span></span>;\n\n<span class=\"pl-k\">function</span> <span class=\"pl-en\">Adder</span>() {\n\t<span class=\"pl-k\">const</span> <span class=\"pl-c1\">x</span> <span class=\"pl-k\">=</span> <span class=\"pl-en\">useSignal</span>(<span class=\"pl-c1\">0</span>);\n\t<span class=\"pl-k\">const</span> <span class=\"pl-c1\">y</span> <span class=\"pl-k\">=</span> <span class=\"pl-en\">useSignal</span>(<span class=\"pl-c1\">0</span>);\n\t<span class=\"pl-k\">const</span> <span class=\"pl-c1\">total</span> <span class=\"pl-k\">=</span> <span class=\"pl-en\">useComputed</span>(() <span class=\"pl-k\">=></span> <span class=\"pl-smi\">x</span>.<span class=\"pl-c1\">value</span> <span class=\"pl-k\">+</span> <span class=\"pl-smi\">y</span>.<span class=\"pl-c1\">value</span>)\n  <span class=\"pl-k\">return</span> (\n    <span class=\"pl-k\">&#x3C;</span>div<span class=\"pl-k\">></span>\n      <span class=\"pl-k\">&#x3C;</span>p<span class=\"pl-k\">></span>{x} <span class=\"pl-k\">+</span> {y} <span class=\"pl-k\">=</span> {total}<span class=\"pl-k\">&#x3C;/</span>p<span class=\"pl-k\">></span>\n      <span class=\"pl-k\">&#x3C;</span>button onClick<span class=\"pl-k\">=</span>{() <span class=\"pl-k\">=></span> <span class=\"pl-smi\">x</span>.<span class=\"pl-c1\">value</span><span class=\"pl-k\">++</span>}<span class=\"pl-k\">></span>Increase <span class=\"pl-c1\">X</span><span class=\"pl-k\">&#x3C;/</span>button<span class=\"pl-k\">>&#x3C;</span>br <span class=\"pl-k\">/></span>\n  \t\t<span class=\"pl-k\">&#x3C;</span>button onClick<span class=\"pl-k\">=</span>{() <span class=\"pl-k\">=></span> <span class=\"pl-smi\">y</span>.<span class=\"pl-c1\">value</span><span class=\"pl-k\">++</span>}<span class=\"pl-k\">></span>Increase <span class=\"pl-c1\">Y</span><span class=\"pl-k\">&#x3C;/</span>button<span class=\"pl-k\">></span>\n\t<span class=\"pl-k\">&#x3C;/</span>div<span class=\"pl-k\">></span>\n  );\n}\n\n<span class=\"pl-en\">render</span>(<span class=\"pl-k\">&#x3C;</span>Adder <span class=\"pl-k\">/></span>, <span class=\"pl-c1\">document</span>.<span class=\"pl-c1\">getElementById</span>(<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>app<span class=\"pl-pds\">\"</span></span>));\n</code></pre>\n<p>It is a bit more verbose than Svelte but still clean.<sup><a href=\"https://mmap.page/dive-into/preact-signal/#user-content-fn-1\" id=\"user-content-fnref-1\" data-footnote-ref aria-describedby=\"footnote-label\">1</a></sup>\nMost importantly, it also works with function calls:</p>\n<pre><code class=\"language-js\"><span class=\"pl-k\">function</span> <span class=\"pl-en\">yPlusAValue</span>(<span class=\"pl-smi\">s</span>) {\n  <span class=\"pl-k\">return</span> <span class=\"pl-smi\">s</span>.<span class=\"pl-c1\">value</span> <span class=\"pl-k\">+</span> <span class=\"pl-smi\">y</span>.<span class=\"pl-c1\">value</span>;\n}\n<span class=\"pl-k\">const</span> <span class=\"pl-c1\">total</span> <span class=\"pl-k\">=</span> <span class=\"pl-en\">useComputed</span>(() <span class=\"pl-k\">=></span> <span class=\"pl-en\">yPlusAValue</span>(x))\n</code></pre>\n<section data-footnotes class=\"footnotes\"><h2 class=\"sr-only\" id=\"footnote-label\">Footnotes</h2>\n<ol>\n<li id=\"user-content-fn-1\">\n<p>At least cleaner than <code>useState</code>. <a href=\"https://mmap.page/dive-into/preact-signal/#user-content-fnref-1\" data-footnote-backref=\"\" aria-label=\"Back to reference 1\" class=\"data-footnote-backref\">↩</a></p>\n</li>\n</ol>\n</section>","date_published":"Thu, 27 Apr 2023 12:31:05 GMT","date_modified":"Thu, 27 Apr 2023 12:31:05 GMT"},{"id":"https://mmap.page/lists/serverless-bandwidth/","url":"https://mmap.page/lists/serverless-bandwidth/","title":"The Cost of Serverless Bandwidth","content_html":"<h1>The Cost of Serverless Bandwidth</h1>\n<p>If only bandwidth is concerned, then:</p>\n<ul>\n<li>\n<p>Serverless provides typically have a free plain, often with 100 GB free\ntransfer per month. VPS provides usually have no free plan.</p>\n</li>\n<li>\n<p>The cheapest paid plan of both serverless and VPS provides often include 1 TB\nfree transfer per month, but the cheapest VPS plan is usually cheaper than\nserverless.</p>\n</li>\n<li>\n<p>Overage is expensive compared to included transfer. Overage seems an\nafterthought for many serverless providers. They do not meter it, or handle it\ncase by case, or enforce a soft limit, or charge a much more expensively,\ncompared to VPS.</p>\n</li>\n<li>\n<p>Cloudflare offers a distinguished deal on bandwidth.</p>\n</li>\n</ul>\n<h2>Comparison</h2>\n<table>\n<thead>\n<tr>\n<th>Provider</th>\n<th>1 GB</th>\n<th>100 GB</th>\n<th>1 TB</th>\n<th>Overage per GB</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Digital Ocean App Platform</td>\n<td>0</td>\n<td>12</td>\n<td>102</td>\n<td>0.10</td>\n</tr>\n<tr>\n<td>Netlify</td>\n<td>0</td>\n<td>0</td>\n<td>19</td>\n<td>0.55</td>\n</tr>\n<tr>\n<td>Vercel</td>\n<td>0</td>\n<td>0</td>\n<td>20</td>\n<td>contact sale</td>\n</tr>\n<tr>\n<td>Gatsby</td>\n<td>0</td>\n<td>0</td>\n<td>42.50</td>\n<td>contact</td>\n</tr>\n<tr>\n<td>Render</td>\n<td>0</td>\n<td>0</td>\n<td>90</td>\n<td>0.10</td>\n</tr>\n<tr>\n<td>Railway</td>\n<td>0</td>\n<td>0</td>\n<td>n/a</td>\n<td>n/a</td>\n</tr>\n<tr>\n<td>Fly</td>\n<td>0</td>\n<td>0</td>\n<td>18</td>\n<td>0.02/0.04/0.12</td>\n</tr>\n<tr>\n<td>LeanCloud</td>\n<td>0</td>\n<td>7</td>\n<td>97</td>\n<td>0.10</td>\n</tr>\n<tr>\n<td>Heroku</td>\n<td>7</td>\n<td>7</td>\n<td>7</td>\n<td>n/a</td>\n</tr>\n<tr>\n<td>GitHub Pages</td>\n<td>0</td>\n<td>0</td>\n<td>n/a</td>\n<td>n/a</td>\n</tr>\n<tr>\n<td>Cloudflare Pages</td>\n<td>0</td>\n<td>0</td>\n<td>0</td>\n<td>0</td>\n</tr>\n<tr>\n<td>Digital Ocean Droplets</td>\n<td>4</td>\n<td>4</td>\n<td>4</td>\n<td>0.01</td>\n</tr>\n<tr>\n<td>Linode Compute</td>\n<td>5</td>\n<td>5</td>\n<td>5</td>\n<td>0.01</td>\n</tr>\n<tr>\n<td>Koyeb</td>\n<td>0</td>\n<td>0</td>\n<td>36</td>\n<td>0.04</td>\n</tr>\n</tbody>\n</table>\n<h3>Details</h3>\n<ul>\n<li>\n<p><a href=\"https://www.digitalocean.com/pricing/app-platform\" title=\"pricing\">Digital Ocean App Platform</a> The starter plan (free) has 1 GB bandwidth per\nmonth, Professional 100 GB, and $0.10/GB for overage.</p>\n</li>\n<li>\n<p><a href=\"https://www.netlify.com/pricing/\" title=\"pricing\">Netlify</a> Starter 100 GB, Pro 1 TB, and $55 per 100 GB for overage.</p>\n</li>\n<li>\n<p><a href=\"https://vercel.com/pricing\" title=\"pricing\">Vercel</a> Hobby 100 GB, Pro 1 TB, and contact the sale to buy additional\nbandwidth.</p>\n</li>\n<li>\n<p><a href=\"https://www.gatsbyjs.com/pricing/\" title=\"pricing\">Gatsby</a> Free 100 GB, Professional 1 TB. Gatsby does not charge for overage,\nand they will contact the user if they continue to exceed bandwidth limits.</p>\n</li>\n<li>\n<p><a href=\"https://render.com/pricing\" title=\"pricing\">Render</a> 100 GB free, then $0.10 per GB.</p>\n</li>\n<li>\n<p><a href=\"https://www.koyeb.com/docs/faqs/pricing#how-does-charging-for-outbound-bandwidth-work\" title=\"charging for outbound bandwidth\">Koyeb</a> 100 GB free, then $0.04 per GB (not charged yet).</p>\n</li>\n<li>\n<p><a href=\"https://railway.app/pricing\" title=\"pricing\">Railway</a> 100 GB free for all the plans. Overage billing is not mentioned on\ntheir pricing page. And I suspect overage billing or throttling has not been\nimplemented yet on their platform yet since I found this paragraph on their\n<a href=\"https://docs.railway.app/reference/usecases\" title=\"Railway usecases\">documentation</a>:</p>\n<blockquote>\n<p>Railway doesn't meter bandwidth within Projects and the broader internet. As\nsuch, we have had projects handle unexpected traffic and features on major\nmedia publications. It is something we are very proud of. ... We do have\nplans to include private networking, static IPs, and allowing people to set\nup firewall rules to control permitted traffic within their projects.</p>\n</blockquote>\n</li>\n<li>\n<p><a href=\"https://fly.io/docs/about/pricing/\" title=\"pricing\">Fly</a> 100/30/30 GB free for North America &#x26; Europe / Other / India, then\n$0.02/$0.04/$0.12 per GB. The price for 1 TB listed in the table above assumes\nbandwidth from North America or Europe.</p>\n</li>\n<li>\n<p><a href=\"https://leancloud.app/pricing\" title=\"pricing\">LeanCloud</a> offers a free trial instance with 1 GB free bandwidth per day,\nthen $0.1/GB for overage. The price listed in the table above assumes the site\nexceeds the free quota every day and there are 30 days in month. The free\ntrial instance will hibernate if it has run more than 18 hours in the past 24\nhours or no request is made in the past 30 minutes. The standard instance (no\nhibernation) costs $1.6 per day.</p>\n<p>BTW, bandwidth usage was <a href=\"https://github.com/leancloud/docs-en/pull/107\" title=\"documentation update\">unmetered until Novermber 2019</a>.</p>\n</li>\n<li>\n<p><a href=\"https://devcenter.heroku.com/articles/usage-and-billing\" title=\"pricing\">Heroku</a> The Hobby plan is the cheapest one, costing $7 per month. Bandwidth\nis <a href=\"https://devcenter.heroku.com/articles/limits#network\" title=\"Heroku limits\">soft limited at 2 TB</a>. Overage bandwidth billing is not mentioned on their\nsite.</p>\n</li>\n<li>\n<p><a href=\"https://docs.github.com/en/pages/getting-started-with-github-pages/about-github-pages#usage-limits\" title=\"usage limits\">GitHub Pages</a> is free and there is a soft bandwidth limit of 100 GB per\nmonth.</p>\n</li>\n<li>\n<p><a href=\"https://pages.cloudflare.com/\" title=\"official site\">Cloudflare Pages</a> features <a href=\"https://webmasters.stackexchange.com/questions/88659/how-can-cloudflare-offer-a-free-cdn-with-unlimited-bandwidth\" title=\"Matthew Prince, Cloudflare Co-founder explains why offering free unlimited bandwidth\">unlimited bandwidth</a>. Use it for serving video or\na disproportionate percentage of pictures, audio files, or other non-HTML\ncontent is against their <a href=\"https://www.cloudflare.com/terms/\" title=\"2.8 Limitation on Serving Non-HTML Content\">terms</a> though.</p>\n</li>\n<li>\n<p>Both <a href=\"https://docs.digitalocean.com/products/droplets/details/pricing/\" title=\"Droplet Pricing\">Digital Ocean</a> and <a href=\"https://www.linode.com/docs/guides/network-transfer/\" title=\"Transfer Allowance\">Linode</a> includes 1 TB bandwidth for the cheapest VPS\nplan. Additional transfer is billed at $0.01 per GB.</p>\n</li>\n</ul>","date_published":"Wed, 26 Apr 2023 06:16:24 GMT","date_modified":"Wed, 20 Dec 2023 04:08:02 GMT"},{"id":"https://mmap.page/thoughts/typescrit-slogan/","url":"https://mmap.page/thoughts/typescrit-slogan/","title":"A History of TypeScript Slogans","content_html":"<h1>A History of TypeScript Slogans</h1>\n<ol>\n<li>TypeScript is a superset of JavaScript.<sup><a href=\"https://mmap.page/thoughts/typescrit-slogan/#user-content-fn-1\" id=\"user-content-fnref-1\" data-footnote-ref aria-describedby=\"footnote-label\">1</a></sup></li>\n<li>TypeScript is JavaScript that scales.<sup><a href=\"https://mmap.page/thoughts/typescrit-slogan/#user-content-fn-2\" id=\"user-content-fnref-2\" data-footnote-ref aria-describedby=\"footnote-label\">2</a></sup></li>\n<li>TypeScript is just JavaScript with types.<sup><a href=\"https://mmap.page/thoughts/typescrit-slogan/#user-content-fn-3\" id=\"user-content-fnref-3\" data-footnote-ref aria-describedby=\"footnote-label\">3</a></sup></li>\n<li>TypeScript is JavaScript with syntax for types.<sup><a href=\"https://mmap.page/thoughts/typescrit-slogan/#user-content-fn-4\" id=\"user-content-fnref-4\" data-footnote-ref aria-describedby=\"footnote-label\">4</a></sup></li>\n<li>TypeScript is JavaScript with types, unsound.<sup><a href=\"https://mmap.page/thoughts/typescrit-slogan/#user-content-fn-5\" id=\"user-content-fnref-5\" data-footnote-ref aria-describedby=\"footnote-label\">5</a></sup></li>\n</ol>\n<section data-footnotes class=\"footnotes\"><h2 class=\"sr-only\" id=\"footnote-label\">Footnotes</h2>\n<ol>\n<li id=\"user-content-fn-1\">\n<p>TypeScript wants to attract CoffeeScript and Dart developers. <a href=\"https://mmap.page/thoughts/typescrit-slogan/#user-content-fnref-1\" data-footnote-backref=\"\" aria-label=\"Back to reference 1\" class=\"data-footnote-backref\">↩</a></p>\n</li>\n<li id=\"user-content-fn-2\">\n<p>TypeScript wants to attract developers on large or hope to be large projects. <a href=\"https://mmap.page/thoughts/typescrit-slogan/#user-content-fnref-2\" data-footnote-backref=\"\" aria-label=\"Back to reference 2\" class=\"data-footnote-backref\">↩</a></p>\n</li>\n<li id=\"user-content-fn-3\">\n<p>TypeScript wants to attract all JavaScript developers. <a href=\"https://mmap.page/thoughts/typescrit-slogan/#user-content-fnref-3\" data-footnote-backref=\"\" aria-label=\"Back to reference 3\" class=\"data-footnote-backref\">↩</a></p>\n</li>\n<li id=\"user-content-fn-4\">\n<p>TypeScript wants to attract all JavaScript developers, including those who have no idea what typing means and thought it is just a syntax thing. <a href=\"https://mmap.page/thoughts/typescrit-slogan/#user-content-fnref-4\" data-footnote-backref=\"\" aria-label=\"Back to reference 4\" class=\"data-footnote-backref\">↩</a></p>\n</li>\n<li id=\"user-content-fn-5\">\n<p>I just could help myself from listing this <em>fake</em> slogan occurred to my mind. <a href=\"https://mmap.page/thoughts/typescrit-slogan/#user-content-fnref-5\" data-footnote-backref=\"\" aria-label=\"Back to reference 5\" class=\"data-footnote-backref\">↩</a></p>\n</li>\n</ol>\n</section>","date_published":"Tue, 25 Apr 2023 08:48:15 GMT","date_modified":"Tue, 25 Apr 2023 08:48:15 GMT"},{"id":"https://mmap.page/coding-style/javascript/","url":"https://mmap.page/coding-style/javascript/","title":"JavaScript Coding Style","content_html":"<h1>JavaScript Coding Style</h1>\n<p>I prefer to <a href=\"https://mmap.page/coding-style/javascript/100-percent-js.md\">not include TypeScript definitions in pure JavaScript projects</a>.</p>\n<p>See <a href=\"https://mmap.page/coding-style/dive-into/eslint.md\">An Optioned Guide to ESLint</a> for ESLint configurations.</p>","date_published":"Tue, 25 Apr 2023 08:09:37 GMT","date_modified":"Tue, 25 Apr 2023 08:09:37 GMT"},{"id":"https://mmap.page/coding-style/typescript/","url":"https://mmap.page/coding-style/typescript/","title":"TypeScript Coding Style","content_html":"<h1>TypeScript Coding Style</h1>\n<p>See <a href=\"https://mmap.page/coding-style/dive-into/eslint.md\">An Optioned Guide to ESLint</a>.</p>","date_published":"Mon, 24 Apr 2023 08:23:55 GMT","date_modified":"Mon, 24 Apr 2023 08:23:55 GMT"},{"id":"https://mmap.page/coding-style/sh/","url":"https://mmap.page/coding-style/sh/","title":"sh Coding Style","content_html":"<h1>sh Coding Style</h1>\n<h2>Abstract</h2>\n<pre><code class=\"language-sh\">cat <span class=\"pl-s\"><span class=\"pl-k\">&#x3C;&#x3C;</span> <span class=\"pl-k\">END</span></span>\n<span class=\"pl-s\">set -e</span>\n<span class=\"pl-s\">snake_case() {</span>\n<span class=\"pl-s\">  local foo=bar</span>\n<span class=\"pl-s\">  some-command --long-option \"<span class=\"pl-smi\">$foo</span>\"</span>\n<span class=\"pl-s\">}</span>\n<span class=\"pl-s\"><span class=\"pl-k\">END</span></span> <span class=\"pl-k\">|</span> dash\n</code></pre>\n<h2>Naming</h2>\n<p>We prefer <code>hyphen-word</code> over <code>snake_case</code> over <code>CamelCase</code>.\nHowever, <code>dash</code> <a href=\"https://github.com/mirror/busybox/blob/1_23_stable/libbb/endofname.c\">only allows <code>_</code> and alnum as variable names</a>.\nThus, <code>snake_case</code> is preferred.</p>\n<h2>Short options</h2>\n<p>We prefer <code>--long</code> for self-documentation.</p>\n<h2>Compatibility</h2>\n<p>Test against dash.</p>\n<h2>Fails early</h2>\n<p>Use <code>set -e</code>.</p>\n<h2>Local variable</h2>\n<p>Use <code>local</code> variables in function definitions when possible.</p>","date_published":"Mon, 24 Apr 2023 08:23:55 GMT","date_modified":"Mon, 24 Apr 2023 08:23:55 GMT"},{"id":"https://mmap.page/search/","url":"https://mmap.page/search/","content_html":"<noscript>\n<p>This site uses <a href=\"https://pagefind.app/\" title=\"Pagefind homepage\">Pagefind</a>,\na static search library, to implement the search function via JavaScript.\n</p>\n<p>If your browser does not enable or support JavaScript,\nplease consider enable JavaScript for this page,\nor switch to another browser to access this page.\n</p>\n<p>I am sorry for the inconvinience,\nbut implementing static site search without relying on external search engines requires JavaScript.\nAll other pages of this site do not use JavaScript.</p>\n<p>Alternatively, you can search this site via external search engines,\nfor example, <code>site:mmap.page keywords</code> on\n<a href=\"https://duckduckgo.com/\" title=\"DuckDuckGo search engine\">DuckDuckGo</a>.\nSome pages may not be indexed by search engines though.</p>\n<p>You can also search the source code at <a href=\"https://github.com/\" title=\"source code repository\">GitHub</a>.\nUnfortunately, the search function on GitHub website also requires JavaScript.\nBut you can use their <a href=\"https://docs.github.com/en/rest/search\" \"GitHub search REST API\">REST API</a> instead.</p>\n<p>And of course, you can clone the source repository of this site,\nand use any tool you preferred to serch it.</p>\n</noscript>\n<div id=\"search\"></div>","date_published":"Mon, 24 Apr 2023 08:04:45 GMT","date_modified":"Mon, 24 Apr 2023 08:04:45 GMT"},{"id":"https://mmap.page/coding-style/ruby/","url":"https://mmap.page/coding-style/ruby/","title":"Ruby Coding Style","content_html":"<h1>Ruby Coding Style</h1>\n<h2>Use <code>{}</code> for blocks returning value, and <code>do end</code> for other blocks.</h2>\n<pre><code class=\"language-ruby\">l <span class=\"pl-k\">=</span> [<span class=\"pl-c1\">1</span>, <span class=\"pl-c1\">2</span>, <span class=\"pl-c1\">3</span>]\n\nl.each <span class=\"pl-k\">do</span> |<span class=\"pl-smi\">n</span>| n <span class=\"pl-k\">+=</span> <span class=\"pl-c1\">1</span> <span class=\"pl-k\">end</span>\n\nl.map { |<span class=\"pl-smi\">n</span>|\n  b <span class=\"pl-k\">=</span> (n <span class=\"pl-k\">+</span> <span class=\"pl-c1\">1</span>) <span class=\"pl-k\">*</span> (n <span class=\"pl-k\">+</span> <span class=\"pl-c1\">2</span>) <span class=\"pl-k\">/</span> <span class=\"pl-c1\">3.0</span>\n  b.to_s\n}\n\nidentity <span class=\"pl-k\">=</span> <span class=\"pl-c1\">-></span>(x) { x }\nsay <span class=\"pl-k\">=</span> <span class=\"pl-c1\">-></span>(x) <span class=\"pl-k\">do</span> <span class=\"pl-c1\">puts</span> x <span class=\"pl-k\">end</span>\n</code></pre>\n<h2>Avoid <code>Proc.new</code> and <code>proc</code>.</h2>\n<p>Avoid <code>Proc.new</code>.</p>\n<p>Never use <code>proc</code>. Its behavior is different for Ruby 1.8 and Ruby 1.9+.</p>\n<h2>Use <code>self</code> module functions.</h2>\n<p>Prefer</p>\n<pre><code class=\"language-ruby\">mod <span class=\"pl-c1\">M</span>\n  <span class=\"pl-k\">def</span> <span class=\"pl-c1\">self</span><span class=\"pl-en\">.a</span>; <span class=\"pl-s\"><span class=\"pl-pds\">'</span>a<span class=\"pl-pds\">'</span></span>; <span class=\"pl-k\">end</span>\n  <span class=\"pl-k\">def</span> <span class=\"pl-c1\">self</span><span class=\"pl-en\">.b</span>; <span class=\"pl-s\"><span class=\"pl-pds\">'</span>b<span class=\"pl-pds\">'</span></span>; <span class=\"pl-k\">end</span>\n  <span class=\"pl-c\"># more ...</span>\n<span class=\"pl-k\">end</span>\n\n<span class=\"pl-c1\">M</span>.a()\n</code></pre>\n<p>over</p>\n<pre><code class=\"language-ruby\"><span class=\"pl-k\">module</span> <span class=\"pl-en\">M</span>\n  <span class=\"pl-c\"># module_function will copy the functions. No need to make duplicated</span>\n  <span class=\"pl-c\"># functions unless you want to let other classes include your module</span>\n  <span class=\"pl-c\"># and let them pollute other classes' namespcae.</span>\n  <span class=\"pl-k\">module_function</span>\n\n  <span class=\"pl-k\">def</span> <span class=\"pl-en\">a</span>; <span class=\"pl-s\"><span class=\"pl-pds\">'</span>a<span class=\"pl-pds\">'</span></span>; <span class=\"pl-k\">end</span>\n  <span class=\"pl-k\">def</span> <span class=\"pl-en\">b</span>; <span class=\"pl-s\"><span class=\"pl-pds\">'</span>b<span class=\"pl-pds\">'</span></span>; <span class=\"pl-k\">end</span>\n  <span class=\"pl-c\"># more ...</span>\n<span class=\"pl-k\">end</span>\n\n<span class=\"pl-c1\">M</span>.a()\n</code></pre>\n<p>over</p>\n<pre><code class=\"language-ruby\"><span class=\"pl-k\">class</span> <span class=\"pl-en\">C</span>\n  <span class=\"pl-c\"># Do not build a class just for some functions. Use module for this.</span>\n  <span class=\"pl-k\">class</span> &#x3C;&#x3C; <span class=\"pl-smi\">self</span>\n\n    <span class=\"pl-k\">def</span> <span class=\"pl-en\">a</span>; <span class=\"pl-s\"><span class=\"pl-pds\">'</span>a<span class=\"pl-pds\">'</span></span>; <span class=\"pl-k\">end</span>\n    <span class=\"pl-k\">def</span> <span class=\"pl-en\">b</span>; <span class=\"pl-s\"><span class=\"pl-pds\">'</span>b<span class=\"pl-pds\">'</span></span>; <span class=\"pl-k\">end</span>\n    <span class=\"pl-c\"># more ...</span>\n  <span class=\"pl-k\">end</span>\n<span class=\"pl-k\">end</span>\n\n<span class=\"pl-c1\">C</span>.a()\n</code></pre>\n<p>and</p>\n<pre><code class=\"language-ruby\"><span class=\"pl-k\">class</span> <span class=\"pl-en\">C</span>\n  <span class=\"pl-k\">def</span> <span class=\"pl-en\">a</span>; <span class=\"pl-s\"><span class=\"pl-pds\">'</span>a<span class=\"pl-pds\">'</span></span>; <span class=\"pl-k\">end</span>\n  <span class=\"pl-k\">def</span> <span class=\"pl-en\">b</span>; <span class=\"pl-s\"><span class=\"pl-pds\">'</span>b<span class=\"pl-pds\">'</span></span>; <span class=\"pl-k\">end</span>\n  <span class=\"pl-c\"># more ...</span>\n<span class=\"pl-k\">end</span>\n\n<span class=\"pl-c\"># This is redundant.</span>\nc <span class=\"pl-k\">=</span> <span class=\"pl-c1\">C</span>.<span class=\"pl-k\">new</span>()\nc.a()\n</code></pre>","date_published":"Sun, 23 Apr 2023 10:25:54 GMT","date_modified":"Sun, 23 Apr 2023 10:25:54 GMT"},{"id":"https://mmap.page/coding-style/100-percent-js/","url":"https://mmap.page/coding-style/100-percent-js/","title":"100% JavaScript Project","content_html":"<h1>100% JavaScript Project</h1>\n<p><a href=\"https://github.com/ljharb\">Jordan Hairband</a> chooses to not include TypeScript definitions in <a href=\"https://github.com/substack/tape/issues/353\">Tape</a>:</p>\n<blockquote>\n<p>No. Typings should never be packaged with individual repos,\nespecially because maintainers who don't use typescript\nhave no friendly way to keep the typings in sync.</p>\n<p>DT or similar is the proper place for types, until JavaScript has them natively.</p>\n<p>...</p>\n<p>The tape codebase will not be written in anything but JavaScript.</p>\n<p>...</p>\n<p>I would encourage you, however, to submit accurate typings for all the tape versions to DT,\nto benefit all TypeScript users - and if there’s anything short of using TS\nthat i can do to make it easier for TS users to use tape, I’d be happy to.</p>\n</blockquote>\n<p>Mentioning TypeScript in README is also <a href=\"https://github.com/substack/tape/issues/574\">refused</a>:</p>\n<blockquote>\n<p>I don’t think that’s necessary.\nA typescript user should already know how to use ts-node with everything if needed,\nand the advice isn’t different with tape than with anything else.\nIt’s not incumbent on “every individual non-typescript package” to make typescript easy to use;\nthat’s typescript’s task.</p>\n<p>...</p>\n<p>...an alternative without ts-node is to transpile first and test the output.</p>\n<p>This is just the sort of thing that you open yourself to\nby making the choice to use “not JavaScript”,\nand it’s not practical for millions of individual JS packages to try to document\nall the caveats you need to know when making that choice.</p>\n</blockquote>\n<p>Besides, strictly speaking, if a library includes <code>.d.ts</code>,\nthen it needs to add typescript as its dependency <em>not</em> dev dependency.\nOtherwise, if the type definitions include features not available on old versions of TypeScript,\nor not compatible with breaking changes from future versions of TypeScript,\nit will not work for the library users, at least causing problems on their IDEs or editors.</p>\n<p>If types are published under <code>@types/foo</code>,\nusers of the library need to install an additional package.\nAlso, this separation requires extra configuration for the package maintainers.</p>\n<p>To be honest, TypeScript may be considered as a special case.\nTypeScript is not added to the dependencies list,\nassuming the type definitions of the library will work with all recent TypeScript versions.\nAnd the users of the library can install the right TypeScript version manually\nspecified in the dev dependencies, as a last resort,\nif they encountered problems, which should be a rare condition.\nAlthough this dependency specification is not rigid,\nit should work well in practical.</p>","date_published":"Thu, 08 Sep 2022 09:36:07 GMT","date_modified":"Tue, 25 Apr 2023 08:09:37 GMT"},{"id":"https://mmap.page/vim/spell/","url":"https://mmap.page/vim/spell/","title":"Spell Checking in Vim","content_html":"<h1>Spell Checking in Vim</h1>\n<p>Vim has built-in support for spell checking.\nThis built-in function provides basic spell checking.\nFor example, it does not recognize 'localhost', 'Lua' or 'Node.js'.\nHowever, new words can be added quickly via <code>zg</code> in normal mode.</p>\n<p>To check grammar and stylish errors,\nGrammarly or <a href=\"https://languagetool.org/\">LanguageTool</a> can be used.</p>\n<p>I prefer LanguageTool because it is open source.\nAll the errors can be checked with <a href=\"https://valentjn.github.io/ltex/\">ltex-ls</a> locally,\nwithout making any network requests.</p>\n<p>Unfortunately, ltex-ls <a href=\"https://github.com/valentjn/ltex-ls/issues/168\">does not support adding unknown words to dictionary</a>.\nPreviously, as a workaround, I disabled the spell checking rule from ltex-ls,\nand use Neovim's built-in spell checking instead.\nNow I use <a href=\"https://github.com/barreiroleo/ltex_extra.nvim\">ltex_extra.nvim</a>, which provides code actions for adding unknown words, disable rules, and hide false positives.</p>\n<p>BTW, the Grammarly LSP <a href=\"https://github.com/znck/grammarly/discussions/294\">does not support this</a>, either.</p>","date_published":"Mon, 05 Sep 2022 08:51:52 GMT","date_modified":"Thu, 18 Jan 2024 11:47:55 GMT"},{"id":"https://mmap.page/dapi/windows-handbook/","url":"https://mmap.page/dapi/windows-handbook/","title":"Windows 使用手冊","content_html":"<h1>Windows 使用手冊</h1>\n<h2>使用 Windows 的理由</h2>\n<ul>\n<li>衆所周知，好人纔能用蘋果電腦，顯然我不是好人。</li>\n<li>標榜 KISS 的 Arch 居然使用 Systemd，讓我大失所望。要說功能強大，Windows 比 Systemd 強大多了。所以與其讓 Systemd 來啓動 Linux，不如乾脆讓 Windows 來啓動。</li>\n<li>最主要的，我比較害怕蟑螂。目前 Windows 系統自帶的 unicode 版本還不夠新，蟑螂 emoji 會顯示成豆腐塊。</li>\n</ul>\n<h2>軟體</h2>\n<ul>\n<li><strong>Debian</strong> 我最熟悉的發行版</li>\n<li><strong>Vivaldi</strong> Opera 創始人復活了 Mozilla Application Suite</li>\n<li><strong>Visual Studio Code</strong> 其實我不怎麼喜歡，無奈它的生態實在太好了，比如 GitHub Copilot 和 WSL2 都是開箱即用。</li>\n<li><strong>小狼毫</strong> 系統自帶的微軟拼音並不尊重英文鍵盤佈局，還要改註冊表纔能換到 dvorak 佈局，也不方便輸入直角引號。</li>\n<li><strong>Notepad++</strong> 輕便的文本編輯器</li>\n<li><strong>Windows Terminal</strong> 應該預裝卻沒有預裝的終端模擬器</li>\n<li><strong>PowerToys</strong> 這些功能也應該直接做進系統</li>\n</ul>\n<h2>Docker</h2>\n<p>鑑於 Docker Desktop For Windows 的許可問題，我直接在 WSL2 的 Debian 裏安裝了 Docker.\r\nWSL2 中的 Debian 環境和標準 Debian 有所差異（比如沒有 systemd），所以 Docker 不能開箱即用，需要額外進行一些配置，詳見<a href=\"https://github.com/microsoft/WSL/discussions/4872#discussioncomment-76635\">這裏的說明</a>。</p>\n<h2>命令行下訪問剪貼板</h2>\n<p>WSL 2 下可以使用 <code>powershell.exe Get-Clipboard</code> 和 <code>clip.exe</code> 讀寫剪貼板的內容：</p>\n<pre><code class=\"language-sh\">powershell.exe Get-Clipboard <span class=\"pl-k\">|</span> cut -d <span class=\"pl-s\"><span class=\"pl-pds\">'</span>,<span class=\"pl-pds\">'</span></span> -f1 <span class=\"pl-k\">|</span> clip.exe\n</code></pre>","date_published":"Fri, 03 Sep 2021 17:25:36 GMT","date_modified":"Thu, 09 Sep 2021 11:51:24 GMT"},{"id":"https://mmap.page/dive-into/jekyll-zeronet/","url":"https://mmap.page/dive-into/jekyll-zeronet/","title":"Deploy Jekyll Site to ZeroNet","content_html":"<h1>Deploy Jekyll Site to ZeroNet</h1>\n<p><strong>This guide is outdated and unmaintained.</strong>\nThe development of ZeroNet ceased.</p>\n<h2>Basic Setup</h2>\n<p>A basic setup is mostly straightforward.\nThe only thing to pay attention to is avoiding broken links.</p>\n<p>Typically, the jekyll site will be deployed to <code>https://some.domain.example</code> (root path) and <code>https://127.0.0.1:43110/some-zite-address/</code> (with zite address as the preceding path).\nThus if not careful, there will be broken links on your clearnet site or/and ZeroNet site.</p>\n<p>As a rule of thumb, keep all internal links within the page content (markdown files) as relative to current path links.\nFor example, the homepage of this site links to this page as <code>[Deploy Jekyll Site to ZeroNet](dive-into/jekyll-zeronet/)</code>.\nRelative to current path links work both under <code>https://some.domain.example</code> and <code>https://127.0.0.1:43110/some-zite-address/</code>.</p>\n<p>For links in page templates, you have several options:</p>\n<ol>\n<li>\n<p>Keep all pages in one directory, thus relative to current path links can be used in page templates.</p>\n</li>\n<li>\n<p>Use different templates for pages under different directories, or at least pages under different depth of directories.\nThis also allows for relative to current path links in page templates.</p>\n</li>\n<li>\n<p>If your site may have arbitrary levels of directories and you want to use just one template for them all, then you can choose a ZeroNet first approach, using your zite address as the base path of your clearnet site.\nFor example, if your zite address is <code>16XMwj6YRNqRHWbmSD8oxYUZCKfM1uzwP9</code> and clearnet site domain is <code>mmap.page</code>, then you can host your clearnet site under <code>https://mmap.page/16XMwj6YRNqRHWbmSD8oxYUZCKfM1uzwP9</code>. This way, you can use relative to document root links in page templates, such as <code>/16XMwj6YRNqRHWbmSD8oxYUZCKfM1uzwP9/assets/css/style.css</code>.</p>\n</li>\n<li>\n<p>You can also use absolute links via template variable in page templates.\nFirst, you define the site variable <code>url</code> as your clearnet url, e.g. <code>https://mmap.page</code>.\nNow comes the tricky part.\nJekyll allows any value for the site url variable.\nThus you can specify it as <code>/zite-address</code> for ZeroNet deployment.\nFor example, <code>url: /16XMwj6YRNqRHWbmSD8oxYUZCKfM1uzwP9</code>.\nNote that you should not use <code>https://127.0.0.1:43110/some-zite-address</code> here, since other users may bind a different IP or port for their ZeroNet service.\nThen you can use {{site.url}} to construct absolute links in page templates,\ne.g. {{site.url}}/assets/css/style.css.</p>\n</li>\n</ol>\n<h2>Multiple Configurations</h2>\n<p>Jekyll can accept multiple configuration files.\nThus if most of your configurations are the same for clearnet and ZeroNet, you can do most configurations in <code>_config.yml</code>, then append or override some configurations in <code>_zeronet.yml</code> or <code>_clearnet.yml</code>.\nFor example, my <code>_zeronet.yml</code> only contains one line <code>url: /16XMwj6YRNqRHWbmSD8oxYUZCKfM1uzwP9</code> and I run the following command to generate a static site for ZeroNet deployment.</p>\n<pre><code class=\"language-sh\">bundle <span class=\"pl-c1\">exec</span> jekyll build --config _config.yml,_zeronet.yml -d /path/to/ZeroNet/data/16XMwj6YRNqRHWbmSD8oxYUZCKfM1uzwP9/\n</code></pre>\n<h2>Conditional Content</h2>\n<p>You can use conditional expressions in Jekyll templates to display different content on clearnet and ZeroNet.</p>\n<p>For example, to display a greyscale version of ZeroNet logo on clearnet, while keeping the logo colorful on ZeroNet:</p>\n<p>{% raw %}</p>\n<pre><code class=\"language-liquid\">{% <span class=\"pl-ent\">assign</span> <span class=\"pl-smi\">leading</span> = <span class=\"pl-smi\">site</span>.<span class=\"pl-smi\">url</span> | <span class=\"pl-c1\">slice:</span> <span class=\"pl-c1\">0</span> %}\n{% <span class=\"pl-k\">if</span> <span class=\"pl-smi\">leading</span> <span class=\"pl-k\">==</span> <span class=\"pl-s\">'/'</span> %}\n    {% <span class=\"pl-ent\">assign</span> <span class=\"pl-smi\">zeronet_logo</span> = <span class=\"pl-s\">'zeronet_logo.svg'</span> %}\n{% <span class=\"pl-k\">else</span> %}\n    {% <span class=\"pl-ent\">assign</span> <span class=\"pl-smi\">zeronet_logo</span> = <span class=\"pl-s\">'zeronet_grey.svg'</span> %}\n{% <span class=\"pl-k\">endif</span> %}\n&#x3C;<span class=\"pl-ent\">img</span> <span class=\"pl-e\">src</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>{{ <span class=\"pl-smi\">site</span>.<span class=\"pl-smi\">url</span> }}/assets/images/{{ <span class=\"pl-smi\">zeronet_logo</span> }}<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">alt</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>ZeroNet Logo<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">width</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>32<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">height</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>32<span class=\"pl-pds\">\"</span></span>>\n</code></pre>\n<p>{% endraw %}</p>\n<p>Here I chose the fourth option (<code>site.url</code>) mentioned in the \"Basic Setup\" section,\nthus I decide if it is on ZeroNet by checking if <code>site.url</code> starts with <code>/</code>.\nIf you use other options, you can define an additional boolean option on your <code>_zeronet.yml</code> or <code>_clearnet.yml</code>,\nand ues it to detect the deployment environment.</p>\n<h2>RSS</h2>\n<p>Unfortunately, RSS does not like relative links.\nIf your sites need RSS, then you have to replace relative links with absolute ones in templates.\nSince the Liquid template language Jekyll uses is quite limited,\nI chose to use <strong>relative to document root links</strong> in page content, which makes it easier to finding these links via Liquid template languages (just looks for <code>&#x3C;a href=\"https://mmap.page/%3C/code%3E%20and%20%3Ccode%3E&#x3C;img%20src=\"/></code>).</p>\n<p>In RSS template, I implemented something like this:</p>\n<p>{% raw %}</p>\n<pre><code class=\"language-liquid\">{% <span class=\"pl-ent\">assign</span> <span class=\"pl-smi\">absolutelink</span> = <span class=\"pl-s\">'&#x3C;a href=\"https://mmap.page/dive-into/jekyll-zeronet/'%3C/span%3E%20|%20%3Cspan%20class=\"pl-c1\">append:</span> <span class=\"pl-v\">site</span>.<span class=\"pl-smi\">url</span> | <span class=\"pl-c1\">append:</span> <span class=\"pl-s\">'/'</span> %}\n{% <span class=\"pl-ent\">assign</span> <span class=\"pl-smi\">absoluteimglink</span> = <span class=\"pl-s\">'&#x3C;img src='</span> | <span class=\"pl-c1\">append:</span> <span class=\"pl-v\">site</span>.<span class=\"pl-smi\">url</span> | <span class=\"pl-c1\">append:</span> <span class=\"pl-s\">'/'</span> %}\n&#x3C;<span class=\"pl-ent\">description</span>>{{ <span class=\"pl-smi\">page_content</span> | <span class=\"pl-c1\">markdownify</span> | <span class=\"pl-c1\">replace:</span> <span class=\"pl-s\">'&#x3C;a href=\"https://mmap.page/'%3C/span%3E,%20%3Cspan%20class=\"pl-smi\">absolutelink</span> | <span class=\"pl-c1\">replace:</span> <span class=\"pl-s\">'&#x3C;img src=\"https://mmap.page/'%3C/span%3E,%20%3Cspan%20class=\"pl-smi\">absoluteimglink</span> | <span class=\"pl-c1\">xml_escape</span>}}&#x3C;/<span class=\"pl-ent\">description</span>>\n</code></pre>\n<p>{% endraw %}</p>\n<p>I also implemented similar logic in default page template to avoid broken links since now relative to document root links are used.</p>\n<p>Alternatively, you can write some lengthy liquid template processing logic or write a post-process script in other programming languages to find and replace all relative links.\nThis way, you can keep using relative to current path in page content and keep the default page template intact.</p>","date_published":"Sat, 30 Jan 2021 06:27:33 GMT","date_modified":"Tue, 06 Sep 2022 05:08:10 GMT"},{"id":"https://mmap.page/lists/vps/","url":"https://mmap.page/lists/vps/","title":"Virtual Private Servers List","content_html":"<h1>Virtual Private Servers List</h1>\n<p>Boring fact: Among all regions of AWS EC2, Cape Town, Mumbai, Hong Kong, and Singapore are the only four not governed by a country that belongs to <a href=\"https://en.wikipedia.org/wiki/NATO\">NATO</a>, <a href=\"https://en.wikipedia.org/wiki/Partnership_for_Peace\">PfP</a>, or <a href=\"https://en.wikipedia.org/wiki/Major_non-NATO_ally\">MNNA</a>.</p>\n<pre><code class=\"language-json\">[\n    {\n        <span class=\"pl-ent\">\"provider\"</span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>BuyVM<span class=\"pl-pds\">\"</span></span>,\n        <span class=\"pl-ent\">\"url\"</span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>https://buyvm.net/kvm-dedicated-server-slices/<span class=\"pl-pds\">\"</span></span>,\n        <span class=\"pl-ent\">\"ram\"</span>: <span class=\"pl-c1\">512</span>,\n        <span class=\"pl-ent\">\"disk\"</span>: <span class=\"pl-c1\">10</span>,\n        <span class=\"pl-ent\">\"bandwidth\"</span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>unmetered<span class=\"pl-pds\">\"</span></span>,\n        <span class=\"pl-ent\">\"ipv4\"</span>: <span class=\"pl-c1\">1</span>,\n        <span class=\"pl-ent\">\"monthly\"</span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>$2<span class=\"pl-pds\">\"</span></span>,\n        <span class=\"pl-ent\">\"regions\"</span>: [\n            <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>us<span class=\"pl-pds\">\"</span></span>,\n            <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>lu<span class=\"pl-pds\">\"</span></span>\n        ]\n    },\n    {\n        <span class=\"pl-ent\">\"provider\"</span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>TinyKVM<span class=\"pl-pds\">\"</span></span>,\n        <span class=\"pl-ent\">\"url\"</span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>https://tinykvm.com<span class=\"pl-pds\">\"</span></span>,\n        <span class=\"pl-ent\">\"ram\"</span>: <span class=\"pl-c1\">256</span>,\n        <span class=\"pl-ent\">\"disk\"</span>: <span class=\"pl-c1\">7</span>,\n        <span class=\"pl-ent\">\"bandwidth\"</span>: <span class=\"pl-c1\">200</span>,\n        <span class=\"pl-ent\">\"yearly\"</span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>$15<span class=\"pl-pds\">\"</span></span>,\n        <span class=\"pl-ent\">\"regions\"</span>: [\n            <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>us<span class=\"pl-pds\">\"</span></span>\n        ]\n    },\n    {\n        <span class=\"pl-ent\">\"provider\"</span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>AnyNode<span class=\"pl-pds\">\"</span></span>,\n        <span class=\"pl-ent\">\"url\"</span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>https://anynode.net/vps-kvm-ssd.php<span class=\"pl-pds\">\"</span></span>,\n        <span class=\"pl-ent\">\"ram\"</span>: <span class=\"pl-c1\">256</span>,\n        <span class=\"pl-ent\">\"disk\"</span>: <span class=\"pl-c1\">10</span>,\n        <span class=\"pl-ent\">\"bandwidth\"</span>: <span class=\"pl-c1\">500</span>,\n        <span class=\"pl-ent\">\"yearly\"</span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>$15<span class=\"pl-pds\">\"</span></span>,\n        <span class=\"pl-ent\">\"regions\"</span>: [\n            <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>us<span class=\"pl-pds\">\"</span></span>\n        ]\n    },\n    {\n        <span class=\"pl-ent\">\"provider\"</span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>AnyNode<span class=\"pl-pds\">\"</span></span>,\n        <span class=\"pl-ent\">\"url\"</span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>https://anynode.net/vps-kvm-ssd.php<span class=\"pl-pds\">\"</span></span>,\n        <span class=\"pl-ent\">\"ram\"</span>: <span class=\"pl-c1\">512</span>,\n        <span class=\"pl-ent\">\"disk\"</span>: <span class=\"pl-c1\">15</span>,\n        <span class=\"pl-ent\">\"bandwidth\"</span>: <span class=\"pl-c1\">500</span>,\n        <span class=\"pl-ent\">\"monthly\"</span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>$2.5<span class=\"pl-pds\">\"</span></span>,\n        <span class=\"pl-ent\">\"regions\"</span>: [\n            <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>us<span class=\"pl-pds\">\"</span></span>\n        ]\n    },\n    {\n        <span class=\"pl-ent\">\"provider\"</span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>Somagu<span class=\"pl-pds\">\"</span></span>,\n        <span class=\"pl-ent\">\"url\"</span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>https://www.somagu.com<span class=\"pl-pds\">\"</span></span>,\n        <span class=\"pl-ent\">\"ram\"</span>: <span class=\"pl-c1\">512</span>,\n        <span class=\"pl-ent\">\"disk\"</span>: <span class=\"pl-c1\">20</span>,\n        <span class=\"pl-ent\">\"ipv4\"</span>: <span class=\"pl-c1\">0</span>,\n        <span class=\"pl-ent\">\"bandwidth\"</span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>90 KRW per 1 GiB, inbound &#x26; outbound<span class=\"pl-pds\">\"</span></span>,\n        <span class=\"pl-ent\">\"monthly\"</span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>$0.65<span class=\"pl-pds\">\"</span></span>,\n        <span class=\"pl-ent\">\"regions\"</span>: [\n            <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>kr<span class=\"pl-pds\">\"</span></span>\n        ]\n    },\n    {\n        <span class=\"pl-ent\">\"provider\"</span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>iwStack<span class=\"pl-pds\">\"</span></span>,\n        <span class=\"pl-ent\">\"url\"</span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>https://iwstack.com<span class=\"pl-pds\">\"</span></span>,\n        <span class=\"pl-ent\">\"ram\"</span>: <span class=\"pl-c1\">512</span>,\n        <span class=\"pl-ent\">\"disk\"</span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>€0.0001 per GB per hour<span class=\"pl-pds\">\"</span></span>,\n        <span class=\"pl-ent\">\"ipv4\"</span>: <span class=\"pl-c1\">1</span>,\n        <span class=\"pl-ent\">\"bandwidth\"</span>: <span class=\"pl-c1\">2000</span>,\n        <span class=\"pl-ent\">\"hourly\"</span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>€0.003<span class=\"pl-pds\">\"</span></span>,\n        <span class=\"pl-ent\">\"regions\"</span>: [\n            <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>it<span class=\"pl-pds\">\"</span></span>,\n            <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>nl<span class=\"pl-pds\">\"</span></span>,\n            <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>ro<span class=\"pl-pds\">\"</span></span>\n        ]\n    },\n    {\n        <span class=\"pl-ent\">\"provider\"</span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>CloudCone<span class=\"pl-pds\">\"</span></span>,\n        <span class=\"pl-ent\">\"url\"</span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>https://cloudcone.com/cloud-servers/<span class=\"pl-pds\">\"</span></span>,\n        <span class=\"pl-ent\">\"ram\"</span>: <span class=\"pl-c1\">1024</span>,\n        <span class=\"pl-ent\">\"disk\"</span>: <span class=\"pl-c1\">20</span>,\n        <span class=\"pl-ent\">\"ipv4\"</span>: <span class=\"pl-c1\">1</span>,\n        <span class=\"pl-ent\">\"hourly\"</span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>$0.00498<span class=\"pl-pds\">\"</span></span>,\n        <span class=\"pl-ent\">\"regions\"</span>: [\n            <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>us<span class=\"pl-pds\">\"</span></span>\n        ],\n        <span class=\"pl-ent\">\"note\"</span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>Even when you have uploaded ssh key in panel, you have to run command manually to download ssh key on the vps! (Initial login need use password.) Also its REST API uses GET method for reboot/shutdown/create/destroy.<span class=\"pl-pds\">\"</span></span>\n    },\n    {\n        <span class=\"pl-ent\">\"provider\"</span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>Scaleway<span class=\"pl-pds\">\"</span></span>,\n        <span class=\"pl-ent\">\"url\"</span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>https: //www.scaleway.com/en/pricing/#virtual-instances<span class=\"pl-pds\">\"</span></span>,\n        <span class=\"pl-ent\">\"ram\"</span>: <span class=\"pl-c1\">1024</span>,\n        <span class=\"pl-ent\">\"disk\"</span>: <span class=\"pl-c1\">10</span>,\n        <span class=\"pl-ent\">\"ipv4\"</span>: <span class=\"pl-c1\">1</span>,\n        <span class=\"pl-ent\">\"bandwidth\"</span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>100 Mbit/s<span class=\"pl-pds\">\"</span></span>,\n        <span class=\"pl-ent\">\"hourly\"</span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>€0.0025<span class=\"pl-pds\">\"</span></span>,\n        <span class=\"pl-ent\">\"regions\"</span>: [\n            <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>fr<span class=\"pl-pds\">\"</span></span>,\n            <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>nl<span class=\"pl-pds\">\"</span></span>,\n            <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>pl<span class=\"pl-pds\">\"</span></span>\n        ]\n    },\n    {\n        <span class=\"pl-ent\">\"provider\"</span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>vultr<span class=\"pl-pds\">\"</span></span>,\n        <span class=\"pl-ent\">\"url\"</span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>https://www.vultr.com/products/cloud-compute/#pricing<span class=\"pl-pds\">\"</span></span>,\n        <span class=\"pl-ent\">\"ram\"</span>: <span class=\"pl-c1\">512</span>,\n        <span class=\"pl-ent\">\"disk\"</span>: <span class=\"pl-c1\">10</span>,\n        <span class=\"pl-ent\">\"ipv4\"</span>: <span class=\"pl-c1\">1</span>,\n        <span class=\"pl-ent\">\"bandwidth\"</span>: <span class=\"pl-c1\">500</span>,\n        <span class=\"pl-ent\">\"hourly\"</span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>$0.005<span class=\"pl-pds\">\"</span></span>\n    },\n    {\n        <span class=\"pl-ent\">\"provider\"</span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>vultr<span class=\"pl-pds\">\"</span></span>,\n        <span class=\"pl-ent\">\"url\"</span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>https://www.vultr.com/products/cloud-compute/#pricing<span class=\"pl-pds\">\"</span></span>,\n        <span class=\"pl-ent\">\"ram\"</span>: <span class=\"pl-c1\">512</span>,\n        <span class=\"pl-ent\">\"disk\"</span>: <span class=\"pl-c1\">10</span>,\n        <span class=\"pl-ent\">\"ipv4\"</span>: <span class=\"pl-c1\">0</span>,\n        <span class=\"pl-ent\">\"bandwidth\"</span>: <span class=\"pl-c1\">500</span>,\n        <span class=\"pl-ent\">\"hourly\"</span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>$0.004<span class=\"pl-pds\">\"</span></span>\n    },\n    {\n        <span class=\"pl-ent\">\"provider\"</span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>vultr<span class=\"pl-pds\">\"</span></span>,\n        <span class=\"pl-ent\">\"url\"</span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>https://www.vultr.com/products/cloud-compute/#pricing<span class=\"pl-pds\">\"</span></span>,\n        <span class=\"pl-ent\">\"ram\"</span>: <span class=\"pl-c1\">1024</span>,\n        <span class=\"pl-ent\">\"disk\"</span>: <span class=\"pl-c1\">25</span>,\n        <span class=\"pl-ent\">\"ipv4\"</span>: <span class=\"pl-c1\">1</span>,\n        <span class=\"pl-ent\">\"bandwidth\"</span>: <span class=\"pl-c1\">1000</span>,\n        <span class=\"pl-ent\">\"hourly\"</span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>$0.007<span class=\"pl-pds\">\"</span></span>,\n        <span class=\"pl-ent\">\"regions\"</span>: [\n            <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>au<span class=\"pl-pds\">\"</span></span>,\n            <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>ca<span class=\"pl-pds\">\"</span></span>,\n            <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>de<span class=\"pl-pds\">\"</span></span>,\n            <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>fr<span class=\"pl-pds\">\"</span></span>,\n            <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>jp<span class=\"pl-pds\">\"</span></span>,\n            <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>kr<span class=\"pl-pds\">\"</span></span>,\n            <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>nl<span class=\"pl-pds\">\"</span></span>,\n            <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>sg<span class=\"pl-pds\">\"</span></span>,\n            <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>uk<span class=\"pl-pds\">\"</span></span>,\n            <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>us<span class=\"pl-pds\">\"</span></span>\n        ]\n    },\n    {\n        <span class=\"pl-ent\">\"provider\"</span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>LunaNode<span class=\"pl-pds\">\"</span></span>,\n        <span class=\"pl-ent\">\"url\"</span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>https://www.lunanode.com/pricing<span class=\"pl-pds\">\"</span></span>,\n        <span class=\"pl-ent\">\"ram\"</span>: <span class=\"pl-c1\">512</span>,\n        <span class=\"pl-ent\">\"disk\"</span>: <span class=\"pl-c1\">15</span>,\n        <span class=\"pl-ent\">\"bandwidth\"</span>: <span class=\"pl-c1\">1000</span>,\n        <span class=\"pl-ent\">\"hourly\"</span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>$0.00625<span class=\"pl-pds\">\"</span></span>,\n        <span class=\"pl-ent\">\"regions\"</span>: [\n            <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>ca<span class=\"pl-pds\">\"</span></span>,\n            <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>fr<span class=\"pl-pds\">\"</span></span>\n        ]\n    },\n    {\n        <span class=\"pl-ent\">\"provider\"</span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>DigitalOcean<span class=\"pl-pds\">\"</span></span>,\n        <span class=\"pl-ent\">\"url\"</span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>https://www.digitalocean.com/pricing<span class=\"pl-pds\">\"</span></span>,\n        <span class=\"pl-ent\">\"ram\"</span>: <span class=\"pl-c1\">1024</span>,\n        <span class=\"pl-ent\">\"disk\"</span>: <span class=\"pl-c1\">25</span>,\n        <span class=\"pl-ent\">\"bandwidth\"</span>: <span class=\"pl-c1\">1000</span>,\n        <span class=\"pl-ent\">\"hourly\"</span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>$0.007<span class=\"pl-pds\">\"</span></span>,\n        <span class=\"pl-ent\">\"regions\"</span>: [\n            <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>ca<span class=\"pl-pds\">\"</span></span>,\n            <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>de<span class=\"pl-pds\">\"</span></span>,\n            <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>in<span class=\"pl-pds\">\"</span></span>,\n            <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>nl<span class=\"pl-pds\">\"</span></span>,\n            <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>sg<span class=\"pl-pds\">\"</span></span>,\n            <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>uk<span class=\"pl-pds\">\"</span></span>,\n            <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>us<span class=\"pl-pds\">\"</span></span>\n        ]\n    },\n    {\n        <span class=\"pl-ent\">\"provider\"</span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>Linode<span class=\"pl-pds\">\"</span></span>,\n        <span class=\"pl-ent\">\"url\"</span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>https://www.digitalocean.com/pricing<span class=\"pl-pds\">\"</span></span>,\n        <span class=\"pl-ent\">\"ram\"</span>: <span class=\"pl-c1\">1024</span>,\n        <span class=\"pl-ent\">\"disk\"</span>: <span class=\"pl-c1\">25</span>,\n        <span class=\"pl-ent\">\"bandwidth\"</span>: <span class=\"pl-c1\">1000</span>,\n        <span class=\"pl-ent\">\"hourly\"</span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>$0.0075<span class=\"pl-pds\">\"</span></span>,\n        <span class=\"pl-ent\">\"regions\"</span>: [\n            <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>au<span class=\"pl-pds\">\"</span></span>,\n            <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>ca<span class=\"pl-pds\">\"</span></span>,\n            <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>de<span class=\"pl-pds\">\"</span></span>,\n            <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>in<span class=\"pl-pds\">\"</span></span>,\n            <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>jp<span class=\"pl-pds\">\"</span></span>,\n            <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>sg<span class=\"pl-pds\">\"</span></span>,\n            <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>uk<span class=\"pl-pds\">\"</span></span>,\n            <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>us<span class=\"pl-pds\">\"</span></span>\n        ]\n    },\n    {\n        <span class=\"pl-ent\">\"provider\"</span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>Memset<span class=\"pl-pds\">\"</span></span>,\n        <span class=\"pl-ent\">\"url\"</span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>https://www.memset.com/services/cloud-iaas/pricing/<span class=\"pl-pds\">\"</span></span>,\n        <span class=\"pl-ent\">\"ram\"</span>: <span class=\"pl-c1\">1024</span>,\n        <span class=\"pl-ent\">\"hourly\"</span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>£0.0155<span class=\"pl-pds\">\"</span></span>,\n        <span class=\"pl-ent\">\"regions\"</span>: [<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>uk<span class=\"pl-pds\">\"</span></span>]\n    },\n    {\n        <span class=\"pl-ent\">\"provider\"</span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>Atlantic<span class=\"pl-pds\">\"</span></span>,\n        <span class=\"pl-ent\">\"url\"</span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>https://www.atlantic.net/vps-hosting/pricing/<span class=\"pl-pds\">\"</span></span>,\n        <span class=\"pl-ent\">\"ram\"</span>: <span class=\"pl-c1\">2048</span>,\n        <span class=\"pl-ent\">\"disk\"</span>: <span class=\"pl-c1\">50</span>,\n        <span class=\"pl-ent\">\"bandwidth\"</span>: <span class=\"pl-c1\">3000</span>,\n        <span class=\"pl-ent\">\"hourly\"</span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>$0.0149<span class=\"pl-pds\">\"</span></span>,\n        <span class=\"pl-ent\">\"regions\"</span>: [<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>ca<span class=\"pl-pds\">\"</span></span>, <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>uk<span class=\"pl-pds\">\"</span></span>, <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>us<span class=\"pl-pds\">\"</span></span>]\n    },\n    {\n        <span class=\"pl-ent\">\"provider\"</span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>ExoScale<span class=\"pl-pds\">\"</span></span>,\n        <span class=\"pl-ent\">\"url\"</span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>https://www.exoscale.com/pricing/<span class=\"pl-pds\">\"</span></span>,\n        <span class=\"pl-ent\">\"ram\"</span>: <span class=\"pl-c1\">512</span>,\n        <span class=\"pl-ent\">\"disk\"</span>: <span class=\"pl-c1\">10</span>,\n        <span class=\"pl-ent\">\"hourly\"</span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>$0.00694<span class=\"pl-pds\">\"</span></span>,\n        <span class=\"pl-ent\">\"regions\"</span>: [<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>at<span class=\"pl-pds\">\"</span></span>, <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>bg<span class=\"pl-pds\">\"</span></span>, <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>ch<span class=\"pl-pds\">\"</span></span>, <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>de<span class=\"pl-pds\">\"</span></span>]\n    },\n    {\n        <span class=\"pl-ent\">\"provider\"</span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>ConoHa<span class=\"pl-pds\">\"</span></span>,\n        <span class=\"pl-ent\">\"url\"</span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>https://www.conoha.jp/vps/pricing/<span class=\"pl-pds\">\"</span></span>,\n        <span class=\"pl-ent\">\"ram\"</span>: <span class=\"pl-c1\">512</span>,\n        <span class=\"pl-ent\">\"disk\"</span>: <span class=\"pl-c1\">30</span>,\n        <span class=\"pl-ent\">\"hourly\"</span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>1.0円<span class=\"pl-pds\">\"</span></span>,\n        <span class=\"pl-ent\">\"regions\"</span>: [<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>jp<span class=\"pl-pds\">\"</span></span>, <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>sg<span class=\"pl-pds\">\"</span></span>]\n    },\n    {\n        <span class=\"pl-ent\">\"provider\"</span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>AWS EC2 Nano<span class=\"pl-pds\">\"</span></span>,\n        <span class=\"pl-ent\">\"url\"</span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>https://aws.amazon.com/ec2/pricing/on-demand/<span class=\"pl-pds\">\"</span></span>,\n        <span class=\"pl-ent\">\"ram\"</span>: <span class=\"pl-c1\">512</span>,\n        <span class=\"pl-ent\">\"hourly\"</span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>$0.0042<span class=\"pl-pds\">\"</span></span>,\n        <span class=\"pl-ent\">\"regions\"</span>: [<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>au<span class=\"pl-pds\">\"</span></span>, <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>bh<span class=\"pl-pds\">\"</span></span>, <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>br<span class=\"pl-pds\">\"</span></span>, <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>ca<span class=\"pl-pds\">\"</span></span>, <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>de<span class=\"pl-pds\">\"</span></span>, <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>fr<span class=\"pl-pds\">\"</span></span>, <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>hk<span class=\"pl-pds\">\"</span></span>, <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>ie<span class=\"pl-pds\">\"</span></span>, <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>in<span class=\"pl-pds\">\"</span></span>, <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>it<span class=\"pl-pds\">\"</span></span>, <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>jp<span class=\"pl-pds\">\"</span></span>, <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>kr<span class=\"pl-pds\">\"</span></span>, <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>se<span class=\"pl-pds\">\"</span></span>, <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>sg<span class=\"pl-pds\">\"</span></span>, <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>uk<span class=\"pl-pds\">\"</span></span>, <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>us<span class=\"pl-pds\">\"</span></span>, <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>za<span class=\"pl-pds\">\"</span></span>]\n    }\n]\n</code></pre>","date_published":"Sat, 23 Jan 2021 19:14:01 GMT","date_modified":"Mon, 05 Sep 2022 11:26:30 GMT"},{"id":"https://mmap.page/uses/android/","url":"https://mmap.page/uses/android/","title":"Android Setup Guide","content_html":"<h1>Android Setup Guide</h1>\n<h2>No Google Account</h2>\n<p>I do not sign in to a Google Account on the phone, because I dislike the idea of link a device to an online account.</p>\n<p>Without a Google Account, I cannot install applications via Google Play Store.\nThus, I use <a href=\"https://f-droid.org/\">F-Droid</a> (free and open source) and <a href=\"https://apkpure.com/\">APKPure</a> (apk files identical to those in the Google Play Store) to install applications.</p>\n<h2>Applications</h2>\n<ul>\n<li>Application market: F-Droid</li>\n<li>Browser: <a href=\"https://duckduckgo.com/app-mobile\">DuckDuckGo Privacy Browser</a> and <a href=\"https://vivaldi.com/android/\">Vivaldi</a> (with user activity tracking disabled by default)</li>\n</ul>\n<p>I also use some preinstalled applications, for example, calculator and Google Photos (with backup &#x26; sync turned off since I do not sign in to a Google Account).</p>","date_published":"Thu, 15 Oct 2020 14:54:49 GMT","date_modified":"Tue, 15 Jul 2025 08:25:46 GMT"},{"id":"https://mmap.page/dive-into/i3/","url":"https://mmap.page/dive-into/i3/","title":"i3 Quick Start","content_html":"<h1>i3 Quick Start</h1>\n<h2>Keybindings</h2>\n<p>When starting i3 without a config file, i3-config-wizard will let you choose Alt or Win as the Modifier, and generate a configure file.\nHowever, it will generate keybindings based on the key <strong>positions</strong> of QWERTY layout.\nSince I am using dvorak, so I copied <code>/etc/i3/config to ~/.config/i3/config</code> and replaced <code>Mod1</code> (<code>Alt</code>) with <code>Mod4</code> (<code>Win</code>) instead.</p>\n<table>\n<thead>\n<tr>\n<th>$mod+key</th>\n<th>function</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Enter</td>\n<td>terminal</td>\n</tr>\n<tr>\n<td>d</td>\n<td>dmenu</td>\n</tr>\n<tr>\n<td>Arrow Keys</td>\n<td>move focus</td>\n</tr>\n<tr>\n<td>Shift+Arrow Keys</td>\n<td>move window</td>\n</tr>\n<tr>\n<td>0-9</td>\n<td>switch workspace 10,1,...,9</td>\n</tr>\n<tr>\n<td>Shift+0-9</td>\n<td>switch workspace 10,1,...,9</td>\n</tr>\n<tr>\n<td>a</td>\n<td>navigate one container up the tree</td>\n</tr>\n<tr>\n<td>h/v</td>\n<td>split container splith/v</td>\n</tr>\n<tr>\n<td>e</td>\n<td>toggle splith/v</td>\n</tr>\n<tr>\n<td>f</td>\n<td>toggle fullscreen</td>\n</tr>\n<tr>\n<td>s/w</td>\n<td>stacking/tabbed</td>\n</tr>\n<tr>\n<td>Shift+Space</td>\n<td>toggle floating</td>\n</tr>\n<tr>\n<td>Shift+q</td>\n<td>close window</td>\n</tr>\n<tr>\n<td>Shift+r</td>\n<td>restart i3</td>\n</tr>\n<tr>\n<td>Shift+e</td>\n<td>exit i3</td>\n</tr>\n<tr>\n<td>Secondary mouse button</td>\n<td>adjust window size</td>\n</tr>\n<tr>\n<td>r</td>\n<td>enter resize mode</td>\n</tr>\n</tbody>\n</table>\n<p>Notes:</p>\n<ol>\n<li>By default, i3 uses <code>dmenu_run</code>, displaying all commands in <code>$PATH</code>. To only display applications shipping a <code>.desktop</code> file, replace <code>dmenu_run</code> with <code>i3-dmenu-desktop</code> instead.</li>\n<li>Multiple screens share workspaces. Workspace will be bound to the focused screen on its creation. Switching to a workspace will focus its screen.</li>\n<li>In resize mode, press arrow keys (or <code>jkl;</code>) to resize focused window: Left/Right: shirk/grow width; Up/Down: shrink/grow height; Esc: escape resize mode.</li>\n</ol>\n<h2>Configurations</h2>\n<p>Edit <code>~/.config/i3/config</code>:</p>\n<pre><code># No title bar, window borders\ndefault_border none\n# For old versions\n# new_window none\n# When already on workspace N, $mod+N will switch to the previous focused workspace\nworkspace_auto_back_and_forth yes\n# Hide i3bar\nbar {\n    mode hide\n    status_command i3status\n}\n# Lock screen\n# keybinding inspired by macOS\nbindsym Mod4+Ctrl+q exec --no-startup-id \"i3lock -i $HOME/Pictures/wallpaper/F14-final-wallpaper-updated.png\"\n# i3lock-img is a shell script of the above i3lock command line\nexec_always --no-startup-id \"xautolock -time 1 -locker i3lock-img\"\n</code></pre>\n<h2>Layouts</h2>\n<p>A container contains windows or containers.</p>\n<p>A container has one of the following layouts:</p>\n<table>\n<thead>\n<tr>\n<th>switch keys</th>\n<th>layout</th>\n<th>move focus</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>$mod+e</code></td>\n<td>tiling (it toggles splitv/splith)</td>\n<td><code>$mod+up/down/left/right</code> (depends on orientation)</td>\n</tr>\n<tr>\n<td><code>$mod+s</code></td>\n<td>stacking</td>\n<td><code>$mod+up/down</code></td>\n</tr>\n<tr>\n<td><code>$mod+w</code></td>\n<td>tabbed</td>\n<td><code>$mod+left/right</code></td>\n</tr>\n</tbody>\n</table>\n<p>And <code>$mod+f</code> will toggle fullscreen mode of the current window.</p>\n<p>A new opened window will appear in the current container, next to the current window:</p>\n<ul>\n<li>tiling: right/below</li>\n<li>stacking: below</li>\n<li>tabbed: right</li>\n</ul>\n<p>A new container can be created explicitly by splitting the current container vertically (<code>$mod+v</code>) or horizontally (<code>$mod+h</code>).\nAnd moving windows may implicitly create containers.</p>\n<p>For example, suppose we have three windows in a splith container (window c is focused):</p>\n<pre><code>|a|b|c*|\n</code></pre>\n<p><code>$mod+Shift+Up</code> results in the following layout:</p>\n<pre><code>|  c*   |\n| a | b |\n</code></pre>\n<p>Here window a and b are in an implicitly created new container.\nThat is,</p>\n<pre><code>splith             splitv\n / | \\    --->      /   \\\na  b  c            c   splith\n                        /  \\\n                       a    b\n</code></pre>\n<p>Similarly, if we focus window a (<code>$mod+Down</code>), and move it up (<code>$mod+Shift+Up</code>):</p>\n<pre><code>| c  |\n| a* |\n| b  |\n</code></pre>\n<p>then move it left (<code>$mod+Shift+Left</code>), we will get the following layout:</p>\n<pre><code>|    | c |\n| a* |\n|    | b |\n</code></pre>\n<p>Let's review the whole process:</p>\n<pre><code>|a|b|c*|  --> |  c*   |  --> | c  | --> |    | c |\n              | a | b |      | a* |     | a* |   |\n                             | b  |     |    | b |\n\nsplith             splitv             splitv           splith\n / | \\    --->      /   \\       --->   / | \\   --->     /   \\\na  b  c            c   splith         a  b  c          a    splitv\n                        /  \\                                 /  \\\n                       a    b                               c    b\n</code></pre>\n<h2>KDE</h2>\n<p>You can use i3 with other desktop environments such as <a href=\"https://userbase.kde.org/Tutorials/Using_Other_Window_Managers_with_Plasma\">KDE</a>.</p>\n<p>If you use i3 in KDE, you may want to uncomment the <code>xautolock</code> line above to lock screen via KDE.\nAlso, vertical KDE panel is not supported under i3.</p>","date_published":"Sun, 12 Jul 2020 10:20:15 GMT","date_modified":"Mon, 05 Sep 2022 11:26:30 GMT"},{"id":"https://mmap.page/uses/","url":"https://mmap.page/uses/","title":"Uses","content_html":"<h1>Uses</h1>\n<h2>Colophon</h2>\n<p>A plain text file documents the colophon of this site.\nAs for the URL to this plain text, if you are interested in the colophon of this site,\nyou probably know it.\nIf not, you can figure it out via the source code of this site.</p>\n<h2>Computers</h2>\n<ul>\n<li>\n<p><code>MacBookPro15,4</code></p>\n<p>The last generation of Intel based MacBookPro.</p>\n<p>I use <a href=\"https://github.com/weakish/dotfiles/blob/master/ports.txt\" title=\"ports installed on my machine\">MacPorts</a> as the package manager for command line programs and <a href=\"https://github.com/weakish/dotfiles/blob/master/Brewfile\" title=\"Brewfile on my machine\">Homebrew</a> for GUI applications.\nPreviously I also use Homebrew for command line programs.\nThe migration to MacPorts was very smooth.</p>\n<p>My previous personal Apple computer was the last generation of PowerPC based iBook (<code>PowerBook 6,7</code>).</p>\n</li>\n<li>\n<p>iPhone 13 mini</p>\n<p>Nowadays, there are almost no choices left for compact smart-phones.\nI bought iPhone 13 mini (131.5 x 64.2 x 7.65 mm, 141 g, 2406 mAH) in 2022, before iPhone SE 3rd generation (138.4 x 67.3 x 7.3 mm, 144 g, 2018 mAH) is available in the Apple Store.\nI prefer <a href=\"https://mmap.page/uses/android.md\" title=\"My Android Setup\">Android</a> phones, but <a href=\"https://tech.balmuda.com/jp/phone/story/\">Balmuda Phone</a> (123 x 69 x 13.7 mm, 138 g, 2500 mAH) is discontinued and <a href=\"https://xperia.sony.jp/xperia/acem3/spec_docomo.html\">Sony Xperia Ace III</a> (140 x 69 x 8.9 mm, 162 g, 4500 mAH) are only available in Japan,\nwhile Samsung Galaxy S23 (146.3 x 70.9 x 7.6 mm, 168 g, 3900 mAh), Sony Xperia 10 V (155 x 68 x 8.3 mm, 159 g, 5000 mAh), and Asus Zenfone 10 (146.5 x 68.1 x 9.4 mm, 172 g, 4300 mAh) are slightly bigger.\nPreviously I used Sony Xperia XZ1 Compact (129 x 65 x 9.3 mm, 140 g, 2700 mAH), then iPhone SE 2rd generation (138.4 x 67.3 x 7.3 mm, 148 g, 1821 mAH).</p>\n</li>\n<li>\n<p>iPad 9th generation</p>\n<p>Among the iPads that Apple is still selling, the 9th generation iPad is the only one with a headphone jack,\nand the cheapest one can be used as a second display via sidecar with Mac.</p>\n</li>\n</ul>\n<h2>Editor</h2>\n<p>I mainly use VSCode since it is a popular choice for a lot of languages and frameworks.\nAlso, it has first class support for GitHub Copilot which I used a lot.\nCurrently I am on its Pro plan but GitHub does not bill me for it (<code>SKU: free_engaged_oss</code>).</p>\n<p>Some of my friends are using <a href=\"https://www.cursor.com/\">Cursor</a> but I have not tried it yet.\nI might try it and <a href=\"https://windsurf.com/editor\">Windsurf</a> in future.</p>\n<h2>Terminal</h2>\n<p>I use <a href=\"https://sw.kovidgoyal.net/kitty/\">kitty</a> because previously I had used Neovim for some time and kitty works well with Neovim (true color &#x26; undercurl).\nAlso, kitty is from Kovid Goyal, the author of <a href=\"https://github.com/kovidgoyal/calibre\">calibre</a>.</p>\n<h2>Browser</h2>\n<p>I use DuckDuckGo browser with the advertisements in DuckDuckGo search engine disabled,\notherwise it will <a href=\"https://duckduckgo.com/duckduckgo-help-pages/privacy/web-tracking-protections#duckduckgo-private-search-ads\">not block some Microsoft tracking scripts under certain conditions</a>.</p>\n<p>Occasionally I use Chromium for fancy features such as <a href=\"https://caniuse.com/webgpu\" title=\"Can I use page for WebGPU\">WebGPU</a>.</p>\n<p>To browse markdown files on my mobile phone, I use <a href=\"https://obsidian.md/\">Obsidian</a>.\nI cloned the corresponding repository to my iCloud drive,\nthen opened it in Obsidian iOS app as a vault.\nMy modifications on the iPhone will be synced via iCloud to my Mac,\nthen I will finish the changes, commit them, and push them to GitHub.</p>\n<h2>Email</h2>\n<p>I use Apple Mail on my Mac and iPhone.\nI've used Spark before but it <a href=\"https://sparkmailapp.com/help/general/email-storage-and-backups\" title=\"Help documentation of Spark\">does not provide offline access to emails</a>.</p>\n<h2>Window Manager</h2>\n<p>Back to the days when I was using Linux\n(before <a href=\"https://www.devuan.org/os/init-freedom\" title=\"Init Freedom\">systemd killed portability</a> and <a href=\"https://www.kicad.org/blog/2025/06/KiCad-and-Wayland-Support/\" title=\"KiCad and Wayland Support\">Wayland killed compatibility</a>),\nI fell in love with tiling window managers like awesomewm and i3.\nOn macOS, I use <a href=\"https://github.com/mogenson/PaperWM.spoon\" title=\"PaperWM.spoon GitHub repository\">PaperWM.spoon</a>, a tiled scrollable window manager.</p>\n<h2>Online Services</h2>\n<ul>\n<li>Transfer files: <a href=\"https://wetransfer.com/\">WeTransfer</a> and <a href=\"https://www.swisstransfer.com/\">SwissTransfer</a>. No account is needed for either the sender or the receiver. The former is more limited (share and receive up to 3GB per month, 10 transfers per month, expires in 3 days), while the latter is more generous (50GB file limit, expires in 30 days).</li>\n</ul>\n<ul>\n<li>Backup files: iCloud for my iPhone and iPad, Time machine and <a href=\"https://secure.backblaze.com/r/04svpb\" title=\"Backblaze referral link, use this link to get a free month Backblaze for you and me\">Backblaze</a> for my MacBook Pro, and <a href=\"https://mmap.page/uses/borg.md\" title=\"Borg Tutorial\">borg</a> for Linux.</li>\n</ul>\n<h2>Camera</h2>\n<ul>\n<li>\n<p>Olympus Pen D3</p>\n<p>Fully manual compact half-frame camera.\nI often load it with Fomapan Classical 100 or Eastman Double X.\nI prefer Orthochromatic films such as Rollei Ortho 25 Plus and Ilford Ortho Plus, but they are hard to buy.\nSometimes I also use color films produced by Kodak or Fujifilm.\nI use Ilford HP5 Plus pushed two or three stops for low light.</p>\n</li>\n</ul>\n<h2>Wear</h2>\n<p>I used to prefer <a href=\"https://www.thedeffest.com/\">vintage style running shoes</a>, those revised <a href=\"https://www.mizuno.jp/mizuno1906/journal/journal_collection/046/\">models</a> originated from <a href=\"https://www.onitsukatiger.com/gb/en-gb/onitsukatiger-inspiration/onitsukatiger-mexico-66/\">1960s</a> to <a href=\"https://mmap.page/uses/nb-420.jpg\" title=\"https://i.ebayimg.com/images/g/ApEAAOSwd7Fb-MP7/s-l1600.jpg\">1980s</a>, <a href=\"https://mmap.page/uses/nb-ads.jpg\" title=\"https://images.squarespace-cdn.com/content/v1/5ab94f5e3c3a536987d16ce5/1586282359719-W9JJP53TVVP0EAJVXOLJ/ke17ZwdGBToddI8pDm48kGNEFA4rC7c0McDIySn7RjkUqsxRUqqbr1mOJYKfIPR7LoDQ9mXPOjoJoqy81S2I8N_N4V1vUb5AoIIIbLZhVYxCRW4BPu10St3TBAUQYVKcPlG31PR0Q5DeNaNXE1QnS_LzyNcqI129vtg_t5azkwh6fx-4rvXr20Sq8_feGDMO/New+Balance+1982+vintage+sneaker+ad+%40+The+Deffest?format=1500w\">light and comfort</a>.\nHowever, I found out that their toe boxes are narrow.\nSo I bought a pair of Crocs Classical Clog instead, which has a large toe box.\nI also put on some charms to make my white Crocs prettier.\nI wore it a lot but did not bought a new pair after it was worn out, since:</p>\n<ul>\n<li>\n<p>I feel the material is too hard for my feet skin so I have to wear socks.</p>\n</li>\n<li>\n<p>The heel to toe drop is low but the sole still feels too thick for me.</p>\n</li>\n<li>\n<p>Some places do not allow wearing Clogs.</p>\n</li>\n</ul>\n<p>Currently my favorite pair is <a href=\"https://www.vibram.com/us/shop/fivefingers/kso-eco-mens/M95_MilitaryGreen.html\">Vibram FiveFingers KSO ECO Green</a>,\nwhich is extremely light (M43 4.9 oz) and minimalistic (3mm rubber outsole).\nWalking wearing it, I can feel the ground and my toes are not constrained.\nHowever, I feel it is not suitable to wear it running on hard surface so later I bought a pair of <a href=\"https://www.vibram.com/us/shop/fivefingers/men/v-run-mens/M31_2_IvoryYellow.html\">Vibram FiveFingers V-Run Ivory / Yellow</a>,\nwhich is also extremely light (M43 4.8 oz) but offers a bit more cushioning (2mm EVA insole, 4mm EVA midsole, 2.5 mm rubber outsole).\nBoth of them have fast lacing system, which I prefer since I hate tying shoelaces.</p>\n<p>I also have a pair of <a href=\"https://www.altrarunning.com/en-us/gym-training/mens-solstice-xt-3/AL0A85Q5.html?dwvar_AL0A85Q5_color=110\">Altra Solstice XT 3 White</a>, zero drop and wide toe box.\nIts 23mm stack feels too thick for my walk but is fine for gym.\nThe stack of Altra running shoes and hiking shoes are too thick for me so I do not consider them after trying them on at the store.</p>\n<p>I also have a pair of running sandals bought from a local shop where they assemble sandals themselves.\nZerodrop, hybrid outsole for both road and trail, red foam and rainbow straps.</p>\n<h2>Drink</h2>\n<p>Water, milk, and Juice.\nI seldom drink coffee or tea, and almost never drink alcohol.\nHowever, I do like drinking chocolate.</p>\n<p>This page is inspired by <a href=\"https://uses.tech/\">uses.tech</a>.</p>","date_published":"Fri, 10 Jul 2020 14:36:17 GMT","date_modified":"Thu, 24 Jul 2025 16:11:45 GMT"},{"id":"https://mmap.page/dive-into/pyinfra/","url":"https://mmap.page/dive-into/pyinfra/","title":"Dive into Pyinfra","content_html":"<h1>Dive into Pyinfra</h1>\n<p>Pyinfra features:</p>\n<ol>\n<li>Minimal dependencies for remote system (only shell).</li>\n<li>Write deploy files in Python.</li>\n</ol>\n<h2>Install</h2>\n<pre><code class=\"language-sh\">pip install pyinfra\n</code></pre>\n<h2>Ad-hoc</h2>\n<p>I can run ad-hoc commands directly without writing any file.</p>\n<pre><code class=\"language-sh\"><span class=\"pl-k\">;</span> pyinfra @local pip.packages pyinfra\n--<span class=\"pl-k\">></span> Loading config...\n--<span class=\"pl-k\">></span> Loading inventory...\n\n--<span class=\"pl-k\">></span> Connecting to hosts...\n    [@local] Connected\n\n--<span class=\"pl-k\">></span> Preparing operation...\n\n--<span class=\"pl-k\">></span> Proposed changes:\n    Groups: @local\n    [@local]   Operations: 1   Commands: 0\n\n--<span class=\"pl-k\">></span> Beginning operation run...\n--<span class=\"pl-k\">></span> Starting operation: Pip/Packages (<span class=\"pl-s\"><span class=\"pl-pds\">'</span>pyinfra<span class=\"pl-pds\">'</span></span>,)\n    [@local] No changes\n\n--<span class=\"pl-k\">></span> Results:\n    Groups: @local\n    [@local]   Successful: 1   Errors: 0   Commands: 0/0\n</code></pre>\n<h2>Deploy File</h2>\n<p>The best feature of pyinfra to me is writing deploy files in Python.</p>\n<pre><code class=\"language-py\"><span class=\"pl-c\"># deploy.py</span>\n\n<span class=\"pl-k\">from</span> pyinfra.modules <span class=\"pl-k\">import</span> pip\n\npip.packages([<span class=\"pl-s\"><span class=\"pl-pds\">'</span>pyinfra<span class=\"pl-pds\">'</span></span>])\n</code></pre>\n<p>Execute it:</p>\n<pre><code class=\"language-sh\"><span class=\"pl-k\">;</span> pyinfra deploy.py\n--<span class=\"pl-k\">></span> Loading config...\n--<span class=\"pl-k\">></span> Loading inventory...\n\n--<span class=\"pl-k\">></span> Connecting to hosts...\n    [@local] Connected\n\n--<span class=\"pl-k\">></span> Preparing operations...\n    Loading: deploy.py\n    [@local] Ready: deploy.py\n\n--<span class=\"pl-k\">></span> Proposed changes:\n    Groups: @local\n    [@local]   Operations: 1   Commands: 0\n\n--<span class=\"pl-k\">></span> Beginning operation run...\n--<span class=\"pl-k\">></span> Starting operation: Pip/Packages (<span class=\"pl-s\"><span class=\"pl-pds\">'</span>pyinfra<span class=\"pl-pds\">'</span></span>,)\n    [@local] No changes\n\n--<span class=\"pl-k\">></span> Results:\n    Groups: @local\n    [@local]   Successful: 1   Errors: 0   Commands: 0/0\n</code></pre>\n<h2>Operations</h2>\n<h3>Global Arguments</h3>\n<ul>\n<li><code>sudo</code>: execute with sudo</li>\n<li><code>env</code>: dictionary of environment variables to set</li>\n<li><code>ignore_errors</code></li>\n<li><code>success_exit_codes</code>: list of exit codes to consider a success</li>\n<li><code>timeout</code>: timeout for <em>each</em> command executed during the operation</li>\n<li><code>stdin</code>: string or buffer to send to the stdin of any commands</li>\n<li><code>on_success</code> and <code>on_error</code>: callback functions</li>\n</ul>\n<p>Refer to <a href=\"https://github.com/Fizzadar/pyinfra/blob/master/pyinfra/api/operation_kwargs.py\">pyinfra/api/operation_kwargs.py</a> for a complete list.</p>\n<h3>Loops</h3>\n<p>Actions are executed in orders, blockingly.\nHowever, operations in a loop are executed, nonblockingly.</p>\n<p>The following will not work, since multiple <code>apt install</code> commands cannot be run at the same time.</p>\n<pre><code class=\"language-python\"><span class=\"pl-k\">for</span> p <span class=\"pl-k\">in</span> [<span class=\"pl-s\"><span class=\"pl-pds\">'</span>git<span class=\"pl-pds\">'</span></span>, <span class=\"pl-s\"><span class=\"pl-pds\">'</span>tmux<span class=\"pl-pds\">'</span></span>, <span class=\"pl-s\"><span class=\"pl-pds\">'</span>fish<span class=\"pl-pds\">'</span></span>]:\n    apt.packages([p])\n</code></pre>\n<p>Pyinfra provides <code>state.preserve_loop_order</code> for serializing execution:</p>\n<pre><code class=\"language-python\"><span class=\"pl-k\">from</span> pyinfra.api <span class=\"pl-k\">import</span> state\n\n<span class=\"pl-k\">with</span> state.preserve_loop_order([<span class=\"pl-s\"><span class=\"pl-pds\">'</span>git<span class=\"pl-pds\">'</span></span>, <span class=\"pl-s\"><span class=\"pl-pds\">'</span>tmux<span class=\"pl-pds\">'</span></span>, <span class=\"pl-s\"><span class=\"pl-pds\">'</span>fish<span class=\"pl-pds\">'</span></span>]) <span class=\"pl-k\">as</span> loop_items:\n    <span class=\"pl-k\">for</span> p <span class=\"pl-k\">in</span> loop_items():\n        apt.packages([p])\n</code></pre>\n<p>Note the above example is for demonstration only, the proper way should be:</p>\n<pre><code class=\"language-python\">apt.packages([<span class=\"pl-s\"><span class=\"pl-pds\">'</span>git<span class=\"pl-pds\">'</span></span>, <span class=\"pl-s\"><span class=\"pl-pds\">'</span>tmux<span class=\"pl-pds\">'</span></span>, <span class=\"pl-s\"><span class=\"pl-pds\">'</span>fish<span class=\"pl-pds\">'</span></span>])\n</code></pre>\n<h3>Writing Operations</h3>\n<p>Example in Python 3.6:</p>\n<pre><code class=\"language-python\"><span class=\"pl-c\"># pkcon.py</span>\n<span class=\"pl-k\">from</span> typing <span class=\"pl-k\">import</span> Generator, List, Dict, Union\n<span class=\"pl-k\">from</span> pyinfra.api <span class=\"pl-k\">import</span> operation\n<span class=\"pl-k\">from</span> pyinfra.api.state <span class=\"pl-k\">import</span> State\n<span class=\"pl-k\">from</span> pyinfra.api.host <span class=\"pl-k\">import</span> Host\n\n<span class=\"pl-en\">@operation</span>\n<span class=\"pl-k\">def</span> <span class=\"pl-en\">update</span>(<span class=\"pl-smi\">state</span>: State, <span class=\"pl-smi\">host</span>: Host) -> Generator[Dict[<span class=\"pl-c1\">str</span>, Union[<span class=\"pl-c1\">str</span>, List[<span class=\"pl-c1\">int</span>]]], <span class=\"pl-c1\">None</span>, <span class=\"pl-c1\">None</span>]:\n    <span class=\"pl-s\"><span class=\"pl-pds\">'''</span>Upgrade system via PackageKit console client.<span class=\"pl-pds\">'''</span></span>\n    command: Dict[<span class=\"pl-c1\">str</span>, Union[<span class=\"pl-c1\">str</span>, List[<span class=\"pl-c1\">int</span>]]] <span class=\"pl-k\">=</span> {\n        <span class=\"pl-s\"><span class=\"pl-pds\">'</span>command<span class=\"pl-pds\">'</span></span>: <span class=\"pl-s\"><span class=\"pl-pds\">'</span>pkcon update --plain --noninteractive<span class=\"pl-pds\">'</span></span>,\n        <span class=\"pl-s\"><span class=\"pl-pds\">'</span>success_exit_codes<span class=\"pl-pds\">'</span></span>: [<span class=\"pl-c1\">0</span>, <span class=\"pl-c1\">5</span>],  <span class=\"pl-c\">## 5: no updates to install</span>\n    }\n    <span class=\"pl-c\"># operation yields shell commands, so the target machine does not need Python.</span>\n    <span class=\"pl-k\">yield</span> command\n</code></pre>\n<p>Note, the above code requires the following stub:</p>\n<pre><code class=\"language-python\"><span class=\"pl-c\"># typings/pyinfra/api/operation.pyi</span>\n<span class=\"pl-c\"># import statements omitted for brevity</span>\n<span class=\"pl-k\">def</span> <span class=\"pl-en\">operation</span>(<span class=\"pl-smi\">func</span>: Callable[[State, Host], Union[<span class=\"pl-c1\">str</span>, Dict[<span class=\"pl-c1\">str</span>, Union[<span class=\"pl-c1\">str</span>, List[<span class=\"pl-c1\">int</span>]]], Generator[<span class=\"pl-c1\">str</span>, <span class=\"pl-c1\">None</span>, <span class=\"pl-c1\">None</span>], Generator[Dict[<span class=\"pl-c1\">str</span>, Any], <span class=\"pl-c1\">None</span>, <span class=\"pl-c1\">None</span>]]],\n    <span class=\"pl-smi\">pipeline_facts</span>: Optional[Any] <span class=\"pl-k\">=</span> <span class=\"pl-c1\">...</span>) -> Callable[<span class=\"pl-c1\">...</span>, OperationMeta]: <span class=\"pl-c1\">...</span>\n</code></pre>\n<p>Use it as below:</p>\n<pre><code class=\"language-python\"><span class=\"pl-c\"># deploy.py</span>\n<span class=\"pl-k\">import</span> pkcon\npkcon.update()\n</code></pre>\n<p>Operations can be packaged in deploys:</p>\n<pre><code class=\"language-python\"><span class=\"pl-c\"># unix.py</span>\n<span class=\"pl-k\">from</span> pyinfra.api <span class=\"pl-k\">import</span> deploy\n<span class=\"pl-k\">from</span> pyinfra.api.state <span class=\"pl-k\">import</span> State\n<span class=\"pl-k\">from</span> pyinfra.api.host <span class=\"pl-k\">import</span> Host\n<span class=\"pl-k\">from</span> pyinfra.modules <span class=\"pl-k\">import</span> python\n<span class=\"pl-k\">import</span> pkcon\n\n<span class=\"pl-en\">@deploy</span>\n<span class=\"pl-k\">def</span> <span class=\"pl-en\">update</span>(<span class=\"pl-smi\">state</span>: State, <span class=\"pl-smi\">host</span>: Host) -> <span class=\"pl-c1\">None</span>:\n    <span class=\"pl-k\">if</span> host.fact.os <span class=\"pl-k\">==</span> <span class=\"pl-s\"><span class=\"pl-pds\">'</span>Linux<span class=\"pl-pds\">'</span></span>:\n        <span class=\"pl-k\">if</span> host.fact.linux_distribution[<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>release_meta<span class=\"pl-pds\">\"</span></span>][<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>ID<span class=\"pl-pds\">\"</span></span>] <span class=\"pl-k\">==</span> <span class=\"pl-s\"><span class=\"pl-pds\">'</span>neon<span class=\"pl-pds\">'</span></span>:\n            <span class=\"pl-c\"># nested operations cannot omit state and host parameters</span>\n            pkcon.update(state, host)\n        <span class=\"pl-k\">else</span>:\n            python.raise_exception(state, host, <span class=\"pl-c1\">NotImplementedError</span>)\n    <span class=\"pl-k\">else</span>:\n        python.raise_exception(state, host, <span class=\"pl-c1\">NotImplementedError</span>)\n</code></pre>\n<p>Again, the above code requires the following stub:</p>\n<pre><code class=\"language-python\"><span class=\"pl-c\"># typings/pyinfra/api/deploy.pyi</span>\n<span class=\"pl-c\"># import statements omitted for brevity</span>\n<span class=\"pl-k\">def</span> <span class=\"pl-en\">deploy</span>(<span class=\"pl-smi\">func_or_name</span>: Union[Callable[<span class=\"pl-c1\">...</span>, <span class=\"pl-c1\">None</span>],<span class=\"pl-c1\">str</span>], <span class=\"pl-smi\">data_defaults</span>: Optional[Any] <span class=\"pl-k\">=</span> <span class=\"pl-c1\">...</span>) -> Callable[<span class=\"pl-c1\">...</span>, <span class=\"pl-c1\">None</span>]: <span class=\"pl-c1\">...</span>\n</code></pre>\n<p>Usage:</p>\n<pre><code class=\"language-python\"><span class=\"pl-c\"># deploy.py</span>\n<span class=\"pl-k\">import</span> unix\nunix.update()\n</code></pre>\n<h2>Inventory</h2>\n<p>Currently, I have only played with Pyinfra on localhost.\nBut pyinfra can also manage remote machines.</p>\n<pre><code class=\"language-sh\">pyinfra example.com fact os\n</code></pre>\n<p>To manage multiple servers, list them in <code>inventory.py</code>:</p>\n<pre><code class=\"language-sh\"><span class=\"pl-k\">;</span> cat inventory.py\nvm = [<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>a.example.com<span class=\"pl-pds\">\"</span></span>, <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>b.example.com<span class=\"pl-pds\">\"</span></span>, <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>c.example.com<span class=\"pl-pds\">\"</span></span>]\n<span class=\"pl-k\">;</span> pyinfra inventory.py deploy.py\n</code></pre>\n<h2>Similar Projects</h2>\n<ul>\n<li><a href=\"https://github.com/sprinkle-tool/sprinkle\">Sprinkle</a>, like Pyinfra but deploy files are written in Ruby.</li>\n<li><a href=\"https://www.cdi.st/\">cdist</a>, also written in Python, but deploy files are written in shell.</li>\n</ul>","date_published":"Sun, 14 Jun 2020 14:09:59 GMT","date_modified":"Mon, 05 Sep 2022 11:26:30 GMT"},{"id":"https://mmap.page/dive-into/wireguard/","url":"https://mmap.page/dive-into/wireguard/","title":"WireGuard Quick Start","content_html":"<h1>WireGuard Quick Start</h1>\n<blockquote>\n<p>WireGuard is an extremely simple yet fast and modern VPN that utilizes state-of-the-art cryptography.</p>\n<p>-- <a href=\"https://www.wireguard.com/\">www.wireguard.com</a></p>\n</blockquote>\n<h2>Client Side</h2>\n<p>Install the <a href=\"https://www.wireguard.com/install/\">WireGuard package / application</a> for your operating system.</p>\n<p>Create key pairs:</p>\n<pre><code>wg genkey | tee privatekey | wg pubkey > publickey\n</code></pre>\n<p>Create configuration file:</p>\n<pre><code>[Interface]\nAddress = 10.200.200.2/32, fd86:ea04:1111::2/128\nPrivateKey = &#x3C;content of privatekey, base64 string>\nDNS = 1.1.1.1\n    \n[Peer]\nPublicKey = &#x3C;content of server publickey, base64 string>\nEndpoint = &#x3C;public ip of server:51820>\nAllowedIPs = 0.0.0.0/0, ::/0\nPersistentKeepalive = 25\n</code></pre>\n<p><code>Interface</code> is for this machine (client info here), and <code>Peer</code> is for other machine (server info here).</p>\n<p><code>10.200.200.2</code> and <code>fd86:ea04:1111::2</code> are private IP addresses.\nI can specify any private IP addresses here,\nas long as the IP addresses are matched with private subnet assigned to the server.</p>\n<p><code>/32</code> is a <a href=\"https://doc.m0n0.ch/quickstartpc/intro-CIDR.html\">subnet mask</a>, which means one single IPv4.\nAs a client, this machine only need one IPv4 within the virtual network.\nSimilarly, <code>/128</code> is a CIDR indicating one single IPv6.</p>\n<p>The <code>DNS</code> line is optional, which should be a DNS resolver which provides optimal resolutions for the server.\nHere I use <a href=\"https://developers.cloudflare.com/1.1.1.1/\">1.1.1.1</a> from cloudflare.</p>\n<p><code>Endpoint</code> specifies how to access the server.\nThe IP can be IPv4 or IPv6, but typically IPv4, because the client machine may be under an IPv4-only network.\nThe port (<code>51820</code> here) must match the <code>ListenPort</code> specified in the interface of the server.</p>\n<p><code>0.0.0.0/0, ::/0</code> means sending all traffic to the server.</p>\n<p>If the client is behind NAT, the router will need to translate its internal IP and port before forwarding the packets to the Internet.\nAnd the router will keep tracks of the connections in a Network Address Translation table.\nBased on this NAT table, it routinely closes off ports that appear dormant.\nIf the router erroneously closes the WireGuard port,\nthe WireGuard service, unaware of this change, will continue to send packets to the closed port.\nThis leads to network problems.\n<code>PersistentKeepalive = 25</code> means sending a keeplive packet to the server every 25 seconds to prevent the NAT expiration (typically in 60 seconds for most routers).</p>\n<p>To enable the tunnel, run:</p>\n<pre><code class=\"language-sh\">sudo wg-quick up /path/to/wg0.conf\n</code></pre>\n<p>To turn off the tunnel, run:</p>\n<pre><code class=\"language-sh\">sudo wg-quick down /path/to/wg0.conf\n</code></pre>\n<p>If you use a GUI WireGuard application, you can import the configuration file instead.</p>\n<p>If you use the WireGuard mobile application, the fast way to import the configuration is scan a QR code:</p>\n<pre><code class=\"language-sh\">cat /path/to/wg0.conf <span class=\"pl-k\">|</span> qrencode -t ansiutf8\n</code></pre>\n<p>Multiple servers can be specified in multiple <code>.conf</code> files.</p>\n<h2>Server Side</h2>\n<p>Install the WireGuard package on server,\nthen generate key pairs as mentioned above.</p>\n<p>Create <code>/etc/wireguard/wg0.conf</code>:</p>\n<pre><code>[Interface]\nAddress    = 10.200.200.1/24, fd86:ea04:1111::1/64\nPrivateKey = &#x3C;content of privatekey, base64 string> \nListenPort = 51820\nPostUp   = iptables -t nat -A POSTROUTING -o ens3 -j MASQUERADE; ip6tables -t nat -A POSTROUTING -o ens3 -j MASQUERADE\nPostDown = iptables -t nat -D POSTROUTING -o ens3 -j MASQUERADE; ip6tables -t nat -A POSTROUTING -o ens3 -j MASQUERADE\n\n[Peer]\nPublicKey  = &#x3C;content of client publickey, base64 string> \nAllowedIPs = 10.200.200.2/32, fd86:ea04:1111::2/128\n</code></pre>\n<p><code>/24</code> is a subnet mask for 256 IPv4 addresses,\nsince an IPv4 address uses 32 bits, masking 24 bits leaves 8 bits (<code>2 ** 8 = 256</code>).\nIn the above example, <code>10.200.200.0</code> is preserved for compatibility reasons (IPv4 addresses ending with <code>.0</code> are historically considered representing the network itself and used for broadcasting), and <code>10.200.200.1</code> is used by the server.\nThus this virtual network allows up to 254 clients.</p>\n<p>The subnet mask for IPv6 could be <code>/120</code> (<code>2 ** (128-120) = 256</code>).\nHowever, IPv6 recommends using <code>/64</code> as the smallest subnet, and a lot of software assumes an IPv6 subnet will not be smaller than <code>/64</code>.</p>\n<p><code>PostUp</code> forwards Internet requests from clients, and <code>ens3</code> is the network interface to access Internet on the server.\n<code>PostDown</code> deletes the iptable rules when the VPN is off.\nActually these are WireGuard hooks, you can fill any shell command here.</p>\n<p>A quick explanation of iptables rules:</p>\n<ul>\n<li><code>iptables</code>: the command line utility to configure the builtin firewall of Linux kernel.</li>\n<li><code>-t</code>: stands for \"table\".</li>\n<li><code>nat</code>: this table is consulted when a packet that creates a new connection is encountered.</li>\n<li><code>-A</code>: append to the rule chain.</li>\n<li><code>POSTROUTING</code>: alter packets as they are about to go out.</li>\n<li><code>-o ens3</code>: alter packets that leave on <code>ens3</code> network interface (<code>-o</code> stands for \"output\").</li>\n<li><code>-j</code>: stands for \"jump\", i.e., what to do if the packet matches it.</li>\n<li><code>MASQUERADE</code>: MASQUERADE replaces the private IP of the packet with the public IP of the server, allowing the packet to go out to the Internet.</li>\n<li><code>ip6tables</code>: iptables for IPv6.</li>\n</ul>\n<p>The <code>PublicKey</code> and <code>AllowedIPs</code> in the <code>Peer</code> section should match the configuration of the client.</p>\n<p>You can add more clients (multiple <code>Peer</code> sections).</p>\n<p>Enable forwarding IPv4 and IPv6 packets on the server:</p>\n<pre><code class=\"language-sh\"><span class=\"pl-c1\">echo</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>net.ipv4.ip_forward=1<span class=\"pl-pds\">\"</span></span> <span class=\"pl-k\">|</span> sudo tee -a /etc/sysctl.conf\n<span class=\"pl-c1\">echo</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>net.ipv6.conf.all.forwarding = 1<span class=\"pl-pds\">\"</span></span> <span class=\"pl-k\">|</span> sudo tee -a /etc/sysctl.conf\nsudo sysctl -p\n</code></pre>\n<p><code>sysctl</code> modifies kernel parameters at runtime, and <code>-p</code> loads <code>/etc/sysctl.conf</code>.\nThis is only required on the server, since client allow Internet through server.</p>\n<p>Start WireGuard:</p>\n<pre><code class=\"language-sh\">sudo wg-quick up wg0\n<span class=\"pl-c\"># equivalent to `sudo wg-quick down /etc/wireguard/wg0.conf`</span>\n</code></pre>\n<p>Stop WireGuard:</p>\n<pre><code class=\"language-sh\">sudo wg-quick down wg0\n</code></pre>\n<p>You may also add WireGuard service to your init system, e.g. systemd:</p>\n<pre><code class=\"language-sh\">sudo systemctl <span class=\"pl-c1\">enable</span> wg-quick@wg0.service\n</code></pre>","date_published":"Sat, 22 Feb 2020 13:14:15 GMT","date_modified":"Tue, 06 Sep 2022 05:05:55 GMT"},{"id":"https://mmap.page/dive-into/rust/","url":"https://mmap.page/dive-into/rust/","title":"Dive into Rust","content_html":"<h1>Dive into Rust</h1>\n<h2>Variable Shadowing</h2>\n<pre><code class=\"language-rust\"><span class=\"pl-k\">let</span> <span class=\"pl-k\">mut</span> <span class=\"pl-smi\">guess</span> <span class=\"pl-k\">=</span> <span class=\"pl-en\">String</span><span class=\"pl-k\">::</span><span class=\"pl-en\">new</span>();\n\n<span class=\"pl-en\">io</span><span class=\"pl-k\">::</span><span class=\"pl-en\">stdin</span>()<span class=\"pl-k\">.</span><span class=\"pl-en\">read_line</span>(<span class=\"pl-k\">&#x26;mut</span> <span class=\"pl-smi\">guess</span>)\n    <span class=\"pl-k\">.</span><span class=\"pl-en\">expect</span>(<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>Failed to read line<span class=\"pl-pds\">\"</span></span>);\n\n<span class=\"pl-k\">let</span> <span class=\"pl-smi\">guess</span><span class=\"pl-k\">:</span> <span class=\"pl-en\">u32</span> <span class=\"pl-k\">=</span> <span class=\"pl-smi\">guess</span><span class=\"pl-k\">.</span><span class=\"pl-en\">trim</span>()<span class=\"pl-k\">.</span><span class=\"pl-en\">parse</span>()\n    <span class=\"pl-k\">.</span><span class=\"pl-en\">expect</span>(<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>Please type a number!<span class=\"pl-pds\">\"</span></span>);\n\n<span class=\"pl-k\">const</span> <span class=\"pl-c1\">CONSTANT</span><span class=\"pl-k\">:</span> <span class=\"pl-k\">&#x26;</span><span class=\"pl-en\">str</span> <span class=\"pl-k\">=</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>a constant expression, not the result of a function call computed at runtime<span class=\"pl-pds\">\"</span></span>;\n<span class=\"pl-k\">let</span> <span class=\"pl-smi\">immutable_variable</span><span class=\"pl-k\">:</span> <span class=\"pl-k\">&#x26;</span><span class=\"pl-en\">str</span> <span class=\"pl-k\">=</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>variables are immutable by default<span class=\"pl-pds\">\"</span></span>;\n<span class=\"pl-k\">let</span> <span class=\"pl-k\">mut</span> <span class=\"pl-smi\">mutable_variable</span><span class=\"pl-k\">:</span> <span class=\"pl-en\">u32</span> <span class=\"pl-k\">=</span> <span class=\"pl-c1\">0</span>;\n<span class=\"pl-k\">let</span> <span class=\"pl-smi\">immutable_variable</span><span class=\"pl-k\">:</span> <span class=\"pl-k\">&#x26;</span><span class=\"pl-en\">str</span> <span class=\"pl-k\">=</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>shadowing the previous immutable_variable, which is bad<span class=\"pl-pds\">\"</span></span>;\n<span class=\"pl-k\">let</span> <span class=\"pl-smi\">immutable_variable</span><span class=\"pl-k\">:</span> <span class=\"pl-en\">u32</span> <span class=\"pl-k\">=</span> <span class=\"pl-c1\">1</span>;\n</code></pre>\n<h2>Data Types</h2>\n<h3>Scalar Types</h3>\n<ul>\n<li>Integer: <code>i8</code>, <code>i16</code>, <code>i32</code>, <code>i64</code>, <code>i128</code>, <code>isize</code> and their unsigned counterpart <code>u8</code>, ..., <code>usize</code>. <code>isize</code> is <code>i32</code> on 32 bit systems and <code>i64</code> on 64 bit systems. Integer types default to <code>i32</code>. Compiling in debug mode will check for integer overflows. Relying on integer overflow’s wrapping behavior is considered an error, use the <code>Wrapping</code> type instead.</li>\n<li>Floats: <code>f32</code> and <code>f64</code>.</li>\n<li>Boolean: <code>bool</code> (values: <code>true</code> and <code>false</code>).</li>\n<li>Character: <code>char</code> (Unicode Scalar Value).</li>\n</ul>\n<h3>Compound Types</h3>\n<ul>\n<li>Tuple: tuple index must be written as a decimal literal, e.g. <code>(0, 1, 2).1</code>.</li>\n<li>Array: can be considered as a tuple whose elements all have the same type. Index out of bounds is a <em>runtime</em> error though.</li>\n</ul>\n<h2>Control Flow</h2>\n<p>Condition <em>must</em> be a <code>bool</code>.\nNice!</p>\n<h2>Enum</h2>\n<p>Rust's enum is actually a tagged union.</p>\n<h2>Generics</h2>\n<p>Rust monomorphizes code that is using generics at compile time.</p>\n<h2>Traits</h2>\n<p>Rust's traits is similar to interface in other languages.</p>\n<h2>Memory Management</h2>\n<p>Rust does not use GC or RC.\nFor values on the heap, it only allow one variable \"own\" a value at a time.\nAssignment, passing a value to function and returning a value move the \"ownership\".\nAlso, Rust allows multiple immutable pointers (<code>&#x26;</code>) but only one mutable pointer (<code>&#x26;mut</code>),\nand restricts mixing immutable and mutable pointers to the same target.\nThe basic idea is to keep the number of reference to a value to one,\nto make memory management easier for the compiler.</p>\n<pre><code class=\"language-rust\"><span class=\"pl-k\">let</span> <span class=\"pl-smi\">s1</span> <span class=\"pl-k\">=</span> <span class=\"pl-en\">String</span><span class=\"pl-k\">::</span><span class=\"pl-en\">from</span>(<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>A long long string<span class=\"pl-pds\">\"</span></span>);\n<span class=\"pl-k\">let</span> <span class=\"pl-smi\">s2</span> <span class=\"pl-k\">=</span> <span class=\"pl-smi\">s1</span> <span class=\"pl-k\">+</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>.<span class=\"pl-pds\">\"</span></span>;\n</code></pre>\n<p>Conceptually s2 can be considered as a newly constructed immutable variable,\nbut since the ownership moves from s1 to s2, and s1 becomes invalid afterwards,\nthe compiler just need to appends <code>\".\"</code> to the end of the value, which is efficient.</p>\n<p>Smart pointers can be used for reference counting.\nSmart pointers are structs satisfying <code>Deref</code> and <code>Drop</code> traits.</p>\n<pre><code class=\"language-rust\"><span class=\"pl-k\">enum</span> <span class=\"pl-en\">List</span> {\n    <span class=\"pl-en\">Cons</span>(<span class=\"pl-en\">i32</span>, <span class=\"pl-en\">Box</span>&#x3C;<span class=\"pl-en\">List</span>>),\n    <span class=\"pl-en\">Nil</span>,\n}\n</code></pre>\n<p>In the above example, <code>Box&#x3C;List></code> is a smart pointer.\nWe use <code>Box&#x3C;List></code> to store the <code>Box&#x3C;List></code> data on the heap,\notherwise <code>Cons(i32, List)</code> will result in infinite size on the stack,\nwhich causes Rust failed to construct the <code>List</code> enum.</p>\n<p>To allow <code>cons</code> more than one lists from a same base list:</p>\n<pre><code class=\"language-rust\"><span class=\"pl-k\">enum</span> <span class=\"pl-en\">List</span> {\n    <span class=\"pl-en\">Cons</span>(<span class=\"pl-en\">i32</span>, <span class=\"pl-en\">Rc</span>&#x3C;<span class=\"pl-en\">List</span>>),\n    <span class=\"pl-en\">Nil</span>,\n}\n</code></pre>\n<p><code>Rc</code> is another smart pointer for reference counting.\nIt increases the reference counter on <code>RC::clone(&#x26;l)</code>,\nand reduce the reference counter automatically when the related variable goes out of scope.\nWhen there are zero references, the value will be cleaned up.</p>\n<p>Be aware that <code>Rc</code> only works in single-thread context.\nIn multiple-threads context, use <code>Arc</code> instead.</p>\n<p>In Rust, functions and struts working with references need lifetime annotation.\nHowever, Rust can infer function lifetime in simplest cases:</p>\n<ul>\n<li>If there is only one reference input parameter, then its lifetime will be the lifetime of output values.</li>\n<li>If there are multiple reference input parameters, but one of them is <code>&#x26;self</code> or <code>&#x26;mut self</code>, then its lifetime will be the lifetime of output values.</li>\n</ul>\n<p>String literals have a <code>'static</code> lifetime, which lives for the entire duration of the program.</p>\n<pre><code class=\"language-rust\"><span class=\"pl-k\">let</span> <span class=\"pl-smi\">b</span>;\n{\n    <span class=\"pl-k\">let</span> <span class=\"pl-smi\">a</span> <span class=\"pl-k\">=</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>hi<span class=\"pl-pds\">\"</span></span>;\n    <span class=\"pl-smi\">b</span> <span class=\"pl-k\">=</span> <span class=\"pl-smi\">a</span>;\n}\n<span class=\"pl-en\">println!</span>(<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>{}<span class=\"pl-pds\">\"</span></span>, <span class=\"pl-smi\">b</span>); <span class=\"pl-c\">// prints \"hi\"</span>\n</code></pre>\n<p>Lifetime annotation tells Rust compiler the lifetime of variables,\nbut it cannot alter the lifetime.</p>\n<h2>Testing</h2>\n<p>While Go use special function name <code>TestXxx</code>, Rust uses <code>#[test]</code> attribute annotation.</p>\n<p>Unit tests are written in <code>mod tests</code>, and integration tests are put in the <code>test</code> directory.</p>\n<h2>Documentation Comments</h2>\n<p>Three leading slashes <code>///</code> with Markdown.</p>\n<p>Similar to Python, Rust also supports doctest:</p>\n<pre><code class=\"language-rust\"><span class=\"pl-c\">/// # Example</span>\n<span class=\"pl-c\">///</span>\n<span class=\"pl-c\">/// ```</span>\n<span class=\"pl-c\">/// let foo = \"foo\";</span>\n<span class=\"pl-c\">/// assert_eq!(foo, \"foo\");</span>\n<span class=\"pl-c\">/// ```</span>\n</code></pre>\n<h2>unsafe</h2>\n<p>In the unsafe block (<code>unsafe {}</code>), you can:</p>\n<ul>\n<li>\n<p>Dereference a raw pointer which</p>\n<ul>\n<li>can have both immutable and mutable pointers or multiple mutable pointers to the same location;</li>\n<li>is not guaranteed to point to valid memory;</li>\n<li>can be null;</li>\n<li>does not implement any automatic cleanup.</li>\n</ul>\n</li>\n<li>\n<p>Call an unsafe function or method (<code>unsafe fn dangerous() {}</code>, including foreign functions such as C functions).</p>\n</li>\n<li>\n<p>Access or modify a mutable static variable (Rust call global variables as static variables).</p>\n</li>\n<li>\n<p>Implement an unsafe trait.</p>\n</li>\n<li>\n<p>Access fields of an union (the unsafe counterpart of Rust's <code>enum</code>, mainly used for FFI).</p>\n</li>\n</ul>","date_published":"Sun, 12 Jan 2020 17:27:44 GMT","date_modified":"Sat, 23 May 2020 15:44:13 GMT"},{"id":"https://mmap.page/dive-into/npm/","url":"https://mmap.page/dive-into/npm/","title":"Use npm without package.json","content_html":"<h1>Use npm without package.json</h1>\n<p><strong>I abandoned this idea.</strong>\nIt does not work well with Node.js tooling and brings more unnecessary complexity.</p>\n<h2>Why NOT package.json?</h2>\n<p><code>package.json</code> brings in unnecessary complexity.\nIf you do not think so, have a look at <a href=\"https://pkg.go.dev/\">Go</a> and <a href=\"https://deno.land/std/manual.md\">Deno</a>.</p>\n<h2>Everyday Use without package.json</h2>\n<p>Tell npm to not save package:</p>\n<pre><code class=\"language-sh\">npm config <span class=\"pl-c1\">set</span> save <span class=\"pl-c1\">false</span>\n</code></pre>\n<p>Install development tools as global packages:</p>\n<pre><code class=\"language-sh\">npm i -g typescript\nnpm install -g eslint\nnpm i -g @zeit/ncc\n</code></pre>\n<p>For temporal usage or test, use <code>npx</code>:</p>\n<pre><code class=\"language-sh\">npx cloc index.js\n</code></pre>\n<p><code>npx</code> can also be used to test different node versions:</p>\n<pre><code class=\"language-sh\">npx -p node@13 node -v\n</code></pre>\n<p>Install dependencies as devDependencies:</p>\n<pre><code class=\"language-sh\">npm i -D express\nnpm i -D @types/express\n</code></pre>\n<p>Use <a href=\"https://github.com/zeit/ncc/\">ncc</a> to package runtime dependencies into a single JavaScript file:</p>\n<pre><code class=\"language-sh\"><span class=\"pl-c\"># install dependencies according to resolved urls to tarballs in package-lock.json</span>\n@cat package-lock.json <span class=\"pl-k\">|</span> jq <span class=\"pl-s\"><span class=\"pl-pds\">'</span>.dependencies[].resolved<span class=\"pl-pds\">'</span></span> <span class=\"pl-k\">|</span> xargs npm i --no-package-lock\nncc build index.js --minify <span class=\"pl-c\"># output file: dist/index.js</span>\n</code></pre>\n<p>Then you can move the bundled <code>index.js</code> file to any place where Node.js is installed,\nand run it with <code>node index.js</code> without installing any npm modules.</p>\n<h2>Alternative to <code>npm run</code></h2>\n<p>Just use plain old Makefile, e.g.</p>\n<pre><code class=\"language-makefile\"><span class=\"pl-en\">dist/index.js</span>: index.js\n\t@cat package-lock.json <span class=\"pl-k\">|</span> jq <span class=\"pl-s\"><span class=\"pl-pds\">'</span>.dependencies[].resolved<span class=\"pl-pds\">'</span></span> <span class=\"pl-k\">|</span> xargs npm i --no-package-lock\n\tncc build index.js --minify\n</code></pre>","date_published":"Sun, 15 Dec 2019 10:31:56 GMT","date_modified":"Wed, 07 Sep 2022 07:44:01 GMT"},{"id":"https://mmap.page/dive-into/eslint/","url":"https://mmap.page/dive-into/eslint/","title":"An Opinionated Guide to ESLint","content_html":"<h1>An Opinionated Guide to ESLint</h1>\n<p><a href=\"https://eslint.org/\">ESLint</a> is a powerful and versatile tool.\nI myself only use eslint for problems coming from JavaScript design.\nThus, I can have a short rule list.</p>\n<h2>No Formatting Rule</h2>\n<p>Use <a href=\"https://deno.land/manual/tools/formatter\">deno fmt</a> or <a href=\"https://prettier.io/\">prettier</a> instead.</p>\n<p>I use <code>deno fmt</code> or prettier with its default options,\nwithout any configuration.</p>\n<p><code>deno fmt</code> is faster, while prettier supports more formats.</p>\n<p>Prettier also helps on some non-formatting lint rules.\nFor example, eslint's <code>curly</code> rule helps to avoid misleading code:</p>\n<pre><code class=\"language-js\"><span class=\"pl-k\">if</span> (condition)\n    <span class=\"pl-en\">do_something</span>();\n    <span class=\"pl-en\">do_something_else</span>();\n</code></pre>\n<p>However, prettier will format the above code as below to avoid the above issue:</p>\n<pre><code class=\"language-js\"><span class=\"pl-k\">if</span> (condition) <span class=\"pl-en\">do_something</span>();\n<span class=\"pl-en\">do_something_else</span>();\n</code></pre>\n<p>In the code sample above, I use <code>snake_case</code> for function names.\nThe Python community favors <code>snake_case</code>:</p>\n<blockquote>\n<p>Function names should be lowercase,\nwith words separated by underscores as necessary to improve readability.</p>\n<p>Variable names follow the same convention as function names.</p>\n<p>mixedCase is allowed only in contexts where that’s already the prevailing style\n(e.g. threading.py), to retain backwards compatibility.</p>\n<p>-- <a href=\"https://peps.python.org/pep-0008/#function-and-variable-names\">PEP 8</a></p>\n</blockquote>\n<p>However, mixedCase is prevailing in the JavaScript/TypeScript community.\nThus, I use mixedCase for exported names.</p>\n<h2>TypeScript Can Detect Lots of Errors</h2>\n<p>TypeScript can detect a lot of problems, and it is usually faster.</p>\n<p>For example, the <code>array-callback-return</code> rule is unnecessary,\nbecause if I accidentally forget to write <code>return</code> statement in array mapping function,\nit tends to trigger a type error.\n<code>eqeqeq</code> is another example of an unnecessary rule,\nsince TypeScript complains when you are comparing two values of different types.</p>\n<p>TypeScript also has other helpful checks like <code>noFallthroughCasesInSwitch</code>.</p>\n<p>So just extend one of strictest <a href=\"https://github.com/tsconfig/bases\">tsconfig base</a>.</p>\n<h2>Only Include Obvious Rules</h2>\n<p>Do not include rules such as <code>no-new-object</code> and <code>no-nested-ternary</code>,\nwhich are merely personal choice of programming style.</p>\n<p>So here is the five ESLint rules I use:</p>\n<pre><code class=\"language-js\">{\n<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>parser<span class=\"pl-pds\">\"</span></span><span class=\"pl-k\">:</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>@typescript-eslint/parser<span class=\"pl-pds\">\"</span></span>,\n<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>plugins<span class=\"pl-pds\">\"</span></span><span class=\"pl-k\">:</span> [<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>@typescript-eslint<span class=\"pl-pds\">\"</span></span>],\n<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>rules<span class=\"pl-pds\">\"</span></span><span class=\"pl-k\">:</span> {\n    <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>prefer-arrow-callback<span class=\"pl-pds\">\"</span></span><span class=\"pl-k\">:</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>error<span class=\"pl-pds\">\"</span></span>, <span class=\"pl-c\">// avoid the evil `this`</span>\n    <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>no-multi-assign<span class=\"pl-pds\">\"</span></span><span class=\"pl-k\">:</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>error<span class=\"pl-pds\">\"</span></span>, <span class=\"pl-c\">// no `a = b = c = 1`</span>\n    <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>no-var<span class=\"pl-pds\">\"</span></span><span class=\"pl-k\">:</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>error<span class=\"pl-pds\">\"</span></span>, <span class=\"pl-c\">// use `const` and `let` instead of `var`</span>\n    <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>prefer-const<span class=\"pl-pds\">\"</span></span><span class=\"pl-k\">:</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>error<span class=\"pl-pds\">\"</span></span>, <span class=\"pl-c\">// use `const` when there is no reassignment</span>\n    <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>no-param-reassign<span class=\"pl-pds\">\"</span></span><span class=\"pl-k\">:</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>error<span class=\"pl-pds\">\"</span></span>, <span class=\"pl-c\">// use nonreassignable function parameters</span>\n}\n}\n</code></pre>\n<p>Note that the default ESLint configuration file generated via <code>@eslint/config</code>\nincludes a lot of recommended rules (<code>extends</code>).\nI do not use <code>npm init @eslint/config</code> and add dependencies by hand:</p>\n<pre><code class=\"language-sh\">ni -D eslint @typescript-eslint/eslint-plugin @typescript-eslint/parser\n</code></pre>\n<h2>Alternatives</h2>\n<p><a href=\"https://biomejs.dev/\">Biome</a> and <a href=\"https://quick-lint-js.com/\">quick-lint-ls</a> are faster alternatives to ESLint.\nBiome currently only has <a href=\"https://biomejs.dev/internals/language-support/\">partial support for Svelte and Astro</a>,\nand quick-lint-ls before 3.0 does not support TypeScript.\nTherefore, I still use ESLint.\nHowever, since <a href=\"https://quick-lint-js.com/blog/version-3.0/\">quick-lint-ls 3.0 introduces TypeScript support</a>,\nI plan to try it in future.\nAlso, Deno 2.0 introduces compatibility with Node.js and npm, so I also plan to try <code>deno lint</code> on non Deno projects.</p>","date_published":"Sat, 14 Dec 2019 12:37:15 GMT","date_modified":"Fri, 25 Jul 2025 15:54:06 GMT"},{"id":"https://mmap.page/dive-into/ts-check/","url":"https://mmap.page/dive-into/ts-check/","title":"Fight for Type Safety Stand with JavaScript","content_html":"<h1>Fight for Type Safety Stand with JavaScript</h1>\n<p>Note: This note is based on old versions of TypeScript and ReScript.</p>\n<p>TypeScript 2.3 and later support type-checking JavaScript files with JSDoc types.\nJSDoc uses the Closure Compiler's type language,\nwhich in turn is originally based on the abandoned ES4 spec.\nTherefore, to some extent, TypeScript can check against <a href=\"https://github.com/bkero/es4/blob/master/spec/working-drafts/type-system.pdf\">ES4 type language</a>!</p>\n<pre><code class=\"language-js\"><span class=\"pl-c\">/**</span>\n<span class=\"pl-c\"> * @template T, U</span>\n<span class=\"pl-c\"> * @typedef {U &#x26; { readonly __TYPE__: T}} Opaque */</span>\n\n<span class=\"pl-c\">/** @typedef {Opaque&#x3C;'age', number>} Age */</span>\n<span class=\"pl-c\">/** @type {function(number): Age} */</span>\n<span class=\"pl-k\">const</span> <span class=\"pl-c1\">newAge</span> <span class=\"pl-k\">=</span> (<span class=\"pl-smi\">n</span>) <span class=\"pl-k\">=></span> {\n  <span class=\"pl-k\">if</span> (n <span class=\"pl-k\">&#x3C;</span> <span class=\"pl-c1\">0</span>) {\n    <span class=\"pl-k\">throw</span> <span class=\"pl-k\">new</span> <span class=\"pl-en\">Error</span>(<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>age must be positive<span class=\"pl-pds\">\"</span></span>)\n  } <span class=\"pl-k\">else</span> {\n    <span class=\"pl-k\">return</span> <span class=\"pl-c\">/** @type {Age} */</span>(n)\n  }\n}\n</code></pre>\n<h2>ES4 Type Language Overview</h2>\n<p>Take a glance at ES4 type language:</p>\n<pre><code class=\"language-js\"><span class=\"pl-c\">/** @type {null} */</span>\n<span class=\"pl-k\">const</span> <span class=\"pl-c1\">nil</span> <span class=\"pl-k\">=</span> <span class=\"pl-c1\">null</span>\n\n<span class=\"pl-c\">/** @type {string?} */</span>\n<span class=\"pl-k\">let</span> nullable <span class=\"pl-k\">=</span> <span class=\"pl-c1\">null</span>\n\n<span class=\"pl-c\">/** @type {function(number, number): number} */</span>\n<span class=\"pl-k\">const</span> <span class=\"pl-c1\">functionType</span> <span class=\"pl-k\">=</span> (<span class=\"pl-smi\">x</span>, <span class=\"pl-smi\">y</span>) <span class=\"pl-k\">=></span> x <span class=\"pl-k\">+</span> y\n\n<span class=\"pl-c\">/**</span>\n<span class=\"pl-c\"> * function.&#x3C;T>(T): T</span>\n<span class=\"pl-c\"> * @type {&#x3C;T>(x: T) => T}</span>\n<span class=\"pl-c\"> */</span>\n<span class=\"pl-k\">const</span> <span class=\"pl-c1\">genericFunction</span> <span class=\"pl-k\">=</span> <span class=\"pl-smi\">x</span> <span class=\"pl-k\">=></span> x\n\n<span class=\"pl-c\">/**</span>\n<span class=\"pl-c\"> * @type { {k: string} }</span>\n<span class=\"pl-c\"> */</span>\n<span class=\"pl-k\">const</span> <span class=\"pl-c1\">objectType</span> <span class=\"pl-k\">=</span> { k<span class=\"pl-k\">:</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>structural<span class=\"pl-pds\">\"</span></span> }\n\n<span class=\"pl-c\">/**</span>\n<span class=\"pl-c\"> * (string, number)</span>\n<span class=\"pl-c\"> * @type {string  | number}</span>\n<span class=\"pl-c\"> */</span>\n<span class=\"pl-k\">let</span> unionType <span class=\"pl-k\">=</span> <span class=\"pl-c1\">0</span>\n\n<span class=\"pl-c\">/**</span>\n<span class=\"pl-c\"> * [number]</span>\n<span class=\"pl-c\"> * @type {number[]}</span>\n<span class=\"pl-c\"> */</span>\n<span class=\"pl-k\">const</span> <span class=\"pl-c1\">arrayType</span> <span class=\"pl-k\">=</span> [<span class=\"pl-c1\">1</span>, <span class=\"pl-c1\">2</span>, <span class=\"pl-c1\">3</span>]\n\n<span class=\"pl-k\">const</span> <span class=\"pl-c1\">immutableArray</span> <span class=\"pl-k\">=</span> <span class=\"pl-c\">/** @type {const} */</span> ([<span class=\"pl-c1\">1</span>, <span class=\"pl-c1\">2</span>, <span class=\"pl-c1\">3</span>])\n\n<span class=\"pl-c\">/**</span>\n<span class=\"pl-c\"> * @type {[string, number]}</span>\n<span class=\"pl-c\"> */</span>\n<span class=\"pl-k\">const</span> <span class=\"pl-c1\">tupleType</span> <span class=\"pl-k\">=</span> [<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>one<span class=\"pl-pds\">\"</span></span>, <span class=\"pl-c1\">1</span>]\n\n<span class=\"pl-c\">/** @type {*} */</span>\n<span class=\"pl-k\">let</span> dynamicType <span class=\"pl-k\">=</span> <span class=\"pl-c1\">null</span>\n</code></pre>\n<p>Note that TypeScript syntax differs from ES4 for the following types:</p>\n<ol start=\"0\">\n<li>dynamic type: <code>any</code> vs <code>*</code></li>\n<li>union type: <code>A | B</code> vs <code>(A, B)</code></li>\n<li>array: <code>T[]</code> vs <code>[T]</code></li>\n<li>function: <code>(x: P) => R</code> vs <code>function(P): R</code></li>\n</ol>\n<p>Since Closure Compiler also uses <code>*</code> and <code>function(P): R</code>,\nand TypeScript tries to be compatible with Closure type syntax,\nTypeScript also accepts <code>*</code> and <code>function(P): R</code> in JSDoc type annotation.\nHowever, some function type cannot be expressed in <code>function(P): R</code> form,\ne.g. type guard and assertion signature:</p>\n<pre><code class=\"language-js\"><span class=\"pl-c\">/** @typedef { {swim(): void;} } Fish */</span>\n<span class=\"pl-c\">/** @typedef { {fly(): void;} } Bird */</span>\n\n<span class=\"pl-c\">/** @type {(p: Fish | Bird) => p is Fish} */</span>\n<span class=\"pl-k\">const</span> <span class=\"pl-c1\">isFish</span> <span class=\"pl-k\">=</span>  (<span class=\"pl-smi\">p</span>) <span class=\"pl-k\">=></span> <span class=\"pl-c\">/** @type {Fish} */</span>(p).<span class=\"pl-smi\">swim</span> <span class=\"pl-k\">!==</span> <span class=\"pl-c1\">undefined</span>\n\n<span class=\"pl-c\">/** @type {(p: Fish | Bird) => asserts p is Fish} */</span>\n<span class=\"pl-k\">const</span> <span class=\"pl-c1\">assertIsFish</span> <span class=\"pl-k\">=</span> (<span class=\"pl-smi\">p</span>) <span class=\"pl-k\">=></span> {\n    <span class=\"pl-k\">if</span> (<span class=\"pl-c\">/** @type {Fish} */</span>(p).<span class=\"pl-smi\">swim</span> <span class=\"pl-k\">===</span> <span class=\"pl-c1\">undefined</span>) {\n        <span class=\"pl-k\">throw</span> <span class=\"pl-k\">new</span> <span class=\"pl-en\">AssertionError</span>(<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>not a string<span class=\"pl-pds\">\"</span></span>);\n    }\n}\n</code></pre>\n<p>And there are other subtle differences,\ne.g. ES4 tuples should have at least two elements.\nBut let's just ignore these details for now.</p>\n<h2>More Syntax Borrowed from Closure Compiler</h2>\n<h3>Type Alias</h3>\n<p>Type aliases can be defined with the keyword <code>@typedef</code>:</p>\n<pre><code class=\"language-js\"><span class=\"pl-c\">/** @typedef { {x: number, y: number} } Pointer */</span>\n<span class=\"pl-c\">/** @type {Pointer} */</span>\n<span class=\"pl-k\">const</span> <span class=\"pl-c1\">typeAlias</span> <span class=\"pl-k\">=</span> { x<span class=\"pl-k\">:</span> <span class=\"pl-c1\">0</span>, y<span class=\"pl-k\">:</span> <span class=\"pl-c1\">0</span> }\n</code></pre>\n<p>Generic type parameters can be defined with the keyword <code>template</code>:</p>\n<pre><code class=\"language-js\"><span class=\"pl-c\">/**</span>\n<span class=\"pl-c\"> * @template T, U</span>\n<span class=\"pl-c\"> * @typedef {U &#x26; { readonly __TYPE__: T}} Opaque */</span>\n\n<span class=\"pl-c\">/** @typedef {Opaque&#x3C;'age', number>} Age */</span>\n<span class=\"pl-c\">/** @type {function(number): Age} */</span>\n<span class=\"pl-k\">const</span> <span class=\"pl-c1\">newAge</span> <span class=\"pl-k\">=</span> (<span class=\"pl-smi\">n</span>) <span class=\"pl-k\">=></span> {\n  <span class=\"pl-k\">if</span> (n <span class=\"pl-k\">&#x3C;</span> <span class=\"pl-c1\">0</span>) {\n    <span class=\"pl-k\">throw</span> <span class=\"pl-k\">new</span> <span class=\"pl-en\">Error</span>(<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>age must be positive<span class=\"pl-pds\">\"</span></span>)\n  } <span class=\"pl-k\">else</span> {\n    <span class=\"pl-c\">// Type cast requires parenthesized expression.</span>\n    <span class=\"pl-k\">return</span> <span class=\"pl-c\">/** @type {Age} */</span>(n)\n  }\n}\n</code></pre>\n<h3>Enum</h3>\n<p><code>@enum</code> is also borrowed from <a href=\"https://github.com/google/closure-compiler/wiki/Annotating-JavaScript-for-the-Closure-Compiler#enum-type\">Closure Compiler's type system</a>,\nand is quite different from <a href=\"https://www.typescriptlang.org/docs/handbook/enums.html\">TypeScript's enum</a>.</p>\n<pre><code class=\"language-js\"><span class=\"pl-c\">/**</span>\n<span class=\"pl-c\"> * @enum {function(number): number}</span>\n<span class=\"pl-c\"> */</span>\n<span class=\"pl-k\">const</span> <span class=\"pl-c1\">immutableObjectLiteral</span> <span class=\"pl-k\">=</span> {\n  <span class=\"pl-c\">/** @type {function(number)} */</span>\n  <span class=\"pl-en\">succ</span><span class=\"pl-k\">:</span> <span class=\"pl-smi\">n</span> <span class=\"pl-k\">=></span> n <span class=\"pl-k\">+</span> <span class=\"pl-c1\">1</span>,\n  <span class=\"pl-c\">/** @type {function(number)} */</span>\n  <span class=\"pl-en\">pred</span><span class=\"pl-k\">:</span> <span class=\"pl-smi\">n</span> <span class=\"pl-k\">=></span> n <span class=\"pl-k\">-</span> <span class=\"pl-c1\">1</span>\n}\n</code></pre>\n<h3>Function Overloads</h3>\n<pre><code class=\"language-js\"><span class=\"pl-c\">/**</span>\n<span class=\"pl-c\"> * @param {string} input</span>\n<span class=\"pl-c\"> * @returns {string} result</span>\n<span class=\"pl-c\"> *//**</span>\n<span class=\"pl-c\"> * @param {number} input</span>\n<span class=\"pl-c\"> * @returns {string} result</span>\n<span class=\"pl-c\"> */</span>\n<span class=\"pl-k\">function</span> <span class=\"pl-en\">notSupported</span>(<span class=\"pl-smi\">input</span>) { <span class=\"pl-c\">/* omit */</span> }\n</code></pre>\n<p>Instead, TypeScript supports <a href=\"https://github.com/microsoft/TypeScript/pull/51234\">a new <code>@overload</code> tag</a>.</p>\n<h3>Import Types</h3>\n<p>Use <code>import(\"module\").Type</code> to import types:</p>\n<pre><code class=\"language-js\"><span class=\"pl-c\">/** @type { import(\"m\").T } */</span>\n</code></pre>\n<p>This is often used in type aliases for brevity:</p>\n<pre><code class=\"language-js\"><span class=\"pl-c\">/** @typedef { import(\"module-name\").LongTypeName } ShortName */</span>\n</code></pre>\n<p>But if you have difficulties in expressing certain types in JSDoc comments,\nyou can also declare the type in a separate TypeScript file,\nthen import it in JSDoc comments.</p>\n<h2>Type Checking</h2>\n<p>Just create a <code>jsconfig.json</code> file under the root of the project.</p>\n<p>It is possible to check JavaScript files without the <code>jsconfig.json</code> file\nwith writing magic comment <code>// @ts-check</code>\nor setting a configuration option in vscode.\nBut I prefer the <code>jsconfig.json</code> way, since I tend to set up some compiler options.</p>\n<h2>Why</h2>\n<p>Actually ES4 type system is quite different from TypeScript.\nFor example, they have different subtype rules.\nAlso, the JSDoc way of TypeScript type checking lacks some features,\nfor example, there is no way to pass type parameter when invoking generic functions via JSDoc.\nThe only thing we can do is let TypeScript infer the type parameter.\nIf it fails to infer the type, we have to accept <code>any</code> as the type parameter.\nAnother example is TypeScript cannot parse conditional types in JSDoc comments correctly. (<a href=\"https://github.com/microsoft/TypeScript/issues/27424\">#27424</a>)</p>\n<p>So why not code in TypeScript instead?</p>\n<p>Possible reasons:</p>\n<ol>\n<li>Get rid of the compilation step.</li>\n<li>Avoid using TypeScript features unavailable in ECMAScript.</li>\n<li>Secretly migrate a JavaScript project to TypeScript when other project developers do not want to switch to TypeScript.</li>\n</ol>\n<h2>Alternatives</h2>\n<p>An alternative approach for a secret migration from JavaScript is to rewrite them in ReScript,\nand use genType to generate TypeScript files.</p>\n<pre><code class=\"language-ts\"><span class=\"pl-c\">/* TypeScript file generated from index.res by genType. */</span>\n<span class=\"pl-c\">/* eslint-disable import/first */</span>\n\n<span class=\"pl-c\">// @ts-ignore: Implicit any on import</span>\n<span class=\"pl-k\">import</span> <span class=\"pl-c1\">*</span> <span class=\"pl-k\">as</span> <span class=\"pl-smi\">indexBS__Es6Import</span> <span class=\"pl-k\">from</span> <span class=\"pl-s\"><span class=\"pl-pds\">'</span>./index.bs<span class=\"pl-pds\">'</span></span>;\n<span class=\"pl-k\">const</span> <span class=\"pl-c1\">indexBS</span><span class=\"pl-k\">:</span> <span class=\"pl-c1\">any</span> <span class=\"pl-k\">=</span> <span class=\"pl-smi\">indexBS__Es6Import</span>;\n\n<span class=\"pl-c\">// tslint:disable-next-line:interface-over-type-literal</span>\n<span class=\"pl-k\">export</span> <span class=\"pl-k\">const</span> <span class=\"pl-en\">h1</span><span class=\"pl-k\">:</span> (<span class=\"pl-v\">line</span><span class=\"pl-k\">:</span><span class=\"pl-c1\">string</span>) <span class=\"pl-k\">=></span> <span class=\"pl-c1\">string</span> <span class=\"pl-k\">=</span> <span class=\"pl-smi\">indexBS</span>.<span class=\"pl-smi\">h1</span>;\n</code></pre>\n<p>This TypeScript files work, but the <code>indexBS</code> part is not perfectly human-readable.\nThe TypeScript compiler can be used to generate corresponding <code>.d.ts</code> files.</p>\n<pre><code class=\"language-ts\"><span class=\"pl-k\">export</span> <span class=\"pl-k\">declare</span> <span class=\"pl-k\">const</span> <span class=\"pl-en\">htm</span><span class=\"pl-k\">:</span> (<span class=\"pl-v\">text</span><span class=\"pl-k\">:</span> <span class=\"pl-c1\">string</span>) <span class=\"pl-k\">=></span> <span class=\"pl-c1\">string</span>;\n</code></pre>\n<p>This approach also brings in a sound type system.</p>","date_published":"Sat, 14 Dec 2019 09:11:48 GMT","date_modified":"Tue, 27 Aug 2024 11:32:47 GMT"},{"id":"https://mmap.page/dive-into/rarcrack/","url":"https://mmap.page/dive-into/rarcrack/","title":"RarCrack Basic Guide","content_html":"<h1>RarCrack Basic Guide</h1>\n<p>This note is written for RarCrack 0.2.</p>\n<p>RarCrack brute-forces password for encrypted zip, rar, 7z files.</p>\n<pre><code class=\"language-sh\">rarcrack FILE_NAME --threads 4\n</code></pre>\n<p>Note that if <code>--threads</code> is omitted, RarCrack will use 2 threads, no matter how many cores your CPU has.</p>\n<p>You can cancel the brute forcing (e.g. via <code>Ctrl-c</code>) at any time,\nand RarCrack will resume cracking at next startup.\nThis is because RarCrack uses a status file <code>FILE_NAME.xml</code> at the same directory to record progress.</p>\n<p>And this mechanism can be used to speed up cracking.\nFor example, if you remember that the password is 6 digits:</p>\n<pre><code class=\"language-xml\">&#x3C;?<span class=\"pl-ent\">xml</span><span class=\"pl-e\"> version</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>1.0<span class=\"pl-pds\">\"</span></span><span class=\"pl-e\"> encoding</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>UTF-8<span class=\"pl-pds\">\"</span></span>?>\n&#x3C;<span class=\"pl-ent\">rarcrack</span>>\n  &#x3C;<span class=\"pl-ent\">abc</span>>0123456789&#x3C;/<span class=\"pl-ent\">abc</span>>\n  &#x3C;<span class=\"pl-ent\">current</span>>000000&#x3C;/<span class=\"pl-ent\">current</span>>\n  &#x3C;<span class=\"pl-ent\">good_password</span>/>\n&#x3C;/<span class=\"pl-ent\">rarcrack</span>>\n</code></pre>\n<p>For zip and 7z files, an alternative to RarCrack is fcrackzip.\nAnd it has more features, e.g. specifying password range and using a dictionary.\nHowever, last time I tried to fcrackzip a zip file,\nit reported that the zip file is corrupt.\nAnd RarCrack successfully cracks the very zip file.</p>","date_published":"Sat, 23 Nov 2019 20:12:03 GMT","date_modified":"Tue, 06 Sep 2022 05:05:55 GMT"},{"id":"https://mmap.page/dive-into/puppet/","url":"https://mmap.page/dive-into/puppet/","title":"A Basic Guide for New Marionettists","content_html":"<h1>A Basic Guide for New Marionettists</h1>\n<h2>TLDR</h2>\n<p>This article only covers the so-called masterless mode, a.k.a. <code>puppet apply</code>,\nbecause the <a href=\"https://puppet.com/docs/puppet/6.7/architecture.html\">master-slave mode</a> is <a href=\"https://bugs.python.org/issue34605\">unethical</a> and <a href=\"https://puppet.com/products/bolt\">bolt</a> sounds violent. On the other hand, <code>puppet apply</code> plays the role of both master and slave, which is considered not unlikely inoffensive.</p>\n<p>Puppet uses a declarative DSL, i.e. describing the state of puppets. Below is an example from <a href=\"https://puppet.com/docs/puppet/6.7/intro_puppet_language_and_code.html\">the official document</a>:</p>\n<pre><code class=\"language-puppet\"><span class=\"pl-k\">case</span> <span class=\"pl-smi\">$operatingsystem</span> {\n  centos, <span class=\"pl-en\">redhat:</span> { <span class=\"pl-smi\">$service_name</span> = <span class=\"pl-s\"><span class=\"pl-pds\">'</span>ntpd<span class=\"pl-pds\">'</span></span> }\n  debian, <span class=\"pl-en\">ubuntu:</span> { <span class=\"pl-smi\">$service_name</span> = <span class=\"pl-s\"><span class=\"pl-pds\">'</span>ntp<span class=\"pl-pds\">'</span></span> }\n}\n\n<span class=\"pl-k\">package</span> { <span class=\"pl-en\">'ntp'</span>:\n  <span class=\"pl-c1\">ensure </span>=> installed,\n}\n\n<span class=\"pl-k\">service</span> { <span class=\"pl-en\">'ntp'</span>:\n  <span class=\"pl-c1\">name      </span>=> <span class=\"pl-smi\">$service_name</span>,\n  <span class=\"pl-c1\">ensure    </span>=> <span class=\"pl-c1\">running</span>,\n  <span class=\"pl-c1\">enable    </span>=> <span class=\"pl-c1\">true</span>,\n  <span class=\"pl-c1\">subscribe </span>=> <span class=\"pl-c1\">File</span>[<span class=\"pl-s\"><span class=\"pl-pds\">'</span>ntp.conf<span class=\"pl-pds\">'</span></span>],\n}\n\n<span class=\"pl-k\">file</span> { <span class=\"pl-en\">'ntp.conf'</span>:\n  <span class=\"pl-c1\">path    </span>=> <span class=\"pl-s\"><span class=\"pl-pds\">'</span>/etc/ntp.conf<span class=\"pl-pds\">'</span></span>,\n  <span class=\"pl-c1\">ensure  </span>=> <span class=\"pl-c1\">file</span>,\n  <span class=\"pl-c1\">require </span>=> Package[<span class=\"pl-s\"><span class=\"pl-pds\">'</span>ntp<span class=\"pl-pds\">'</span></span>],\n  <span class=\"pl-c1\">source  </span>=> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>puppet:///modules/ntp/ntp.conf<span class=\"pl-pds\">\"</span></span>,\n}\n</code></pre>\n<p>This guide applies to Puppet 6.7.</p>\n<h2>Quick Start</h2>\n<p>Install the <code>puppet-agent</code> package (which provides <code>puppet apply</code>),\nfollowing the <a href=\"https://puppet.com/docs/puppet/6.7/install_agents.html\">instructions at official document</a>.</p>\n<p>As an oversimplified example, I wrote a script to ensure git is installed:</p>\n<pre><code class=\"language-puppet\"><span class=\"pl-c\"># filename: laptop.pp</span>\n<span class=\"pl-k\">package</span> {<span class=\"pl-en\">'git'</span>:\n  <span class=\"pl-c1\">ensure </span>=> installed\n}\n</code></pre>\n<p>Validate its syntax:</p>\n<pre><code class=\"language-sh\">puppet parser validate laptop.pp\n</code></pre>\n<p>In practice, this is mainly for CI,\nsince a decent editor should have warned you if you made some syntax mistakes.</p>\n<p>Rehearse the play (dry run):</p>\n<pre><code class=\"language-sh\">puppet apply --noop laptop.pp\n</code></pre>\n<p>It's show time: (run as root since installing package usually requires root permission)</p>\n<pre><code class=\"language-sh\">puppet apply laptop.pp\n</code></pre>\n<p>You can also pass a directory instead of a file to <code>puppet apply</code>.\nBut in this case Puppet combines all files under that directory as one script,\nwithout isolated scope.\nThus I prefer use one file.</p>\n<h2>Puppet DSL</h2>\n<h3>Style</h3>\n<p>The Puppet community prefers <code>snake_case</code> and two spaces soft tab.</p>\n<h3>Selector Expression</h3>\n<p>Selector expression returns a value.\nFor example, the case \"statement\" in the beginning code sample:</p>\n<pre><code class=\"language-puppet\"><span class=\"pl-k\">case</span> <span class=\"pl-smi\">$operatingsystem</span> {\n  centos, <span class=\"pl-en\">redhat:</span> { <span class=\"pl-smi\">$service_name</span> = <span class=\"pl-s\"><span class=\"pl-pds\">'</span>ntpd<span class=\"pl-pds\">'</span></span> }\n  debian, <span class=\"pl-en\">ubuntu:</span> { <span class=\"pl-smi\">$service_name</span> = <span class=\"pl-s\"><span class=\"pl-pds\">'</span>ntp<span class=\"pl-pds\">'</span></span> }\n}\n</code></pre>\n<p>can be rewritten as:</p>\n<pre><code class=\"language-puppet\"><span class=\"pl-smi\">$service_name</span> = <span class=\"pl-smi\">$operatingsystem</span> ? {\n  centos, <span class=\"pl-c1\">redhat </span>=> <span class=\"pl-s\"><span class=\"pl-pds\">'</span>ntpd<span class=\"pl-pds\">'</span></span>,\n  debian, <span class=\"pl-c1\">ubuntu </span>=> <span class=\"pl-s\"><span class=\"pl-pds\">'</span>ntp<span class=\"pl-pds\">'</span></span>,\n}\n</code></pre>\n<p>Strictly speaking, they are not semantically equivalent.\nIf the os failed to match, the former will do nothing,\nwhile the later will refuse to compile.</p>\n<p>However, the <code>if</code> and <code>case</code> \"statements\" are actually expressions,\nreturning the value of the last expression in the executed block\nor <code>undef</code> when no block was executed.</p>\n<h3>Puppet Defaults</h3>\n<p>Puppet DSL has a wired syntax (capitalizing type name) for declaring defaults for a specific type of puppet:</p>\n<pre><code class=\"language-puppet\"><span class=\"pl-c\"># Set default values for the path attribute of the exec puppet.</span>\nExec {\n  <span class=\"pl-c1\">path </span>=> <span class=\"pl-s\"><span class=\"pl-pds\">'</span>/usr/bin:/bin:/usr/sbin:/sbin<span class=\"pl-pds\">'</span></span>,\n}\n</code></pre>\n<p>The more wired part is, puppet defaults are <strong>dynamically scoped</strong>!</p>\n<p>Therefore, using per-expression defaults is preferred.\nBelow is an example from <a href=\"https://puppet.com/docs/puppet/6.7/lang_resources.html#resource-declaration-default-attributes\">the official document</a>:</p>\n<pre><code class=\"language-puppet\"><span class=\"pl-c1\">file</span> {\n  <span class=\"pl-en\">default:</span>\n    <span class=\"pl-c1\">ensure </span>=> <span class=\"pl-c1\">file</span>,\n    <span class=\"pl-c1\">owner  </span>=> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>root<span class=\"pl-pds\">\"</span></span>,\n    <span class=\"pl-c1\">group  </span>=> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>wheel<span class=\"pl-pds\">\"</span></span>,\n    <span class=\"pl-c1\">mode   </span>=> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>0600<span class=\"pl-pds\">\"</span></span>,\n  ;\n  [<span class=\"pl-s\"><span class=\"pl-pds\">'</span>ssh_host_dsa_key<span class=\"pl-pds\">'</span></span>, <span class=\"pl-s\"><span class=\"pl-pds\">'</span>ssh_host_key<span class=\"pl-pds\">'</span></span>, <span class=\"pl-s\"><span class=\"pl-pds\">'</span>ssh_host_rsa_key<span class=\"pl-pds\">'</span></span>]:\n    <span class=\"pl-c\"># use all defaults</span>\n  ;\n  [<span class=\"pl-s\"><span class=\"pl-pds\">'</span>ssh_config<span class=\"pl-pds\">'</span></span>, <span class=\"pl-s\"><span class=\"pl-pds\">'</span>ssh_host_dsa_key.pub<span class=\"pl-pds\">'</span></span>, <span class=\"pl-s\"><span class=\"pl-pds\">'</span>ssh_host_key.pub<span class=\"pl-pds\">'</span></span>, <span class=\"pl-s\"><span class=\"pl-pds\">'</span>ssh_host_rsa_key.pub<span class=\"pl-pds\">'</span></span>, <span class=\"pl-s\"><span class=\"pl-pds\">'</span>sshd_config<span class=\"pl-pds\">'</span></span>]:\n    <span class=\"pl-c\"># override mode</span>\n    <span class=\"pl-c1\">mode </span>=> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>0644<span class=\"pl-pds\">\"</span></span>,\n  ;\n}\n</code></pre>\n<h3>Puppet Collector</h3>\n<p>This is sometimes called the \"spaceship operator\",\nwhich selects a group of puppets via attribute searching:</p>\n<pre><code class=\"language-puppet\">User &#x3C;| groups == <span class=\"pl-s\"><span class=\"pl-pds\">'</span>wheel<span class=\"pl-pds\">'</span></span> |>\n</code></pre>\n<p>Besides <code>==</code>, there are other operators, <code>!=</code>, <code>and</code>, and <code>or</code>.</p>\n<h3>Lazy Puppet</h3>\n<p>The at (<code>@</code>) prefix marks a puppet declaration as lazy:</p>\n<pre><code class=\"language-puppet\"><span class=\"pl-k\">@user</span> {<span class=\"pl-en\">'ubuntu'</span>:\n  <span class=\"pl-c1\">uid </span>=> 1000,\n  <span class=\"pl-c1\">comment </span>=> <span class=\"pl-s\"><span class=\"pl-pds\">'</span>default user<span class=\"pl-pds\">'</span></span>,\n  <span class=\"pl-c1\">group </span>=> wheel,\n}\n</code></pre>\n<p>Lazy puppets will not be applied until:</p>\n<ol>\n<li>explicitly realized, e.g. <code>realize User['ubuntu']</code>, or</li>\n<li>implicitly realized by a matched collector, e.g. <code>User &#x3C;| group == wheel |></code>.</li>\n</ol>\n<h2>Glossary</h2>\n<p>This guide uses different terms to the official Puppet documentation.\nThese are just my personal preference.\nFor example, the <em>script</em> term used in this guide is called <strong>manifest</strong> in the official Puppet documentation.\nIn my opinion, <em>script</em> makes more sense than <strong>manifest</strong>.\nIn fact, <a href=\"https://www.chef.io/\">chef</a> refers to the similar notation as <a href=\"https://docs.chef.io/recipes.html\">recipe</a>.</p>\n<ul>\n<li><strong>agent</strong> Puppet actually uses the term agent instead of <em>slave</em>, but this is just a euphemism.</li>\n<li><strong>catalog</strong> In master <em>slave</em> mode, catalog are compiled by master with <em>stage</em> specific information. In <code>puppet apply</code> mode, it is just unimportant mid-product.</li>\n<li><strong>class</strong> A <em>set</em> of puppets. And a <strong>subclass</strong> is <em>an extended set</em> of puppets base on another <em>set</em> of puppets, a.k.a. a class <code>inherits</code> another class.</li>\n<li><strong>environment</strong> A <em>play</em>.</li>\n<li><strong>fact</strong> A <em>detail</em> about the <em>stage</em>.</li>\n<li><strong>Facter</strong> The <em>stage manager</em> can tell you <em>details</em> about the <em>stage</em>.</li>\n<li><strong>filebucket</strong> A repository for file backups.</li>\n<li><strong>Hiera</strong> A built-in key-value database for puppet.</li>\n<li><strong>lambda</strong> In Puppet, a lambda can only be used in function calls. That is, it can only be passed to functions, but cannot be assigned to variables. To some extent, it is more like Ruby's block.</li>\n<li><strong>manifest</strong> The <em>script</em> used by a marionettist. Puppet refers to the entry point as <strong>main manifest</strong> or <strong>site manifest</strong>. <code>puppet apply</code> only cares about the <em>script</em> passed to it on the command line.</li>\n<li><strong>node</strong> The <em>stage</em> for the show. In <code>puppet apply</code> mode, the local machine is the only <em>stage</em>.</li>\n<li><strong>resource</strong> A <em>puppet</em> controlled by the marionettist. Puppet uses the term <strong>virtual resource</strong> to refer to <em>lazy puppet</em>.</li>\n</ul>","date_published":"Sat, 03 Aug 2019 08:34:35 GMT","date_modified":"Sun, 24 May 2020 13:58:17 GMT"},{"id":"https://mmap.page/dive-into/react/","url":"https://mmap.page/dive-into/react/","title":"A Quick Introduction to React","content_html":"<h1>A Quick Introduction to React</h1>\n<h2>Hello World</h2>\n<pre><code class=\"language-tsx\"><span class=\"pl-k\">import</span> <span class=\"pl-smi\">React</span>, { <span class=\"pl-smi\">ReactElement</span> } <span class=\"pl-k\">from</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>react<span class=\"pl-pds\">\"</span></span>\n<span class=\"pl-k\">import</span> <span class=\"pl-smi\">ReactDOM</span> <span class=\"pl-k\">from</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>react-dom<span class=\"pl-pds\">\"</span></span>\n\n\n<span class=\"pl-k\">type</span> <span class=\"pl-en\">HelloProps</span> <span class=\"pl-k\">=</span> { <span class=\"pl-k\">readonly</span> <span class=\"pl-v\">name</span><span class=\"pl-k\">:</span> <span class=\"pl-c1\">string</span> }\n\n<span class=\"pl-k\">function</span> <span class=\"pl-en\">Hello</span>({ <span class=\"pl-v\">name</span> }<span class=\"pl-k\">:</span> <span class=\"pl-en\">HelloProps</span>)<span class=\"pl-k\">:</span> <span class=\"pl-en\">ReactElement</span>&#x3C;<span class=\"pl-en\">HelloProps</span>> {\n  <span class=\"pl-k\">return</span> &#x3C;<span class=\"pl-ent\">button</span>>Hello <span class=\"pl-pse\">{</span><span class=\"pl-smi\">name</span><span class=\"pl-pse\">}</span>!&#x3C;/<span class=\"pl-ent\">button</span>>\n}\n\n<span class=\"pl-k\">const</span> <span class=\"pl-c1\">helloWorld</span><span class=\"pl-k\">:</span> <span class=\"pl-en\">ReactElement</span>&#x3C;<span class=\"pl-en\">HelloProps</span>> <span class=\"pl-k\">=</span> &#x3C;<span class=\"pl-c1\">Hello</span> <span class=\"pl-e\">name</span><span class=\"pl-k\">=</span><span class=\"pl-s\"><span class=\"pl-pds\">\"</span>World<span class=\"pl-pds\">\"</span></span> />\n\n<span class=\"pl-k\">const</span> <span class=\"pl-c1\">rootElement</span><span class=\"pl-k\">:</span> <span class=\"pl-en\">HTMLElement</span> <span class=\"pl-k\">=</span> <span class=\"pl-c1\">document</span>.<span class=\"pl-c1\">getElementById</span>(<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>root<span class=\"pl-pds\">\"</span></span>)\n<span class=\"pl-smi\">ReactDOM</span>.<span class=\"pl-en\">render</span>(<span class=\"pl-smi\">helloWorld</span>, <span class=\"pl-smi\">rootElement</span>)\n</code></pre>\n<h2>React Components</h2>\n<p>The <code>Hello</code> function is a React component,\nwhich receives an object containing properties,\nand returns a ReactElement.\nHere I do not plan to change the value of the <code>name</code> property,\nso I annotate it as readonly.\nBut these properties can be mutable.\nReactElements can be considered as extensible html elements,\nor some content to be rendered.\nA react component may return null for conditional rendering.</p>\n<h2>Hooks</h2>\n<p>Hooks decouple state related logic from components.\nLike components, hooks are just functions, nothing magical:</p>\n<pre><code class=\"language-javascript\"><span class=\"pl-k\">const</span> <span class=\"pl-c1\">SimpleReact</span> <span class=\"pl-k\">=</span> (<span class=\"pl-k\">function</span>() {\n    <span class=\"pl-k\">let</span> state\n    <span class=\"pl-k\">return</span> {\n      <span class=\"pl-en\">render</span>(<span class=\"pl-smi\">Component</span>) {\n        <span class=\"pl-k\">const</span> <span class=\"pl-c1\">C</span> <span class=\"pl-k\">=</span> <span class=\"pl-en\">Component</span>()\n        <span class=\"pl-c1\">C</span>.<span class=\"pl-en\">render</span>()\n        <span class=\"pl-k\">return</span> <span class=\"pl-c1\">C</span>\n      },\n      <span class=\"pl-en\">useState</span>(<span class=\"pl-smi\">initialValue</span>) {\n        state <span class=\"pl-k\">=</span> state <span class=\"pl-k\">||</span> initialValue\n        <span class=\"pl-k\">function</span> <span class=\"pl-en\">setState</span>(<span class=\"pl-smi\">newValue</span>) {\n          state <span class=\"pl-k\">=</span> newValue\n        }\n        <span class=\"pl-k\">return</span> [state, setState]\n      }\n    }\n})()\n\n<span class=\"pl-k\">const</span> <span class=\"pl-c1\">useState</span> <span class=\"pl-k\">=</span> <span class=\"pl-smi\">SimpleReact</span>.<span class=\"pl-smi\">useState</span>\n<span class=\"pl-k\">const</span> <span class=\"pl-c1\">render</span> <span class=\"pl-k\">=</span> <span class=\"pl-smi\">SimpleReact</span>.<span class=\"pl-smi\">render</span>\n\n<span class=\"pl-k\">function</span> <span class=\"pl-en\">useCountCharacters</span>(<span class=\"pl-smi\">str</span>) {\n    <span class=\"pl-k\">const</span> [<span class=\"pl-c1\">text</span>, <span class=\"pl-c1\">setText</span>] <span class=\"pl-k\">=</span> <span class=\"pl-en\">useState</span>(str)\n    <span class=\"pl-k\">const</span> <span class=\"pl-c1\">len</span> <span class=\"pl-k\">=</span> <span class=\"pl-smi\">text</span>.<span class=\"pl-c1\">length</span>\n    <span class=\"pl-k\">return</span> [len, setText]\n}\n\n<span class=\"pl-k\">function</span> <span class=\"pl-en\">Component</span>() {\n    <span class=\"pl-k\">const</span> [<span class=\"pl-c1\">len</span>, <span class=\"pl-c1\">setLen</span>] <span class=\"pl-k\">=</span> <span class=\"pl-en\">useCountCharacters</span>(<span class=\"pl-s\"><span class=\"pl-pds\">\"\"</span></span>)\n    <span class=\"pl-k\">return</span> {\n      <span class=\"pl-en\">type</span><span class=\"pl-k\">:</span> <span class=\"pl-smi\">txt</span> <span class=\"pl-k\">=></span> <span class=\"pl-en\">setLen</span>(txt),\n      <span class=\"pl-en\">render</span><span class=\"pl-k\">:</span> () <span class=\"pl-k\">=></span> <span class=\"pl-en\">console</span>.<span class=\"pl-c1\">log</span>({ len })\n    }\n}\n\n<span class=\"pl-k\">let</span> App <span class=\"pl-k\">=</span> <span class=\"pl-en\">render</span>(Component) <span class=\"pl-c\">// { len: 0 }</span>\n<span class=\"pl-smi\">App</span>.<span class=\"pl-c1\">type</span>(<span class=\"pl-s\"><span class=\"pl-pds\">'</span>hello<span class=\"pl-pds\">'</span></span>)\nApp <span class=\"pl-k\">=</span> <span class=\"pl-en\">render</span>(Component) <span class=\"pl-c\">// { len: 5 }</span>\n</code></pre>\n<p>The real React will re-render components on state changes automatically.\nAnd there are other kind of hooks, e.g. <code>useEffect</code> for side-effects, triggered on state changes.\nAlso, the real React can handle multiple hooks, which can be considered as <a href=\"https://medium.com/@ryardley/react-hooks-not-magic-just-arrays-cd4f1857236e\">an array of hooks</a>.\nWhatever, the above naive implementation captures the essence of React Hooks.</p>\n<h2>JSX</h2>\n<p><code>&#x3C;button>Hello {name}!&#x3C;/button></code> and <code>&#x3C;Hello name=\"World\" /></code> are JSX,\nan extension to JavaScript, or a DSL to express DOM elements.\nTypeScript has excellent support for JSX. Thus JSX can be considered as typed HTML template expressions.</p>\n<p>Component names such as <code>Hello</code> begin with an uppercase letter,\nwhile intrinsic HTML elements such as <code>button</code> begin with a lowercase letter.\nCertain attributes in HTML are renamed to resolve conflicts with TypeScript keywords.\nFor example, the <code>class</code> attributes are renamed to <code>className</code> in JSX.</p>\n<p>A component cannot directly return multiple elements.\nTo return multiple elements, nest them inside a <code>div</code> element, then return that <code>div</code>.\nSometimes returning an div element is not possible.\nFor example, nesting multiple <code>&#x3C;td></code> elements in <code>div</code> results in invalid HTML.\nAnd sometimes, you just do not want to wrap them inside a <code>div</code> element.\nUnder such conditions, you can wrap them inside a <code>&#x3C;React.Fragment></code>,\nwhich can be considered as a seamless div element.</p>\n<p><code>&#x3C;React.Fragment></code> accepts an optional <code>key</code> attribute,\nwhich is its only acceptable attribute.\nFor example:</p>\n<pre><code class=\"language-tsx\"><span class=\"pl-c\">// type annotations omitted for brevity</span>\n<span class=\"pl-k\">function</span> <span class=\"pl-en\">Glossary</span>({ <span class=\"pl-v\">items</span> }) {\n  <span class=\"pl-k\">return</span> (\n    &#x3C;<span class=\"pl-ent\">dl</span>>\n      <span class=\"pl-pse\">{</span><span class=\"pl-smi\">items</span>.<span class=\"pl-en\">map</span>(<span class=\"pl-v\">item</span> <span class=\"pl-k\">=></span> (\n        &#x3C;<span class=\"pl-c1\">React.Fragment</span> <span class=\"pl-e\">key</span><span class=\"pl-k\">=</span><span class=\"pl-pse\">{</span><span class=\"pl-smi\">item</span>.<span class=\"pl-c1\">id</span><span class=\"pl-pse\">}</span>>\n          &#x3C;<span class=\"pl-ent\">dt</span>><span class=\"pl-pse\">{</span><span class=\"pl-smi\">item</span>.<span class=\"pl-smi\">term</span><span class=\"pl-pse\">}</span>&#x3C;/<span class=\"pl-ent\">dt</span>>\n          &#x3C;<span class=\"pl-ent\">dd</span>><span class=\"pl-pse\">{</span><span class=\"pl-smi\">item</span>.<span class=\"pl-c1\">description</span><span class=\"pl-pse\">}</span>&#x3C;/<span class=\"pl-ent\">dt</span>>\n        &#x3C;/<span class=\"pl-c1\">React.Fragment</span>>\n      ))<span class=\"pl-pse\">}</span>\n    &#x3C;/<span class=\"pl-ent\">dl</span>>\n  )\n}\n</code></pre>\n<p><code>key</code> is a special attribute for React to identify member element in a list.\nIt helps React to detect which members have changed, added, or removed.</p>\n<p>JSX is syntax sugar for calling <code>React.createElement</code>,\nfor example, <code>&#x3C;Hello name=\"World\" /></code> is equivalent to:</p>\n<pre><code class=\"language-js\"><span class=\"pl-smi\">React</span>.<span class=\"pl-c1\">createElement</span>(Hello, { name<span class=\"pl-k\">:</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>World<span class=\"pl-pds\">\"</span></span> });\n</code></pre>\n<p>So JSX is optional, you can use React without JSX.</p>\n<h2>Styling</h2>\n<p>React does not have an opinion about how styles are defined.\nYou can define styles in separate <code>*.css</code> files.\nHowever, I prefer to define styles in TypeScript than CSS.\nYou can check <a href=\"https://michelebertoli.github.io/css-in-js/\">this comparison of CSS-in-JS</a>.\nAgain, there are a lot of choices.</p>\n<p>Among those projects, I checked the five projects written in TypeScript:</p>\n<ul>\n<li><a href=\"https://github.com/jsxstyle/jsxstyle\">jsxstyle</a> and <a href=\"https://github.com/blakeembrey/react-free-style\">react-free-style</a> are inline style systems. I do not like inline style systems.</li>\n<li><a href=\"https://github.com/streamich/freestyler\">freestyler</a>'s APIs are complex. There are too many choices.</li>\n<li>Both <a href=\"https://stylable.io/\">stylable</a> and <a href=\"https://typestyle.github.io/\">typestyle</a> provide a type safe styling language.</li>\n</ul>\n<p>stylable has a syntax similar to CSS, while typestyle just uses object literals (no custom AST transform).\nAs I said before, I want to define styles <em>in TypeScript</em>, thus I pick typestyle.</p>\n<h2>Alternative Implementations</h2>\n<ol>\n<li>\n<p><a href=\"https://preactjs.com/\">Preact</a> is the most popular alternative implementation.\nIt is small (3KB gzipped) and fast.\nHowever, to leverage many React libraries, <code>preact/compat</code> is required.\nThis compatibility layer is slow.</p>\n</li>\n<li>\n<p><a href=\"https://infernojs.org/\">Inferno</a> is a faster alternative implementation.\nUnlike Preact, it is not that obsessed about the size (but still small).\nLike Preact, its compatibility layer <code>inferno-compat</code> has extra overhead.\nAlso, hooks is <a href=\"https://github.com/infernojs/inferno/issues/1453\">not supported yet</a>.</p>\n</li>\n<li>\n<p><a href=\"https://github.com/NervJS/nerv\">Nerv</a> is yet another small alternative implementation.\nIt features compatibility with IE 8 and a more identical React API.\nThus there is no <code>nerv-compat</code>.</p>\n</li>\n</ol>\n<h2>References</h2>\n<ol>\n<li><a href=\"https://twitter.com/chrisachard/status/1175022111758442497\">Learn React in 10 tweets</a></li>\n<li><a href=\"https://www.netlify.com/blog/2019/03/11/deep-dive-how-do-react-hooks-really-work/\">Deep dive: How do React hooks really work?</a></li>\n</ol>","date_published":"Tue, 07 May 2019 16:38:38 GMT","date_modified":"Tue, 06 Sep 2022 05:05:55 GMT"},{"id":"https://mmap.page/dive-into/cyclejs/","url":"https://mmap.page/dive-into/cyclejs/","title":"Dive into Cycle.js","content_html":"<h1>Dive into Cycle.js</h1>\n<h2>Core Abstraction</h2>\n<p><a href=\"https://cycle.js.org/\">Cycle.js</a> has a simple core abstraction:\nan application is a pure <code>main()</code> function,\nwhose input (<em>sources</em>) and output (<em>sinks</em>) are effects of the external world,\nmanaged by plugins (<em>drivers</em>).</p>\n<p><img src=\"https://cycle.js.org/img/cycle-nested-frontpage.svg\" alt=\"dataflow\" title=\"source: cycle.js.org\"></p>\n<p>The primitives used inside the <code>main</code> function is reactive streams.\nThus Cycle.js applications are entirely <code>this</code> free and have nothing like <code>setState()</code> or <code>update()</code>.</p>\n<p>The separation between function and drivers allows for great extensibility (easy to swap drivers) and testability (easy to test pure functions).</p>\n<p>This abstraction also allows for awesome composablity:\nthe main function of every Cycle.js application is also a reusable function in main function of another Cycle.js application.\nSources and sinks are not only the interface between main function and the drivers, but also the interface between a child component and its parent.</p>\n<p><img src=\"https://cycle.js.org/img/nested-components.svg\" alt=\"nested-components\"></p>\n<h2>Example</h2>\n<p>The core API of Cycle.js is <code>run(main, drivers)</code>.</p>\n<pre><code class=\"language-typescript\"><span class=\"pl-k\">import</span> {<span class=\"pl-smi\">Stream</span>} <span class=\"pl-k\">from</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>xstream<span class=\"pl-pds\">\"</span></span>;\n<span class=\"pl-k\">import</span> {<span class=\"pl-smi\">run</span>} <span class=\"pl-k\">from</span> <span class=\"pl-s\"><span class=\"pl-pds\">'</span>@cycle/run<span class=\"pl-pds\">'</span></span>\n<span class=\"pl-k\">import</span> {<span class=\"pl-smi\">div</span>, <span class=\"pl-smi\">label</span>, <span class=\"pl-smi\">input</span>, <span class=\"pl-smi\">hr</span>, <span class=\"pl-smi\">h1</span>, <span class=\"pl-smi\">makeDOMDriver</span>, <span class=\"pl-smi\">DOMSource</span>, <span class=\"pl-smi\">VNode</span>} <span class=\"pl-k\">from</span> <span class=\"pl-s\"><span class=\"pl-pds\">'</span>@cycle/dom<span class=\"pl-pds\">'</span></span>\n\n<span class=\"pl-k\">interface</span> <span class=\"pl-en\">Sources</span> {\n  <span class=\"pl-v\">Dom</span><span class=\"pl-k\">:</span> <span class=\"pl-en\">DOMSource</span>\n}\n\n<span class=\"pl-k\">interface</span> <span class=\"pl-en\">Sinks</span> {\n  <span class=\"pl-v\">Dom</span><span class=\"pl-k\">:</span> <span class=\"pl-en\">Stream</span>&#x3C;<span class=\"pl-en\">VNode</span>>\n}\n\n\n<span class=\"pl-k\">function</span> <span class=\"pl-en\">main</span>(<span class=\"pl-v\">sources</span><span class=\"pl-k\">:</span> <span class=\"pl-en\">Sources</span>)<span class=\"pl-k\">:</span> <span class=\"pl-en\">Sinks</span> {\n  <span class=\"pl-k\">const</span> <span class=\"pl-c1\">input$</span> <span class=\"pl-k\">=</span> <span class=\"pl-smi\">sources</span>.<span class=\"pl-smi\">Dom</span>.<span class=\"pl-c1\">select</span>(<span class=\"pl-s\"><span class=\"pl-pds\">'</span>.field<span class=\"pl-pds\">'</span></span>).<span class=\"pl-en\">events</span>(<span class=\"pl-s\"><span class=\"pl-pds\">'</span>input<span class=\"pl-pds\">'</span></span>)\n\n  <span class=\"pl-k\">const</span> <span class=\"pl-c1\">name$</span> <span class=\"pl-k\">=</span> <span class=\"pl-smi\">input$</span>.<span class=\"pl-en\">map</span>(<span class=\"pl-v\">ev</span> <span class=\"pl-k\">=></span> (<span class=\"pl-smi\">ev</span>.<span class=\"pl-c1\">target</span> <span class=\"pl-k\">as</span> <span class=\"pl-en\">HTMLInputElement</span>).<span class=\"pl-c1\">value</span>).<span class=\"pl-en\">startWith</span>(<span class=\"pl-s\"><span class=\"pl-pds\">''</span></span>)\n\n  <span class=\"pl-k\">const</span> <span class=\"pl-c1\">vdom$</span> <span class=\"pl-k\">=</span> <span class=\"pl-smi\">name$</span>.<span class=\"pl-en\">map</span>(<span class=\"pl-v\">name</span> <span class=\"pl-k\">=></span>\n    <span class=\"pl-en\">div</span>([\n      <span class=\"pl-en\">label</span>(<span class=\"pl-s\"><span class=\"pl-pds\">'</span>Name:<span class=\"pl-pds\">'</span></span>),\n      <span class=\"pl-en\">input</span>(<span class=\"pl-s\"><span class=\"pl-pds\">'</span>.field<span class=\"pl-pds\">'</span></span>, {attrs: {type: <span class=\"pl-s\"><span class=\"pl-pds\">'</span>text<span class=\"pl-pds\">'</span></span>}}),\n      <span class=\"pl-en\">hr</span>(),\n      <span class=\"pl-en\">h1</span>(<span class=\"pl-s\"><span class=\"pl-pds\">`</span>Hello ${<span class=\"pl-smi\">name</span>}<span class=\"pl-pds\">`</span></span>),\n    ])\n  )\n\n  <span class=\"pl-k\">return</span> { Dom: <span class=\"pl-smi\">vdom$</span> }\n}\n\n<span class=\"pl-en\">run</span>(<span class=\"pl-smi\">main</span>, { Dom: <span class=\"pl-en\">makeDOMDriver</span>(<span class=\"pl-s\"><span class=\"pl-pds\">'</span>#app-container<span class=\"pl-pds\">'</span></span>) })\n</code></pre>\n<p>The above code is adapted from the JavaScript hello world sample on the frontpage of  <a href=\"https://cycle.js.org/\">Cycle.js</a> official website. I use TypeScript instead.</p>","date_published":"Sun, 17 Mar 2019 18:51:51 GMT","date_modified":"Sun, 24 May 2020 13:58:17 GMT"},{"id":"https://mmap.page/dive-into/tinygo/","url":"https://mmap.page/dive-into/tinygo/","title":"Tinygo","content_html":"<h1>Tinygo</h1>\n<p><strong>This short introduction is outdated and unmaintained.</strong>\nPlease refer to the <a href=\"https://tinygo.org/\">official TinyGo documentation</a> instead.</p>\n<p><a href=\"https://tinygo.org/\">Tinygo</a> is a Go compiler for microcontrollers and WebAssembly.\nIt also supports x86 32 bit and 64 bit Linux.</p>\n<h2>Getting Started</h2>\n<h3>Install</h3>\n<pre><code class=\"language-sh\">sudo apt install llvm-7-dev libclang-7-dev\ngo get -u github.com/tinygo-org/tinygo\n</code></pre>\n<h3>Usage</h3>\n<p>To compile a Linux executable:</p>\n<pre><code class=\"language-sh\">tinygo build -o hello_tiny hello.go\n</code></pre>\n<p>The output size of a hello world program is very impressive to me:</p>\n<pre><code class=\"language-sh\">1.1M    hello\n12K     hello_tiny\n</code></pre>\n<p>Or run it directly:</p>\n<pre><code class=\"language-sh\">tinygo run hello.go\n</code></pre>\n<h2>Go Language Features</h2>\n<p>Not supported:</p>\n<ul>\n<li>Maps.</li>\n<li>Concurrency.</li>\n<li>Reflection.</li>\n<li>Cgo.</li>\n<li>Many parts of standard library (due to the above missing pieces).</li>\n<li><code>recover()</code></li>\n<li><code>complex64</code>, <code>complex128</code>, and arithmetic on complex numbers.</li>\n<li><code>defer</code> a call on a function pointer.</li>\n<li>3-index slicing, e.g. <code>slice = array[2:4:7]</code>.</li>\n</ul>","date_published":"Sat, 02 Mar 2019 04:35:01 GMT","date_modified":"Mon, 05 Sep 2022 10:56:44 GMT"},{"id":"https://mmap.page/dive-into/gitmoji/","url":"https://mmap.page/dive-into/gitmoji/","title":"Selected Gitmojis","content_html":"<h1>Selected Gitmojis</h1>\n<h2>Summary</h2>\n<table>\n<thead>\n<tr>\n<th>emoji</th>\n<th>code</th>\n<th>usage</th>\n<th>Angular Convention</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>🐛</td>\n<td><code>:bug:</code></td>\n<td>bug fix</td>\n<td>fix</td>\n</tr>\n<tr>\n<td>🆕</td>\n<td><code>:new:</code></td>\n<td>new feature</td>\n<td>feat</td>\n</tr>\n<tr>\n<td>🔥</td>\n<td><code>:fire:</code></td>\n<td>remove feature</td>\n<td>n/a</td>\n</tr>\n<tr>\n<td>💥</td>\n<td><code>:boom:</code></td>\n<td>breaking changes</td>\n<td>n/a</td>\n</tr>\n<tr>\n<td>🔒</td>\n<td><code>:lock:</code></td>\n<td>security fix</td>\n<td>n/a</td>\n</tr>\n<tr>\n<td>🎨</td>\n<td><code>:art:</code></td>\n<td>refactor</td>\n<td>refactor</td>\n</tr>\n<tr>\n<td>⚡️</td>\n<td><code>:zap:</code></td>\n<td>performance</td>\n<td>perf</td>\n</tr>\n<tr>\n<td>💯</td>\n<td><code>:100:</code></td>\n<td>test</td>\n<td>test</td>\n</tr>\n<tr>\n<td>📝</td>\n<td><code>:memo:</code></td>\n<td>doc</td>\n<td>docs</td>\n</tr>\n<tr>\n<td>💤</td>\n<td><code>:zzz:</code></td>\n<td>chore</td>\n<td>chore</td>\n</tr>\n<tr>\n<td>🎉</td>\n<td><code>:tada:</code></td>\n<td>release</td>\n<td>n/a</td>\n</tr>\n<tr>\n<td>💩</td>\n<td><code>:poop:</code></td>\n<td>dirty</td>\n<td>n/a</td>\n</tr>\n<tr>\n<td>🥚</td>\n<td><code>:egg:</code></td>\n<td>Easter eggs</td>\n<td>n/a</td>\n</tr>\n</tbody>\n</table>\n<h2>Features</h2>\n<ul>\n<li>\n<p>Only 13 types.</p>\n<p>Do not need to open gitmoji.dev in the browser before writing a commit message.</p>\n</li>\n<li>\n<p>Only use emojis with a short emoji code (less than five characters).</p>\n<p>Commit message title is recommended to be less than 50 characters.</p>\n</li>\n<li>\n<p>Most emojis have corresponding types in Angular convention.</p>\n</li>\n<li>\n<p>Looks good and comprehensible in plain text.</p>\n<p>Friendlier for infancy terminals and acceptable (I hope) for emoji haters.</p>\n</li>\n</ul>\n<h2>Intersection between gitmoji and Atom style guide</h2>\n<ul>\n<li>🎨 <code>:art:</code> when improving the format/structure of the code</li>\n<li>📝 <code>:memo:</code> when writing docs</li>\n<li>🐧 <code>:penguin:</code> when fixing something on Linux</li>\n<li>🍎 <code>:apple:</code> when fixing something on macOS</li>\n<li>🏁 <code>:checkered_flag:</code> when fixing something on Windows</li>\n<li>🐛 <code>:bug:</code> when fixing a bug</li>\n<li>🔥 <code>:fire:</code> when removing code or files</li>\n<li>💚 <code>:green_heart:</code> when fixing the CI build</li>\n<li>✅ <code>:white_check_mark:</code> when adding tests</li>\n<li>🔒 <code>:lock:</code> when dealing with security</li>\n<li>⬆️ <code>:arrow_up:</code> when upgrading dependencies</li>\n<li>⬇️ <code>:arrow_down:</code> when downgrading dependencies</li>\n</ul>\n<h2>Conflicts between gitmoji and Atom style guide</h2>\n<table>\n<thead>\n<tr>\n<th>Meaning</th>\n<th>gitmoji</th>\n<th>Atom</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Performance</td>\n<td>⚡️</td>\n<td>🐎</td>\n</tr>\n<tr>\n<td>Removing linter warnings</td>\n<td>🚨</td>\n<td>👕</td>\n</tr>\n</tbody>\n</table>\n<h2>Comparison with Angular Convention</h2>\n<table>\n<thead>\n<tr>\n<th><a href=\"https://github.com/angular/angular.js/blob/master/DEVELOPERS.md#type\">Angular</a></th>\n<th>gitmoji</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>feat</td>\n<td>✨</td>\n</tr>\n<tr>\n<td>fix</td>\n<td>🐛</td>\n</tr>\n<tr>\n<td>docs</td>\n<td>📝</td>\n</tr>\n<tr>\n<td>style</td>\n<td>🎨</td>\n</tr>\n<tr>\n<td>refactor</td>\n<td>♻️</td>\n</tr>\n<tr>\n<td>perf</td>\n<td>⚡️</td>\n</tr>\n<tr>\n<td>test</td>\n<td>✅</td>\n</tr>\n<tr>\n<td>chore</td>\n<td>🚀 (deploy)　or 💚 (CI)</td>\n</tr>\n</tbody>\n</table>\n<h2>A reduced list of gitmoji</h2>\n<p>From the intersection, remove the following emojis:</p>\n<ul>\n<li>\n<p>Too long:</p>\n<p>:penguin:, :checkered_flag:, :green_heart:, :white_check_mark:, :arrow_up:, :arrow_down:</p>\n</li>\n<li>\n<p>Ambiguous:</p>\n<ul>\n<li>:green_heart:, I don't know why this is related to CI.</li>\n<li>:arrow_up:, this could mean \"bump version\".</li>\n<li>:arrow_down:, this could mean \"regression\".</li>\n</ul>\n</li>\n<li>\n<p>Other:</p>\n<p>:apple:, since both :penguin: and :checkered_flag: have been removed.</p>\n</li>\n</ul>\n<p>And add the following:</p>\n<ul>\n<li>⚡️ <code>:zap:</code> for performance from gitmoji.</li>\n<li>🆕 <code>:new:</code> for new features. I saw someone used this.</li>\n<li>💯 <code>:100:</code> for tests, aiming at 100% branch coverage.</li>\n<li>💤 <code>:zzz:</code> for chores. I think changes of this type is somehow boring.</li>\n<li>💥 <code>:boom:</code> for breaking changes from gitmoji.</li>\n<li>🎉 <code>:tada:</code> for new release. Gitmoji uses this for project begin and 🔖 <code>:bookmark</code> for release.</li>\n<li>💩 <code>:poop:</code> for dirty hacks and twisted workarounds from gitmoji (\"Write bad code that needs to be improved.\").</li>\n<li>🥚 <code>:egg:</code> for Easter eggs from gitmoji.</li>\n</ul>\n<p>Thus, the final list is:</p>\n<ul>\n<li>🎨 <code>:art:</code> when improving the format/structure of the code</li>\n<li>🐛 <code>:bug:</code> when fixing a bug</li>\n<li>🔥 <code>:fire:</code> when removing code or files</li>\n<li>📝 <code>:memo:</code> when writing docs</li>\n<li>🆕 <code>:new:</code> when adding a new feature</li>\n<li>🔒 <code>:lock:</code> when fixing security problems</li>\n<li>⚡️ <code>:zap:</code> when improving performance</li>\n</ul>\n<ul>\n<li>💯 <code>:100:</code> when adding or updating tests.</li>\n</ul>\n<ul>\n<li>💤 <code>:zzz:</code> for chores. I think changes of this type is somehow boring.</li>\n<li>💥 <code>:boom:</code> when introducing breaking changes.</li>\n<li>🎉 <code>:tada:</code> when releasing a new version.</li>\n<li>💩 <code>:poop:</code> when committing dirty hacks and twisted workarounds</li>\n<li>🥚 <code>:egg:</code> when adding or updating an Easter egg.</li>\n</ul>\n<p>Compared to Angular Convention, I removed the following types:</p>\n<ul>\n<li><code>style</code>: White-space, formatting etc. are unimportant. And most of the time, they do not deserve a separate commit.</li>\n</ul>\n<p>I added the following types:</p>\n<ul>\n<li>A security issue (<code>:lock:</code>) is a special kind of bug (<code>:bug:</code>). It is so important that I use a different emoji.</li>\n<li>Removing a feature (<code>:fire:</code>) belongs to <code>refactor</code> by Angular Convention's definition: \"A code change that neither fixes a bug nor adds a feature\". However, it makes sense to assume a refactor does not introduce a breaking change of API, while removing a feature always break the API.</li>\n<li>Breaking changes (<code>:boom:</code>) may have serious effects thus deserve a dedicated emoji.</li>\n<li>Some projects have a change log file in the repository. Thus, a commit preparing a release typically starts with <code>:memo:</code>. However, some projects do not maintain a change log file in the repository, but use the annotations of git tags. Then a commit preparing a release typically only involve things such as updating some version strings. Therefore, an extra emoji (<code>:tada:</code>) is added.</li>\n<li><code>:poop:</code> is similar to <code>:boom:</code>, asking for special attention. These commits may be squashed or rebased on merging, if a <em>clean</em> history is preferred.</li>\n<li><code>:egg:</code> itself can be considered as an Easter egg of gitmoji.</li>\n</ul>\n<h2>Change Log</h2>\n<h3>0.1.0</h3>\n<ul>\n<li>\n<p>Use <code>:100:</code> for tests. <code>:mag:</code> should be considered as an alias of <code>:100:</code>.</p>\n<p>When displayed in plain text, <code>:mag:</code>,\nI think it is hard to recognize \"mag\" is an abbreviation for \"magnifier\".\nOn the other hands, I ensure all tests are passed in pre commit hook.\nThus, most of the time, changes on tests come with changes in other types,\ne.g. <code>:bug:</code> or <code>:new:</code>.\nTest only changes thus are most likely improve test coverage.\nTherefore, I replace <code>:mag:</code> with <code>:100:</code>.</p>\n<p>Any tools supporting this selected gitmoji set\nshould treat <code>:mag:</code> as an alias of <code>:100:</code>,\nto maintain backward compatibility.</p>\n</li>\n</ul>\n<h3>0.0.2022</h3>\n<p>The following new emojis are added:</p>\n<ul>\n<li>\n<p><code>:mag:</code> for tests, and <code>:zzz:</code> for chores.</p>\n<p>I used to think that tests and build process are part of code logic.\nHowever, when reviewing changes, separation is a good thing.</p>\n</li>\n<li>\n<p><code>:boom:</code> for breaking changes, and <code>:tada:</code> for releases.</p>\n</li>\n<li>\n<p><code>:poop:</code> for dirtiness and <code>:egg:</code> for Easter eggs.</p>\n</li>\n</ul>\n<h3>0.0.0</h3>\n<p>The initial version.</p>","date_published":"Sat, 02 Feb 2019 07:14:45 GMT","date_modified":"Wed, 24 Jan 2024 14:32:48 GMT"},{"id":"https://mmap.page/dive-into/typescript/","url":"https://mmap.page/dive-into/typescript/","title":"Notes on TypeScript","content_html":"<h1>Notes on TypeScript</h1>\n<h2>Top and Bottom Types</h2>\n<p>Unlike <code>Anything</code> or <code>Any</code> in most static typed languages,\n<code>any</code> supports the same operations as a value in JavaScript\nand minimal static type checking is performed.\nTypeScript's <code>unknown</code> is more similar to <code>Any</code> (top type) in other languages.</p>\n<p>TypeScript's bottom type is <code>never</code>, which is called <code>Nothing</code> in some languages.</p>\n<pre><code class=\"language-ts\"><span class=\"pl-k\">const</span> <span class=\"pl-en\">verifyCasesAreExhaustive</span> <span class=\"pl-k\">=</span> (<span class=\"pl-v\">kind</span><span class=\"pl-k\">:</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>x<span class=\"pl-pds\">\"</span></span> <span class=\"pl-k\">|</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>y<span class=\"pl-pds\">\"</span></span> <span class=\"pl-k\">|</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>z<span class=\"pl-pds\">\"</span></span>) <span class=\"pl-k\">=></span> {\n<span class=\"pl-k\">switch</span> (<span class=\"pl-smi\">kind</span>) {\n    <span class=\"pl-k\">case</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>x<span class=\"pl-pds\">\"</span></span>:\n        <span class=\"pl-k\">return</span> <span class=\"pl-c1\">1</span>\n    <span class=\"pl-k\">case</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>y<span class=\"pl-pds\">\"</span></span>:\n        <span class=\"pl-k\">return</span> <span class=\"pl-c1\">2</span>\n    <span class=\"pl-k\">case</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>z<span class=\"pl-pds\">\"</span></span>:\n        <span class=\"pl-k\">return</span> <span class=\"pl-c1\">3</span>\n    <span class=\"pl-k\">default</span>:\n        <span class=\"pl-k\">const</span> <span class=\"pl-c1\">nothing</span><span class=\"pl-k\">:</span> <span class=\"pl-c1\">never</span> <span class=\"pl-k\">=</span> <span class=\"pl-smi\">kind</span>\n        <span class=\"pl-k\">throw</span>(<span class=\"pl-smi\">nothing</span>)\n}\n}\n</code></pre>\n<h2>Function Overloads</h2>\n<p>Considering the following definition:</p>\n<pre><code class=\"language-typescript\"><span class=\"pl-k\">function</span> <span class=\"pl-en\">plus</span>(<span class=\"pl-v\">x</span><span class=\"pl-k\">:</span> <span class=\"pl-c1\">number</span>, <span class=\"pl-v\">y</span><span class=\"pl-k\">:</span> <span class=\"pl-c1\">0</span>)<span class=\"pl-k\">:</span> <span class=\"pl-c1\">boolean</span>;\n<span class=\"pl-k\">function</span> <span class=\"pl-en\">plus</span>(<span class=\"pl-v\">x</span><span class=\"pl-k\">:</span> <span class=\"pl-c1\">number</span>, <span class=\"pl-v\">y</span><span class=\"pl-k\">:</span> <span class=\"pl-c1\">number</span>)<span class=\"pl-k\">:</span> <span class=\"pl-c1\">number</span>;\n<span class=\"pl-k\">function</span> <span class=\"pl-en\">plus</span>(<span class=\"pl-v\">x</span><span class=\"pl-k\">:</span> <span class=\"pl-c1\">string</span>, <span class=\"pl-v\">y</span><span class=\"pl-k\">:</span> <span class=\"pl-c1\">string</span>)<span class=\"pl-k\">:</span> <span class=\"pl-c1\">string</span>;\n<span class=\"pl-c\">// function plus(x: number, y: string): boolean;</span>\n<span class=\"pl-c\">// function plus(x: string, y: number): boolean;</span>\n<span class=\"pl-k\">function</span> <span class=\"pl-en\">plus</span>(<span class=\"pl-v\">x</span><span class=\"pl-k\">:</span> <span class=\"pl-c1\">number</span> <span class=\"pl-k\">|</span> <span class=\"pl-c1\">string</span>, <span class=\"pl-v\">y</span><span class=\"pl-k\">:</span> <span class=\"pl-c1\">number</span> <span class=\"pl-k\">|</span> <span class=\"pl-c1\">string</span>)<span class=\"pl-k\">:</span> <span class=\"pl-c1\">number</span> <span class=\"pl-k\">|</span> <span class=\"pl-c1\">string</span> <span class=\"pl-k\">|</span> <span class=\"pl-c1\">boolean</span> {\n    <span class=\"pl-k\">if</span> (<span class=\"pl-k\">typeof</span> <span class=\"pl-smi\">x</span> <span class=\"pl-k\">==</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>number<span class=\"pl-pds\">\"</span></span> <span class=\"pl-k\">&#x26;&#x26;</span> <span class=\"pl-k\">typeof</span> <span class=\"pl-smi\">y</span> <span class=\"pl-k\">==</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>number<span class=\"pl-pds\">\"</span></span>) {\n        <span class=\"pl-k\">if</span> (<span class=\"pl-smi\">y</span> <span class=\"pl-k\">===</span> <span class=\"pl-c1\">0</span>) {\n            <span class=\"pl-k\">return</span> <span class=\"pl-c1\">false</span>\n        } <span class=\"pl-k\">else</span> {\n        <span class=\"pl-k\">return</span> <span class=\"pl-smi\">x</span> <span class=\"pl-k\">+</span> <span class=\"pl-smi\">y</span>;\n        } \n    } <span class=\"pl-k\">else</span> <span class=\"pl-k\">if</span> (<span class=\"pl-k\">typeof</span> <span class=\"pl-smi\">x</span> <span class=\"pl-k\">==</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>string<span class=\"pl-pds\">\"</span></span> <span class=\"pl-k\">&#x26;&#x26;</span> <span class=\"pl-k\">typeof</span> <span class=\"pl-smi\">y</span> <span class=\"pl-k\">==</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>string<span class=\"pl-pds\">\"</span></span>) {\n        <span class=\"pl-k\">return</span> <span class=\"pl-s\"><span class=\"pl-pds\">`</span>${<span class=\"pl-smi\">x</span>}${<span class=\"pl-smi\">y</span>}<span class=\"pl-pds\">`</span></span>; <span class=\"pl-c\">// equivalent to `x + y`.</span>\n    } <span class=\"pl-k\">else</span> {\n        <span class=\"pl-k\">return</span> <span class=\"pl-c1\">false</span>;\n    }\n}\n\n<span class=\"pl-smi\">In</span> <span class=\"pl-smi\">early</span> <span class=\"pl-smi\">versions</span> <span class=\"pl-k\">of</span> <span class=\"pl-en\">TypeScript</span> (<span class=\"pl-smi\">e</span>.<span class=\"pl-smi\">g</span>. [<span class=\"pl-smi\">v3</span>.<span class=\"pl-c1\">5.1</span>]),\n<span class=\"pl-smi\">the</span> <span class=\"pl-smi\">following</span> <span class=\"pl-smi\">code</span> <span class=\"pl-smi\">gives</span> <span class=\"pl-smi\">misleading</span> <span class=\"pl-smi\">error</span> <span class=\"pl-en\">information</span>:\n\n<span class=\"pl-s\"><span class=\"pl-pds\">```</span>typescript</span>\n<span class=\"pl-s\">plus(\"1\", 0)</span>\n<span class=\"pl-s\">// error: Argument of type '0' is not assignable to parameter of type 'string'.</span>\n</code></pre>\n<p>Readers may wonder why TypeScript does not match <code>(\"1\", 0)</code> against <code>plus(x: number | string, y: number | string)</code>.</p>\n<p>However, recent versions of TypeScript (e.g. <a href=\"https://www.typescriptlang.org/play?ts=5.3.2#code/GYVwdgxgLglg9mABABwDYgM4AoAeAuRMEAWwCMBTAJwBpEBPAgBgEoDS45VyBDMAbgBQoSLAQp02fIRIUa9AkTJVW0pZUHDo8JGky4CGKJRhgA5rQaJDxsyusnTggPRPEm0Ton7VsiwaMOKuycPPwCLm7gWmK6kv425vI+ymwcXLwaUR7ielKKsogAPlYBZn7JlEUlCSr5VFX2ZlXB6UgA3gKIXYgwwIhYUHTI5HB9OIgAvBOIAER1lDOIAGRLiIPDo-ST03MyVDPMiB3dJz19WHTb0yxHnaf3lORQIJRIwNyoGOR39wC+iORPuRbvcuo9nq9EOMANT0QSgxD-H6IgFAs79dYjMbbWaNUyLFZrIZYrZTXGlfGHY6g8EvJAAAwAJG0cL9mXRfvS+IgIuQAI4gGAANw+5DAUDWcEQ9Jh9HpADpkf9AV8QTSnnS3B8vvDur8BPqBLEsDMAIwzWgsIA\">v5.3.2</a>) provides clearer message:</p>\n<pre><code class=\"language-typescript\"><span class=\"pl-en\">plus</span>(<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>1<span class=\"pl-pds\">\"</span></span>, <span class=\"pl-c1\">0</span>)\n<span class=\"pl-c\">// The call would have succeeded against this implementation,</span>\n<span class=\"pl-c\">// but implementation signatures of overloads are not externally visible</span>\n</code></pre>\n<h2>Type Equality</h2>\n<p>With TypeScript's conditional types, testing type equality is intuitive:</p>\n<pre><code class=\"language-ts\"><span class=\"pl-k\">type</span> <span class=\"pl-en\">EqEq</span>&#x3C;<span class=\"pl-en\">T</span>, <span class=\"pl-en\">S</span>> <span class=\"pl-k\">=</span> [<span class=\"pl-en\">T</span>] <span class=\"pl-k\">extends</span> [<span class=\"pl-en\">S</span>] <span class=\"pl-k\">?</span> ([<span class=\"pl-en\">S</span>] <span class=\"pl-k\">extends</span> [<span class=\"pl-en\">T</span>] <span class=\"pl-k\">?</span> <span class=\"pl-c1\">true</span> <span class=\"pl-k\">:</span> <span class=\"pl-c1\">false</span>) <span class=\"pl-k\">:</span> <span class=\"pl-c1\">false</span>\n\n<span class=\"pl-k\">type</span> <span class=\"pl-en\">FunctionOverloadsEquality</span> <span class=\"pl-k\">=</span> <span class=\"pl-en\">EqEq</span>&#x3C;\n    { (<span class=\"pl-v\">x</span><span class=\"pl-k\">:</span> <span class=\"pl-c1\">0</span>, <span class=\"pl-v\">y</span><span class=\"pl-k\">:</span> <span class=\"pl-c1\">null</span>)<span class=\"pl-k\">:</span> <span class=\"pl-c1\">void</span>; (<span class=\"pl-v\">x</span><span class=\"pl-k\">:</span> <span class=\"pl-c1\">number</span>, <span class=\"pl-v\">y</span><span class=\"pl-k\">:</span> <span class=\"pl-c1\">null</span>)<span class=\"pl-k\">:</span> <span class=\"pl-c1\">void</span> },\n    { (<span class=\"pl-v\">x</span><span class=\"pl-k\">:</span> <span class=\"pl-c1\">number</span>, <span class=\"pl-v\">y</span><span class=\"pl-k\">:</span> <span class=\"pl-c1\">null</span>)<span class=\"pl-k\">:</span> <span class=\"pl-c1\">void</span>; (<span class=\"pl-v\">x</span><span class=\"pl-k\">:</span> <span class=\"pl-c1\">0</span>, <span class=\"pl-v\">y</span><span class=\"pl-k\">:</span> <span class=\"pl-c1\">null</span>)<span class=\"pl-k\">:</span> <span class=\"pl-c1\">void</span> }> <span class=\"pl-c\">// true</span>\n\n<span class=\"pl-k\">type</span> <span class=\"pl-en\">F</span> <span class=\"pl-k\">=</span> (<span class=\"pl-v\">x</span><span class=\"pl-k\">:</span> <span class=\"pl-c1\">0</span>, <span class=\"pl-v\">y</span><span class=\"pl-k\">:</span> <span class=\"pl-c1\">null</span>) <span class=\"pl-k\">=></span> <span class=\"pl-c1\">void</span>\n<span class=\"pl-k\">type</span> <span class=\"pl-en\">G</span> <span class=\"pl-k\">=</span> (<span class=\"pl-v\">x</span><span class=\"pl-k\">:</span> <span class=\"pl-c1\">number</span>, <span class=\"pl-v\">y</span><span class=\"pl-k\">:</span> <span class=\"pl-c1\">string</span>) <span class=\"pl-k\">=></span> <span class=\"pl-c1\">void</span>\n<span class=\"pl-k\">type</span> <span class=\"pl-en\">FunctionIntersectionEquality</span> <span class=\"pl-k\">=</span> <span class=\"pl-en\">EqEq</span>&#x3C;<span class=\"pl-en\">F</span> <span class=\"pl-k\">&#x26;</span> <span class=\"pl-en\">G</span>, <span class=\"pl-en\">G</span> <span class=\"pl-k\">&#x26;</span> <span class=\"pl-en\">F</span>> <span class=\"pl-c\">// true</span>\n</code></pre>\n<h2>The Crazy <code>satisfies</code> Operator</h2>\n<p>Below is the example given in <a href=\"https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-9.html#the-satisfies-operator\">What's New in TypeScript 4.9</a>:</p>\n<pre><code class=\"language-ts\"><span class=\"pl-k\">type</span> <span class=\"pl-en\">Colors</span> <span class=\"pl-k\">=</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>red<span class=\"pl-pds\">\"</span></span> <span class=\"pl-k\">|</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>green<span class=\"pl-pds\">\"</span></span> <span class=\"pl-k\">|</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>blue<span class=\"pl-pds\">\"</span></span>;\n<span class=\"pl-k\">type</span> <span class=\"pl-en\">RGB</span> <span class=\"pl-k\">=</span> [<span class=\"pl-en\">red</span>: <span class=\"pl-c1\">number</span>, <span class=\"pl-en\">green</span>: <span class=\"pl-c1\">number</span>, <span class=\"pl-en\">blue</span>: <span class=\"pl-c1\">number</span>];\n<span class=\"pl-k\">const</span> <span class=\"pl-c1\">palette</span> <span class=\"pl-k\">=</span> {\n    red: [<span class=\"pl-c1\">255</span>, <span class=\"pl-c1\">0</span>, <span class=\"pl-c1\">0</span>],\n    green: <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>#00ff00<span class=\"pl-pds\">\"</span></span>,\n    bleu: [<span class=\"pl-c1\">0</span>, <span class=\"pl-c1\">0</span>, <span class=\"pl-c1\">255</span>]\n<span class=\"pl-c\">//  ~~~~ The typo is now caught!</span>\n} <span class=\"pl-k\">satisfies</span> <span class=\"pl-en\">Record</span>&#x3C;<span class=\"pl-en\">Colors</span>, <span class=\"pl-c1\">string</span> <span class=\"pl-k\">|</span> <span class=\"pl-en\">RGB</span>>;\n<span class=\"pl-c\">// Both of these methods are still accessible!</span>\n<span class=\"pl-k\">const</span> <span class=\"pl-c1\">redComponent</span> <span class=\"pl-k\">=</span> <span class=\"pl-smi\">palette</span>.<span class=\"pl-smi\">red</span>.<span class=\"pl-en\">at</span>(<span class=\"pl-c1\">0</span>);\n<span class=\"pl-k\">const</span> <span class=\"pl-c1\">greenNormalized</span> <span class=\"pl-k\">=</span> <span class=\"pl-smi\">palette</span>.<span class=\"pl-smi\">green</span>.<span class=\"pl-c1\">toUpperCase</span>();\n</code></pre>\n<p>IMHO, this shows the craziness of TypeScript.\nWhy <code>green</code> is encoded as hex string but <code>red</code> and <code>blue</code> are encoded as RGB arrays?\nWhat if one day someone refactors the code and change <code>green</code> to an RGB array?\nAnd in real world application, I would rather make all colors encoded as hex strings or RGB arrays,\nbut not a mix of them.\nThen the <code>getComponent</code> or <code>displayHex</code> will be implemented assuming input is either a hex string or an RGB array.</p>","date_published":"Sun, 13 Jan 2019 08:52:16 GMT","date_modified":"Mon, 18 Dec 2023 18:37:33 GMT"},{"id":"https://mmap.page/thoughts/","url":"https://mmap.page/thoughts/","title":"Thoughts","content_html":"<h1>Thoughts</h1>\n<p>Some random thoughts.</p>","date_published":"Thu, 06 Dec 2018 08:01:12 GMT","date_modified":"Tue, 25 Apr 2023 08:48:15 GMT"},{"id":"https://mmap.page/thoughts/express-more-in-code/","url":"https://mmap.page/thoughts/express-more-in-code/","title":"Express more in code","content_html":"<h1>Express more in code</h1>\n<p>Code tends to be clearer and more precise.</p>\n<h2>Math formula</h2>\n<p>The traditional math language has a lot of issues:</p>\n<ul>\n<li>Variables may be used before or without declaration.</li>\n<li>Variables do not have scoping.</li>\n<li>Prone to typos and untestable.</li>\n</ul>\n<p>Instead of writing <code>E = mc^2</code>, I'd rather just write <code>e = m * (c ** 2)</code>.</p>\n<h2>Tables</h2>\n<p>Most tables can be converted to code in a clear way. For example:</p>\n<table>\n<thead>\n<tr>\n<th>Strength</th>\n<th>Dexterity</th>\n<th>Constitution</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>9 (-1)</td>\n<td>11 (+0)</td>\n<td>10 (+0)</td>\n</tr>\n</tbody>\n</table>\n<p>Via direct variable declaration:</p>\n<pre><code class=\"language-c\">strength = <span class=\"pl-c1\">9</span>;\nstrength_modifier = -<span class=\"pl-c1\">1</span>;\ndexterity = <span class=\"pl-c1\">11</span>;\ndexterity_modifier = <span class=\"pl-c1\">0</span>;\nconstitution = <span class=\"pl-c1\">10</span>;\nconstitutito_modifier = <span class=\"pl-c1\">0</span>;\n</code></pre>\n<p>Or via a data structure:</p>\n<pre><code class=\"language-ceylon\"><span class=\"pl-k\">class</span> <span class=\"pl-en\">AbilityScore</span>(<span class=\"pl-en\">Integer</span> <span class=\"pl-smi\">score</span>) {\n  <span class=\"pl-k\">assert</span>(<span class=\"pl-smi\">score</span> >= <span class=\"pl-c1\">1</span> &#x26;&#x26; <span class=\"pl-smi\">score</span> &#x3C;= <span class=\"pl-c1\">30</span>);\n  <span class=\"pl-k\">shared</span> <span class=\"pl-en\">Integer</span> <span class=\"pl-smi\">modifier</span> => <span class=\"pl-smi\">floor</span>((<span class=\"pl-smi\">score</span> - <span class=\"pl-c1\">10</span>) / <span class=\"pl-c1\">2.0</span>).<span class=\"pl-smi\">integer</span>;\n}\n<span class=\"pl-k\">value</span> <span class=\"pl-smi\">strength</span> = <span class=\"pl-en\">AbilityScore</span>(<span class=\"pl-c1\">9</span>);\n<span class=\"pl-k\">value</span> <span class=\"pl-smi\">dexterity</span> = <span class=\"pl-en\">AbilityScore</span>(<span class=\"pl-c1\">11</span>);\n<span class=\"pl-k\">value</span> <span class=\"pl-smi\">constitution</span> = <span class=\"pl-en\">AbilityScore</span>(<span class=\"pl-c1\">10</span>);\n</code></pre>\n<p>In fact, the later form reveals the relationship between ability and modifier.</p>\n<h2>Choices of language</h2>\n<p>A lot of programming languages suffer from design flaws or lack of ecosystem,\nbut usually these issues do not affect brief code samples.\nThus, most languages are fine.</p>\n<p>If a language with C like syntax is chosen,\nthen it is recommended to use the Java style (opening braces on same line)\nand an indent level of 2 spaces.\nThis saves space and does not harm readability for brief code samples.</p>\n<p>The most popular choice seems Python,\nwhich is the most used language in the <a href=\"https://jupyter.org/\">Jupyter</a> ecosystem.</p>","date_published":"Thu, 06 Dec 2018 00:53:57 GMT","date_modified":"Mon, 05 Sep 2022 14:05:34 GMT"},{"id":"https://mmap.page/dive-into/kotlin/","url":"https://mmap.page/dive-into/kotlin/","title":"On Design of Kotlin","content_html":"<h1>On Design of Kotlin</h1>\n<h2>Good parts</h2>\n<h3>Assignments are not expressions</h3>\n<pre><code class=\"language-kotlin\"><span class=\"pl-k\">if</span> (a <span class=\"pl-k\">=</span> <span class=\"pl-c1\">1</span>) { <span class=\"pl-c1\">println</span>(<span class=\"pl-c1\">2</span>) }\nerror<span class=\"pl-k\">:</span> assignments are <span class=\"pl-k\">not</span> expressions, <span class=\"pl-k\">and</span> only expressions are allowed <span class=\"pl-k\">in</span> <span class=\"pl-c1\">this</span> context\n</code></pre>\n<h3>Not nullable by default</h3>\n<p>By default values are not nullable. Nullable values are declared as <code>T?</code>.</p>\n<h2>Bad parts</h2>\n<h3>Type erasure</h3>\n<blockquote>\n<p>Like Java’s, Kotlin’s generics are not retained at runtime,\ni.e. objects do not carry information about actual type arguments\npassed to their constructors, i.e.\n<code>ArrayList&#x3C;Integer>()</code> is indistinguishable from <code>ArrayList&#x3C;Character>()</code>.\nThis makes it impossible to perform is-checks\nthat take generics into account.\nKotlin only allows is-checks for star-projected generic types.</p>\n</blockquote>\n<p>-- <a href=\"https://kotlinlang.org/docs/reference/java-interop.html\">Kotlin Reference</a></p>\n<p>Because they thought reified generics are expensive on JVM:</p>\n<blockquote>\n<p>on the JVM reified generics are expensive</p>\n</blockquote>\n<p>-- <a href=\"http://blog.jetbrains.com/kotlin/2014/12/m10-is-out/\">Kotlin Blog: M10 is out</a></p>\n<p>But</p>\n<blockquote>\n<p>FTR I am not sure I believe that explanation.\nI was with Gavin a few years ago\nwhen Andrey Breslav asked us\nif we were going to implement reified generics\n(we had not yet at the time)\nbecause they were having trouble implementing it\nand so if we were not going to implement it, they would not bother.</p>\n<p>My guess is they tried and failed, strictly based on this conversation.\nIt's possible that they really considered it too expensive,\nbut I since that's not backed by public experiments\nand our own experiments tell us\nit's not that expensive for the benefits it gives us,\nI don't <em>have</em> to believe them ;)</p>\n</blockquote>\n<p>-- <a href=\"https://news.ycombinator.com/item?id=10466643\">UnFroMage commented on HackerNews</a></p>\n<h3>No union types</h3>\n<p>No union types yet. (<a href=\"https://discuss.kotlinlang.org/t/any-thoughts-on-ceylon-style-union-and-intersection-types/547\">547</a>)</p>\n<h3>No checked exceptions</h3>\n<p>Kotlin does not support checked exceptions.</p>\n<p>I think the good part of checked exception is\nto force you think about corner cases,\nand the bad part is increasing verbosity.</p>\n<p>Ceylon does not support checked exceptions either.\nBut Ceylon supports union types.\nIn fact, Java's checked exception mimics union types.</p>\n<p>Kotlin supports neither checked exception, nor union types.\nThus its type system cannot check whether a function may raise an exception\n(unless the exception is representable as null)\nand what exceptions it may raise.</p>\n<p>However, throwing one exception is a good practice in common situations.</p>\n<blockquote>\n<p>The reason that you would, ideally, want to only throw one type of exception\nis because doing otherwise likely violates the Single Responsibility and\nDependency Inversion principles.</p>\n<p>...</p>\n<pre><code class=\"language-java\"><span class=\"pl-k\">public</span> <span class=\"pl-smi\">String</span> getData(<span class=\"pl-k\">int</span> id) throws <span class=\"pl-smi\">FileNotFoundException</span>\n</code></pre>\n<p>Now, we have a change in requirements, and our data comes from a database.</p>\n<p>...</p>\n<pre><code class=\"language-java\"><span class=\"pl-k\">public</span> <span class=\"pl-smi\">String</span> getData(<span class=\"pl-k\">int</span> id) throws <span class=\"pl-smi\">SQLException</span>\n</code></pre>\n<p>We would now have to go through all code that uses our method\nand change the exception we have to check for, else the code won't compile.</p>\n<p>Dependency inversion says that we really shouldn't throw either\nof these exceptions\nbecause they expose internal implementation details\nwe are working to encapsulate.\n...\nInstead we should throw an exception\nthat conveys the error at the same level of abstraction\nas we are exposing through our API.</p>\n</blockquote>\n<p>-- <a href=\"http://programmers.stackexchange.com/a/264068/65620\">cbojar, 2014-11-29</a></p>\n<p>For a similar reason, Swift just uses <code>throws</code> in function signature,\nto declare a function which may throw exceptions,\nwithout specifying types of exception.</p>\n<p>Another reason to throw only one exception is Single Responsibility:</p>\n<blockquote>\n<p>As for Single Responsibility, we need to think about code\nthat throws multiple, unrelated exceptions.\nLet's say we have the following method:</p>\n<pre><code class=\"language-java\"><span class=\"pl-k\">public</span> <span class=\"pl-smi\">Record</span> parseFile(<span class=\"pl-smi\">String</span> filename) throws <span class=\"pl-smi\">IOException</span>, <span class=\"pl-smi\">ParseException</span>\n</code></pre>\n<p>What can we say about this method? We can tell just from the signature\nthat it opens a file <strong>and</strong> parses it.\nWhen we see a conjunction, like \"and\" or \"or\"\nin the description of a method,\nwe know that it is doing more than one thing;\nit has more than one <strong>responsibility</strong>.\nMethods with more than one responsibility are hard to manage\nas they can change if any of the responsibilities change.\nInstead, we should break methods up so they have a single responsibility:</p>\n<pre><code class=\"language-java\"><span class=\"pl-k\">public</span> <span class=\"pl-smi\">String</span> readFile(<span class=\"pl-smi\">String</span> filename) throws <span class=\"pl-smi\">IOException</span>\n<span class=\"pl-k\">public</span> <span class=\"pl-smi\">Record</span> parse(<span class=\"pl-smi\">String</span> data) throws <span class=\"pl-smi\">ParseException</span>\n</code></pre>\n</blockquote>\n<p>-- <a href=\"http://programmers.stackexchange.com/a/264068/65620\">cbojar, 2014-11-29</a></p>\n<h2>Mixed feelings</h2>\n<h3><code>return</code> behaves differently in lambda and anonymous function</h3>\n<p>Kotlin distinguishes lambda expression and anonymous function.\nIn lambda, <code>return</code> returns from the outer function.</p>\n<p>This reminds me of the dark side of Ruby.\nRuby also distinguishes <code>proc</code> created by lambda expression and <code>Proc.new</code>.\nIn Ruby,the <code>return</code> statement in <code>proc</code> created by <code>Proc.new</code>\nwill not only returns control just from itself,\nbut also from the method enclosing it.</p>\n<p>To be fair, Kotlin is more reasonable than Ruby.\nIn Kotlin, lambda does not allow explicit return result expression.</p>\n<h3>Use <code>when</code> for both <code>case</code> and <code>cond</code> in Scheme</h3>\n<p>Kotlin uses <code>when</code> for both <code>case</code> (pattern matching)\nand <code>cond</code> (conditional expression) in Scheme.</p>\n<pre><code class=\"language-kotlin\"><span class=\"pl-k\">when</span> {\n    f(i) <span class=\"pl-k\">-></span> <span class=\"pl-c1\">false</span>  <span class=\"pl-c\">// f = { it == 0}</span>\n    <span class=\"pl-k\">else</span> <span class=\"pl-k\">-></span> <span class=\"pl-c1\">true</span>\n}\n<span class=\"pl-k\">when</span> (i) {\n    g(i) <span class=\"pl-k\">-></span> <span class=\"pl-c1\">false</span>  <span class=\"pl-c\">// g = { if (it == 0) 0 else 1 }</span>\n    <span class=\"pl-k\">else</span> <span class=\"pl-k\">-></span> <span class=\"pl-c1\">true</span>\n}\n</code></pre>\n<p>Unless you remember the definition of <code>f</code> or <code>g</code>,\nyou does not know whether it is pattern matching or conditional expressions\nuntil you go back to the beginning of the <code>when</code> expression.</p>\n<p>A workaround is to make it explicit using the full expression of condition:</p>\n<pre><code class=\"language-kotlin\"><span class=\"pl-k\">when</span> {\n    f(i) <span class=\"pl-k\">==</span> <span class=\"pl-c1\">true</span> <span class=\"pl-k\">-></span> <span class=\"pl-c1\">false</span>  <span class=\"pl-c\">// f = { it == 0}</span>\n    <span class=\"pl-k\">else</span> <span class=\"pl-k\">-></span> <span class=\"pl-c1\">true</span>\n}\n<span class=\"pl-k\">when</span> (i) {\n    g(i) <span class=\"pl-k\">-></span> <span class=\"pl-c1\">false</span>  <span class=\"pl-c\">// g = { if (it == 0) 0 else 1 }</span>\n    <span class=\"pl-k\">else</span> <span class=\"pl-k\">-></span> <span class=\"pl-c1\">true</span>\n}\n</code></pre>\n<p>Or use an explicit function name:</p>\n<pre><code class=\"language-kotlin\"><span class=\"pl-k\">when</span> {\n    isZero(i) <span class=\"pl-k\">-></span> <span class=\"pl-c1\">false</span>  <span class=\"pl-c\">// isZero = { it == 0}</span>\n    <span class=\"pl-k\">else</span> <span class=\"pl-k\">-></span> <span class=\"pl-c1\">true</span>\n}\n<span class=\"pl-k\">when</span> (i) {\n    matchesZero(i) <span class=\"pl-k\">-></span> <span class=\"pl-c1\">false</span>  <span class=\"pl-c\">// matchesZero = { if (it == 0) 0 else 1 }</span>\n    <span class=\"pl-k\">else</span> <span class=\"pl-k\">-></span> <span class=\"pl-c1\">true</span>\n}\n</code></pre>\n<p>This workaround does not work when <code>i</code> itself is a <code>Boolean</code>.</p>\n<p>However, if <code>i</code> is a <code>Boolean</code>, usually we will use <code>when</code> as:</p>\n<pre><code class=\"language-kotlin\"><span class=\"pl-k\">when</span> (i) {\n    <span class=\"pl-c1\">true</span> <span class=\"pl-k\">-></span> <span class=\"pl-k\">..</span>.\n    <span class=\"pl-c1\">false</span> <span class=\"pl-k\">-></span> <span class=\"pl-k\">..</span>.\n}\n</code></pre>\n<p>Ambiguity does exist\nwhen we match <code>i</code> against <code>Boolean</code> value returned by other functions.</p>\n<h3>Boxed types in Java</h3>\n<p>Some types are boxed in Java, which does not preserve identity, and often preserve equality.</p>\n<pre><code class=\"language-kotlin\"><span class=\"pl-k\">val</span> a<span class=\"pl-k\">:</span> <span class=\"pl-c1\">Int</span> <span class=\"pl-k\">=</span> <span class=\"pl-c1\">10000</span>\n<span class=\"pl-c1\">print</span>(a <span class=\"pl-k\">===</span> a) <span class=\"pl-c\">// Prints 'true'</span>\n<span class=\"pl-k\">val</span> boxedA<span class=\"pl-k\">:</span> <span class=\"pl-c1\">Int?</span> <span class=\"pl-k\">=</span> a\n<span class=\"pl-k\">val</span> anotherBoxedA<span class=\"pl-k\">:</span> <span class=\"pl-c1\">Int?</span> <span class=\"pl-k\">=</span> a\n<span class=\"pl-c1\">print</span>(boxedA <span class=\"pl-k\">===</span> anotherBoxedA) <span class=\"pl-c\">// !!!Prints 'false'!!!</span>\n<span class=\"pl-c1\">print</span>(boxedA <span class=\"pl-k\">==</span> anotherBoxedA) <span class=\"pl-c\">// Prints 'true'</span>\n</code></pre>\n<p>This confuses me.\nI understood that interoperability is important, though.</p>\n<h3>String templates</h3>\n<p>String templates are supported both inside raw strings and inside escaped strings. If you need to represent a literal <code>$</code> character in a raw string (which does't support backslash escaping), you can use the following syntax):</p>\n<pre><code class=\"language-kotlin\"><span class=\"pl-k\">val</span> price <span class=\"pl-k\">=</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"\"\"</span></span>\n<span class=\"pl-s\"><span class=\"pl-e\">${</span><span class=\"pl-pds\">'</span><span class=\"pl-e\">$</span><span class=\"pl-pds\">'</span><span class=\"pl-e\">}</span>9.99</span>\n<span class=\"pl-s\"><span class=\"pl-pds\">\"\"\"</span></span>\n</code></pre>\n<p><code>${'$'}</code> looks ugly to me.\nAnd dollar signs are common in text for prices.\nAnd I wonder whether raw strings with templates are truly raw.\nEven if we did need templates in raw string,\nI think restricting it to <code>${var}</code> is better.\nPut this under \"mixed feeling\" rather than \"bad parts\",\nbecause I think this is trivial after all.</p>\n<h2>Conclusion</h2>\n<p>Kotlin is an improved Java, featuring interoperability.\nMost features are already in Java as \"best practices\".</p>\n<p>On other side, it lost checked exception.</p>\n<p>Read more on my opinions on the design of Kotlin in <a href=\"https://mmap.page/dive-into/kotlin/ceylon-kotlin.md\">Ceylon v.s. Kotlin</a></p>","date_published":"Thu, 06 Dec 2018 00:53:57 GMT","date_modified":"Sun, 23 Apr 2023 04:25:20 GMT"},{"id":"https://mmap.page/dive-into/exceptions/","url":"https://mmap.page/dive-into/exceptions/","title":"Exception and Union Type","content_html":"<h1>Exception and Union Type</h1>\n<p>Java has checked exception, which is essentially union type.</p>\n<p>Kotlin dislikes Java's checked exception, and just removes it.</p>\n<p>Ceylon also does not have checked exception, but it has union types.</p>\n<p>Swift has something like semi-checked exception.\nUnlike Java, a Swift function can only declare if it may throw an exception or not.\n(Specifying <code>throws</code> in function signature.)\nBut it cannot specify types of exception.\nThus if the caller of the function tries to catch the exception,\nit must have a default catch all clause in the end.\nAnd since Swift only distinguish functions may throw and may not throw,\nit is straightforward to map a function's throwability to optional type\n(via <code>try?</code>).</p>\n<h2>Optional Type and Union Type</h2>\n<p><code>T?</code> can be considered as a union of <code>T|Null</code>.</p>\n<p><code>(J|K) -> T</code> can be expressed as overloads.</p>\n<h2>More on Exception and Union Type</h2>\n<blockquote>\n<p>Checked exception is an imperfect, ugly implementation of union type.</p>\n</blockquote>\n<p>-- <a href=\"http://www.yinwang.org/blog-cn/2017/05/23/kotlin\">Yin Wang</a></p>\n<p>For example, <code>String f() throws NotFound</code> can be considered as a function returning a union type of <code>String | NotFound</code>.</p>\n<p>From the viewpoint of union type, <code>String | NotFound</code> and <code>NotFound | String</code> is equivalent.\nThus we can use exceptions as return value, and return value as exception in Java.</p>\n<pre><code class=\"language-java\"><span class=\"pl-k\">class</span> <span class=\"pl-en\">DividedByZero</span> {}\n\n<span class=\"pl-k\">class</span> <span class=\"pl-en\">IntRet</span> <span class=\"pl-k\">extends</span> <span class=\"pl-e\">Exception</span>\n{\n\t<span class=\"pl-k\">public</span> <span class=\"pl-k\">int</span> value;\n\n\t<span class=\"pl-k\">public</span> <span class=\"pl-en\">IntRet</span>(<span class=\"pl-k\">int</span> <span class=\"pl-v\">value</span>)\n    {\n      <span class=\"pl-c1\">this</span><span class=\"pl-k\">.</span>value <span class=\"pl-k\">=</span> value;\n    }\n}\n\n<span class=\"pl-k\">class</span> <span class=\"pl-en\">CharRet</span> <span class=\"pl-k\">extends</span> <span class=\"pl-e\">Exception</span>\n{\n\t<span class=\"pl-k\">public</span> <span class=\"pl-k\">char</span> value;\n\n\t<span class=\"pl-k\">public</span> <span class=\"pl-en\">CharRet</span>(<span class=\"pl-k\">char</span> <span class=\"pl-v\">value</span>)\n    {\n\t\t<span class=\"pl-c1\">this</span><span class=\"pl-k\">.</span>value <span class=\"pl-k\">=</span> value;\n    }\n}\n\n<span class=\"pl-k\">public</span> <span class=\"pl-k\">class</span> <span class=\"pl-en\">HelloWorld</span>\n{\n\t<span class=\"pl-k\">private</span> <span class=\"pl-k\">static</span> <span class=\"pl-smi\">DividedByZero</span> <span class=\"pl-en\">divide</span>(<span class=\"pl-k\">int</span> <span class=\"pl-v\">x</span>, <span class=\"pl-k\">int</span> <span class=\"pl-v\">y</span>) <span class=\"pl-k\">throws</span> <span class=\"pl-smi\">IntRet</span>, <span class=\"pl-smi\">CharRet</span>\n\t{\n\t\t<span class=\"pl-k\">if</span> (y <span class=\"pl-k\">==</span> <span class=\"pl-c1\">0</span>)\n\t\t{\n\t\t\t<span class=\"pl-k\">return</span> <span class=\"pl-k\">new</span> <span class=\"pl-smi\">DividedByZero</span>();\n\t\t}\n\t\t<span class=\"pl-k\">else</span> <span class=\"pl-k\">if</span> (y <span class=\"pl-k\">&#x3C;</span> <span class=\"pl-c1\">0</span>)\n\t\t{\n\t\t\t<span class=\"pl-k\">throw</span> <span class=\"pl-k\">new</span> <span class=\"pl-smi\">CharRet</span>(<span class=\"pl-s\"><span class=\"pl-pds\">'</span>N<span class=\"pl-pds\">'</span></span>);\n        }\n\t\t<span class=\"pl-k\">else</span>\n\t\t{\n\t\t\t<span class=\"pl-k\">throw</span> <span class=\"pl-k\">new</span> <span class=\"pl-smi\">IntRet</span>(x <span class=\"pl-k\">/</span> y);\n\t\t}\n\t}\n\n\t<span class=\"pl-k\">public</span> <span class=\"pl-k\">static</span> <span class=\"pl-k\">void</span> <span class=\"pl-en\">main</span>(<span class=\"pl-k\">String</span>[] <span class=\"pl-v\">args</span>)\n\t{\n\t\t<span class=\"pl-k\">try</span>\n\t\t{\n\t\t\t<span class=\"pl-smi\">DividedByZero</span> err <span class=\"pl-k\">=</span> divide(<span class=\"pl-c1\">10</span>, <span class=\"pl-c1\">2</span>);\n\t\t\t<span class=\"pl-smi\">System</span><span class=\"pl-k\">.</span>out<span class=\"pl-k\">.</span>println(err); <span class=\"pl-c\">// handle error</span>\n\t\t}\n\t\t<span class=\"pl-k\">catch</span> (<span class=\"pl-smi\">IntRet</span> e)\n\t\t{\n\t\t\t<span class=\"pl-smi\">System</span><span class=\"pl-k\">.</span>out<span class=\"pl-k\">.</span>println(e<span class=\"pl-k\">.</span>value);\n\t\t}\n\t\t<span class=\"pl-k\">catch</span> (<span class=\"pl-smi\">CharRet</span> e)\n        {\n\t\t\t<span class=\"pl-smi\">System</span><span class=\"pl-k\">.</span>out<span class=\"pl-k\">.</span>println(<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>Divided by a negative number is not supported yet.<span class=\"pl-pds\">\"</span></span>);\n        }\n\t}\n}\n</code></pre>\n<p>This also applies Kotlin.\nUsing exceptions as return values can spare return value for exception.\nThe Kotlin compiler will warn us unused declared variable,\nso this in effect mimics checked exception for a language without checked exception in an exotic and ugly way.</p>\n<pre><code class=\"language-kotlin\"><span class=\"pl-k\">object</span> DividedByZero {}\n\n<span class=\"pl-k\">class</span> <span class=\"pl-en\">IntRet</span>(<span class=\"pl-k\">val</span> <span class=\"pl-smi\">value</span><span class=\"pl-k\">:</span> <span class=\"pl-c1\">Int</span>): Throwable(<span class=\"pl-c1\">null</span>, <span class=\"pl-c1\">null</span>) {}\n\n<span class=\"pl-k\">fun</span> <span class=\"pl-en\">divide</span>(<span class=\"pl-smi\">x</span><span class=\"pl-k\">:</span> <span class=\"pl-c1\">Int</span>, <span class=\"pl-smi\">y</span><span class=\"pl-k\">:</span> <span class=\"pl-c1\">Int</span>): <span class=\"pl-en\">DividedByZero</span>\n{\n    <span class=\"pl-k\">if</span> (y <span class=\"pl-k\">==</span> <span class=\"pl-c1\">0</span>)\n    {\n        <span class=\"pl-k\">return</span> <span class=\"pl-en\">DividedByZero</span>\n    }\n    <span class=\"pl-k\">else</span>\n    {\n        <span class=\"pl-k\">throw</span> <span class=\"pl-en\">IntRet</span>(x <span class=\"pl-k\">/</span> y)\n    }\n}\n\n<span class=\"pl-k\">fun</span> <span class=\"pl-en\">main</span>(<span class=\"pl-smi\">args</span><span class=\"pl-k\">:</span> <span class=\"pl-c1\">Array</span>&#x3C;<span class=\"pl-c1\">String</span>>) {\n    <span class=\"pl-k\">try</span>\n    {\n        <span class=\"pl-k\">val</span> err <span class=\"pl-k\">=</span> divide(<span class=\"pl-c1\">10</span>, <span class=\"pl-c1\">2</span>)\n        <span class=\"pl-c1\">println</span>(err) <span class=\"pl-c\">// handle error</span>\n    }\n    <span class=\"pl-k\">catch</span> (e<span class=\"pl-k\">:</span> <span class=\"pl-en\">IntRet</span>)\n    {\n        <span class=\"pl-c1\">println</span>(e.value)\n    }\n}\n</code></pre>","date_published":"Thu, 06 Dec 2018 00:53:57 GMT","date_modified":"Thu, 26 Dec 2019 15:16:30 GMT"},{"id":"https://mmap.page/dive-into/ceylon-kotlin/","url":"https://mmap.page/dive-into/ceylon-kotlin/","title":"Ceylon v.s. Kotlin","content_html":"<h1>Ceylon v.s. Kotlin</h1>\n<h2>void function</h2>\n<p>Kotlin uses <code>Unit</code> for functions returning nothing, like many functional languages,\nwhile Ceylon uses <code>void</code> keyword.\nvoid functions in Ceylon actually returns <code>Anything</code>.\nThis allows to use other non-void functions when void functions are expected,\nand other non-void functions to accept void function as parameter.</p>\n<p>Ceylon's <code>Anything</code> approach is flexible,\nbut it may not fit in a more disciplined coding style.\nIf non-void functions are used when void functions are expected,\nthen we are using side effects with non-void functions.\nBut a non-void function should avoid exposing side effects.</p>\n<p>We can declare our own <code>Unit</code> class in Ceylon:</p>\n<pre><code class=\"language-ceylon\"><span class=\"pl-k\">abstract</span> <span class=\"pl-k\">class</span> <span class=\"pl-en\">Unit</span>() <span class=\"pl-k\">of</span> <span class=\"pl-smi\">unit</span> {}\n<span class=\"pl-k\">object</span> <span class=\"pl-smi\">unit</span> <span class=\"pl-k\">extends</span> <span class=\"pl-en\">Unit</span>() {}\n\n<span class=\"pl-en\">Unit</span> <span class=\"pl-smi\">f</span>() {\n    <span class=\"pl-smi\">print</span>(<span class=\"pl-s\">\"hi\"</span>);\n    <span class=\"pl-k\">return</span> <span class=\"pl-smi\">unit</span>;\n}\n\n<span class=\"pl-k\">shared</span> <span class=\"pl-k\">void</span> <span class=\"pl-smi\">run</span>() {\n    <span class=\"pl-smi\">f</span>();\n}\n</code></pre>\n<p>Like assignment returning a value, Ceylon's behavior may also be influenced by C.\nIn C, any function can be converted to <code>void</code> via <code>(void) f</code>, discarding its return value.</p>\n<h2>Variadic arguments</h2>\n<p>Kotlin uses <code>vararg</code> keyword to mark variadic argument, while Ceylon just types\nthem with <code>T*</code> or <code>T+</code> (at least have an argument).  This is an example of\nCeylon's regularity of type system. Kotlin uses <code>Array&#x3C;T></code> for <code>vararg p: T</code>\nunderhood but special array types for basic types, e.g. <code>IntArray</code> for <code>vararg p: Int</code>. However, <code>p: Array&#x3C;T></code> and <code>vararg p: T</code> behaves differently. In other\nwords, given a function <code>Array&#x3C;T> -> Unit</code>, we do not know how to invoke it\njust from its signature.</p>\n<h2>Function reference</h2>\n<p>Kotlin's function reference syntax is strange:</p>\n<pre><code class=\"language-kotlin\"><span class=\"pl-k\">fun</span> <span class=\"pl-en\">gf</span>(<span class=\"pl-smi\">x</span><span class=\"pl-k\">:</span> <span class=\"pl-c1\">Double</span>, <span class=\"pl-smi\">f</span><span class=\"pl-k\">:</span> (<span class=\"pl-c1\">Double</span>) <span class=\"pl-k\">-></span> <span class=\"pl-c1\">Double</span>): <span class=\"pl-c1\">Double</span> {\n    <span class=\"pl-k\">return</span> f(x)\n}\ngf(<span class=\"pl-c1\">2.0</span>, ::findFixPoint)\n</code></pre>\n<p>Without <code>::</code> it will not work.</p>\n<p>Languages using special function reference syntax usually saves <code>f</code> for <code>f()</code>.\nBut that is not allowed in Kotlin, either.\nInstead, Kotlin saves <code>f</code> for a variable/property <code>f</code> with the same name!</p>\n<pre><code class=\"language-kotlin\"><span class=\"pl-k\">val</span> i <span class=\"pl-k\">=</span> <span class=\"pl-c1\">2</span>\n<span class=\"pl-k\">fun</span> <span class=\"pl-en\">i</span>(): <span class=\"pl-c1\">Int</span> { <span class=\"pl-k\">return</span> <span class=\"pl-c1\">2</span> };\n<span class=\"pl-c1\">print</span>(i)\n<span class=\"pl-c1\">print</span>(i())\n</code></pre>\n<p>Still Kotlin compiler cannot resolve the function reference\nif there is a property which has the same name:</p>\n<pre><code class=\"language-kotlin\"><span class=\"pl-k\">fun</span> <span class=\"pl-en\">h</span>(<span class=\"pl-smi\">f</span><span class=\"pl-k\">:</span> () <span class=\"pl-k\">-></span> <span class=\"pl-c1\">Int</span>) {\n    <span class=\"pl-c1\">print</span>(f())\n}\nh(::i) <span class=\"pl-c\">// error: overload resolution ambiguity</span>\n</code></pre>\n<p>Also, Kotlin only allows reference to <code>Foo::bar</code>\n<a href=\"https://github.com/Kotlin/KEEP/blob/master/proposals/bound-callable-references.md\">not <code>foo::bar</code></a>.</p>\n<p>For anonymous function, there is no ambiguity.\nThus the function reference is normal.</p>\n<pre><code class=\"language-kotlin\"><span class=\"pl-k\">val</span> f <span class=\"pl-k\">=</span> <span class=\"pl-k\">fun</span>(): <span class=\"pl-c1\">Int</span> { <span class=\"pl-k\">return</span> <span class=\"pl-c1\">1</span> }\nh(i)\n</code></pre>\n<p>Ceylon's function reference is normal.</p>\n<p>Ceylon does not support overloading. And function reference will not work for\nJava overloading functions.</p>\n<h2>Inline functions</h2>\n<p>Kotlin supports inline functions.</p>\n<pre><code class=\"language-kotlin\"><span class=\"pl-k\">inline</span> <span class=\"pl-k\">fun</span> <span class=\"pl-en\">foo</span>(<span class=\"pl-smi\">inlined</span><span class=\"pl-k\">:</span> () <span class=\"pl-k\">-></span> <span class=\"pl-c1\">Unit</span>, noinline <span class=\"pl-smi\">notInlined</span><span class=\"pl-k\">:</span> () <span class=\"pl-k\">-></span> <span class=\"pl-c1\">Unit</span>) {}\n<span class=\"pl-k\">inline</span> <span class=\"pl-k\">fun</span> <span class=\"pl-en\">f</span>(crossinline <span class=\"pl-smi\">body</span><span class=\"pl-k\">:</span> () <span class=\"pl-k\">-></span> <span class=\"pl-c1\">Unit</span>) {\n    <span class=\"pl-k\">val</span> f <span class=\"pl-k\">=</span> <span class=\"pl-k\">object:</span> <span class=\"pl-en\">Runnable</span> {\n        <span class=\"pl-c\">// body is called in another context `object: Runnable`,</span>\n        <span class=\"pl-c\">// thus we need the `crossinline` keyword.</span>\n        <span class=\"pl-k\">override</span> <span class=\"pl-k\">fun</span> <span class=\"pl-en\">run</span>() <span class=\"pl-k\">=</span> body()\n    }\n    <span class=\"pl-c\">// ...</span>\n}\n</code></pre>\n<p>Kotlin's inline function supports reified generics:</p>\n<pre><code class=\"language-kotlin\"><span class=\"pl-k\">inline</span> <span class=\"pl-k\">fun</span> &#x3C;<span class=\"pl-en\">reified</span> <span class=\"pl-en\">T</span>> TreeNode.<span class=\"pl-en\">findParentOfType</span>(): <span class=\"pl-en\">T</span><span class=\"pl-k\">?</span> {\n    <span class=\"pl-k\">var</span> p <span class=\"pl-k\">=</span> parent\n    <span class=\"pl-k\">while</span> (p <span class=\"pl-k\">!=</span> <span class=\"pl-c1\">null</span> <span class=\"pl-k\">&#x26;&#x26;</span> p <span class=\"pl-k\">!is</span> <span class=\"pl-en\">T</span>) {\n        p <span class=\"pl-k\">=</span> p?.parent\n    }\n    <span class=\"pl-k\">return</span> p <span class=\"pl-k\">as</span> <span class=\"pl-en\">T</span>\n}\n</code></pre>\n<p>Ceylon does not support inline functions, and all generics are reified, except\ninteroperation with Java code.</p>\n<p>IMO, languages should make function calls cheap, instead of bring in confusing\ninline features.</p>\n<h2>Object</h2>\n<p>Kotlin's object looks like class, and provides an <code>invoke</code> method to mimic\nfunction call with object initialization.</p>\n<pre><code class=\"language-kotlin\"><span class=\"pl-k\">object</span> SingletonExample {\n   <span class=\"pl-k\">fun</span> <span class=\"pl-en\">singletonMethod</span>() {\n        <span class=\"pl-k\">return</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>We cannot initialize a singleton.<span class=\"pl-pds\">\"</span></span>\n   }\n   <span class=\"pl-k\">operator</span> <span class=\"pl-k\">fun</span> <span class=\"pl-en\">invoke</span>() {\n        <span class=\"pl-k\">return</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>`invoke` will be called when we write `SingletonExample()`.<span class=\"pl-pds\">\"</span></span>\n   }\n}\n</code></pre>\n<p>I dislike this feature.\nNow every time I see <code>CapsName(something)</code>\nI am not sure it returns an instance of <code>CapsName</code>.\nIt may return anything!</p>\n<p>Ceylon's object does not have a <code>invoke</code> method.</p>\n<pre><code class=\"language-ceylon\"><span class=\"pl-k\">shared</span> <span class=\"pl-k\">object</span> <span class=\"pl-smi\">consoleWriter</span> <span class=\"pl-k\">satisfies</span> <span class=\"pl-en\">Writer</span> {\n    <span class=\"pl-smi\">formatter</span> = <span class=\"pl-en\">StringFormatter</span>();\n    <span class=\"pl-smi\">write</span>(<span class=\"pl-en\">String</span> <span class=\"pl-smi\">string</span>) => <span class=\"pl-smi\">process</span>.<span class=\"pl-smi\">write</span>(<span class=\"pl-smi\">string</span>);\n}\n</code></pre>\n<p>The downside of object (anonymous class) in Ceylon is if we ever need to write\ncode that refers to the concrete type consoleWriter, we must use the very ugly\nsyntax <code>\\IconsoleWriter</code> as the type name.\nA toplevel object in Ceylon is a singleton.</p>\n<p>Object (anonymous class) in Ceylon is actually a value constructor:</p>\n<pre><code class=\"language-ceylon\"><span class=\"pl-c\">// object thing {}</span>\n<span class=\"pl-k\">class</span> <span class=\"pl-en\">\\Ithing</span> {\n    <span class=\"pl-k\">shared</span> <span class=\"pl-k\">new</span> <span class=\"pl-smi\">thing</span> {}\n}\n<span class=\"pl-en\">\\Ithing</span> <span class=\"pl-smi\">thing</span> => <span class=\"pl-en\">\\Ithing</span>.<span class=\"pl-smi\">thing</span>;\n</code></pre>\n<p>Kotlin also has object expression.</p>\n<pre><code class=\"language-kotlin\"><span class=\"pl-k\">val</span> adHoc <span class=\"pl-k\">=</span> <span class=\"pl-k\">object</span> {\n    <span class=\"pl-k\">var</span> x<span class=\"pl-k\">:</span> <span class=\"pl-c1\">Int</span> <span class=\"pl-k\">=</span> <span class=\"pl-c1\">0</span>\n    <span class=\"pl-k\">var</span> y<span class=\"pl-k\">:</span> <span class=\"pl-c1\">Int</span> <span class=\"pl-k\">=</span> <span class=\"pl-c1\">0</span>\n}\n<span class=\"pl-k\">open</span> <span class=\"pl-k\">class</span> <span class=\"pl-en\">A</span>(<span class=\"pl-smi\">x</span><span class=\"pl-k\">:</span> <span class=\"pl-c1\">Int</span>) {\n    <span class=\"pl-k\">public</span> <span class=\"pl-k\">open</span> <span class=\"pl-k\">val</span> y<span class=\"pl-k\">:</span> <span class=\"pl-c1\">Int</span> <span class=\"pl-k\">=</span> x\n}\n\n<span class=\"pl-k\">interface</span> <span class=\"pl-en\">B</span>\n\n<span class=\"pl-k\">val</span> ab <span class=\"pl-k\">=</span> <span class=\"pl-k\">object</span> <span class=\"pl-k\">:</span> <span class=\"pl-en\">A</span>(<span class=\"pl-c1\">1</span>), <span class=\"pl-en\">B</span> {\n    <span class=\"pl-k\">override</span> <span class=\"pl-k\">val</span> y <span class=\"pl-k\">=</span> <span class=\"pl-c1\">15</span>\n}\n</code></pre>\n<p>Object expression in Ceylon:</p>\n<pre><code class=\"language-ceylon\"><span class=\"pl-k\">return</span> <span class=\"pl-k\">object</span> <span class=\"pl-k\">extends</span> <span class=\"pl-en\">Foo</span>() <span class=\"pl-k\">satisfies</span> <span class=\"pl-en\">Bar</span> {\n    <span class=\"pl-c\">// ...</span>\n};\n</code></pre>\n<p>An object expression is basically a shorthand for a local object declaration.</p>\n<pre><code class=\"language-ceylon\"><span class=\"pl-k\">object</span> <span class=\"pl-smi\">foo</span> <span class=\"pl-k\">extends</span> <span class=\"pl-en\">Foo</span>() <span class=\"pl-k\">satisfies</span> <span class=\"pl-en\">Bar</span> {\n    <span class=\"pl-c\">// ...</span>\n};\n<span class=\"pl-k\">return</span> <span class=\"pl-smi\">foo</span>;\n</code></pre>\n<p>Kotlin uses component object to mimic Java static methods:</p>\n<pre><code class=\"language-kotlin\"><span class=\"pl-k\">class</span> <span class=\"pl-en\">ExampleClass</span>(<span class=\"pl-k\">val</span> <span class=\"pl-smi\">x</span><span class=\"pl-k\">:</span> <span class=\"pl-c1\">Int</span>) {\n    <span class=\"pl-k\">companion</span> <span class=\"pl-k\">object</span> {\n        <span class=\"pl-c\">// still a real object at runtime</span>\n        <span class=\"pl-k\">fun</span> <span class=\"pl-en\">aMethodLooksLikeStaticButNot</span>() <span class=\"pl-k\">=</span> <span class=\"pl-c1\">println</span>(<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>not static<span class=\"pl-pds\">\"</span></span>)\n        @JvmStatic <span class=\"pl-k\">fun</span> <span class=\"pl-en\">aMethodToBeCompiledToStaticMethodOnJVM</span>() {\n            <span class=\"pl-c1\">println</span>(<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>compiled to static methods on JVM<span class=\"pl-pds\">\"</span></span>)\n        }\n    }\n}\n<span class=\"pl-en\">ExampleClass</span>.aMethodLooksLikeStaticButNot()\n<span class=\"pl-en\">ExampleClass</span>.aMethodToBeCompiledToStaticMethodOnJVM()\n</code></pre>\n<p>Ceylon does not support this.</p>\n<p>Both Kotlin and Ceylon support top level function declaration,\nsomething like package level static method.</p>\n<p>Ceylon 1.3.1 introduces static member.</p>\n<p>Also, Kotlin supports extension method.\nExtension method on Kotlin is resolved statically,\nonly providing a way to call with <code>Class.method</code> syntax,\nnot actually modifying the extended class.</p>\n<p>Similarly to functions, Kotlin supports extension properties. Again, Ceylon\ndoes not support this.</p>\n<h2>Final class</h2>\n<p>Classes in Kotlin are <code>final</code> by default.\nAlso, Kotlin requires explicit <code>open</code> modifier for overridable members.\nAnd a member marked override is itself open.\nAlso, properties declared in Interface are open.</p>\n<pre><code class=\"language-kotlin\"><span class=\"pl-k\">open</span> <span class=\"pl-k\">class</span> <span class=\"pl-en\">OpenClass</span>(<span class=\"pl-smi\">x</span><span class=\"pl-k\">:</span> <span class=\"pl-c1\">Int</span>) {\n    <span class=\"pl-k\">open</span> <span class=\"pl-k\">fun</span> <span class=\"pl-en\">overridableMember</span>() {}\n}\n<span class=\"pl-k\">open</span> <span class=\"pl-k\">class</span> <span class=\"pl-en\">ChildOfOpenClass</span>(<span class=\"pl-smi\">x</span><span class=\"pl-k\">:</span> <span class=\"pl-c1\">Int</span>) : OpenClass(x) {\n    <span class=\"pl-k\">override</span> <span class=\"pl-k\">fun</span> <span class=\"pl-en\">overridableMember</span>() {}\n}\n</code></pre>\n<p>Ceylon classes are by default open, unless annotated with <code>final</code>.\nHowever, Ceylon also requires explicit annotation for overridable members:</p>\n<ul>\n<li><code>formal</code> for declaration without implementation,</li>\n<li><code>default</code> for <code>open</code> in Kotlin,</li>\n<li><code>actual</code> for <code>override</code> in Kotlin (no <code>default</code> unless denoted).</li>\n</ul>\n<p>Also, attributes in interface are not open by default in Kotlin.\nYou need to explicitly annotate it as <code>formal</code>.</p>\n<h2><code>super</code> ambiguity</h2>\n<p>Kotlin uses <code>super&#x3C;A>.f()</code>.</p>\n<pre><code class=\"language-kotlin\"><span class=\"pl-k\">open</span> <span class=\"pl-k\">class</span> <span class=\"pl-en\">A</span>() {\n    <span class=\"pl-k\">open</span> <span class=\"pl-k\">fun</span> <span class=\"pl-en\">f</span>() { <span class=\"pl-c1\">print</span>(<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>A<span class=\"pl-pds\">\"</span></span>) }\n}\n\n<span class=\"pl-k\">interface</span> <span class=\"pl-en\">B</span> {\n    <span class=\"pl-c\">// Interface members are open by default.</span>\n    <span class=\"pl-k\">fun</span> <span class=\"pl-en\">f</span>() { <span class=\"pl-c1\">print</span>(<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>B<span class=\"pl-pds\">\"</span></span>) }  <span class=\"pl-c\">// Allowing method implementations, like Java 8.</span>\n}\n\n<span class=\"pl-k\">class</span> <span class=\"pl-en\">ChildOfAB</span>() : A(), B {\n    <span class=\"pl-c\">// The compiler requires `f()` to be overridden.</span>\n    <span class=\"pl-c\">// So you do not need to remember rules of priorities</span>\n    <span class=\"pl-c\">// and check super class definitions for possible conflicts.</span>\n    <span class=\"pl-k\">override</span> <span class=\"pl-k\">fun</span> <span class=\"pl-en\">f</span>() {\n        <span class=\"pl-c1\">super</span>&#x3C;<span class=\"pl-en\">A</span>>.f()\n        <span class=\"pl-c1\">super</span>&#x3C;<span class=\"pl-en\">B</span>>.f()\n    }\n}\n</code></pre>\n<p>Ceylon uses <code>(super of A).f()</code>.</p>\n<pre><code class=\"language-ceylon\"><span class=\"pl-k\">class</span> <span class=\"pl-en\">SelfReference</span>() {\n    <span class=\"pl-c\">// Ceylon has keywords `this` and `super`.</span>\n    <span class=\"pl-c\">// To deal with ambiguity of what `super` refers to, use the widening operator.</span>\n    <span class=\"pl-k\">class</span> <span class=\"pl-en\">Impl</span>() <span class=\"pl-k\">extends</span> <span class=\"pl-en\">Class</span>() <span class=\"pl-k\">satisfies</span> <span class=\"pl-en\">Interface</span> {\n    <span class=\"pl-c\">// Suppose Impl inherits two different implementations of `ambiguous`</span>\n    <span class=\"pl-c\">// from Class and Interface.</span>\n        (<span class=\"pl-k\">super</span> <span class=\"pl-k\">of</span> <span class=\"pl-en\">Interface</span>).<span class=\"pl-smi\">ambiguous</span>()\n    }\n}\n</code></pre>\n<h2>getter and setter</h2>\n<p>Kotlin uses <code>get()</code> and <code>set()</code> functions with optional backing field:</p>\n<pre><code class=\"language-kotlin\"><span class=\"pl-k\">class</span> <span class=\"pl-en\">GettersAndSetters</span>(<span class=\"pl-k\">val</span> <span class=\"pl-smi\">x</span><span class=\"pl-k\">:</span> <span class=\"pl-c1\">Int</span>) {\n    <span class=\"pl-k\">var</span> isEmpty<span class=\"pl-k\">:</span> <span class=\"pl-c1\">Boolean</span> <span class=\"pl-k\">=</span> <span class=\"pl-c1\">null</span>\n        get() <span class=\"pl-k\">=</span> <span class=\"pl-c1\">this</span>.x <span class=\"pl-k\">==</span> <span class=\"pl-c1\">0</span>\n        <span class=\"pl-c\">// By convention, the name of the setter parameter is value,</span>\n        <span class=\"pl-c\">// but you can choose a different name if you prefer.</span>\n        set(value) {\n            <span class=\"pl-k\">if</span> (value <span class=\"pl-k\">==</span> <span class=\"pl-c1\">null</span>) {\n                <span class=\"pl-c\">// Kotlin provides an automatic backing `field`.</span>\n                field <span class=\"pl-k\">=</span> <span class=\"pl-c1\">false</span>\n            } <span class=\"pl-k\">else</span> {\n                <span class=\"pl-c\">// The field identifier can only be used in the accessors of the property.</span>\n                field <span class=\"pl-k\">=</span> value\n            }\n        }\n}\n</code></pre>\n<p>Ceylon uses anonymous setter and <code>assign</code> for getter,\nwithout backing field.</p>\n<pre><code class=\"language-Ceylon\"><span class=\"pl-k\">class</span> <span class=\"pl-en\">GetterSetterExample</span>() {\n    <span class=\"pl-k\">variable</span> <span class=\"pl-en\">String</span>? <span class=\"pl-smi\">rank</span> = <span class=\"pl-smi\">null</span>;  <span class=\"pl-c\">// Ceylon never auto initializes to null.</span>\n    <span class=\"pl-k\">variable</span> <span class=\"pl-en\">String</span>? <span class=\"pl-smi\">comment</span> = <span class=\"pl-smi\">null</span>;\n    <span class=\"pl-k\">shared</span> <span class=\"pl-en\">String</span> <span class=\"pl-smi\">review</span> => <span class=\"pl-s\">\"``</span><span class=\"pl-smi\">rank</span><span class=\"pl-s\">``: ``</span><span class=\"pl-smi\">comment</span><span class=\"pl-s\">``\"</span>;\n    <span class=\"pl-k\">assign</span> <span class=\"pl-smi\">review</span> {\n        <span class=\"pl-k\">value</span> <span class=\"pl-smi\">tokens</span> = <span class=\"pl-smi\">review</span>.<span class=\"pl-smi\">split</span>(<span class=\"pl-s\">\":\"</span>).<span class=\"pl-smi\">iterator</span>();\n        <span class=\"pl-k\">if</span> (<span class=\"pl-k\">is</span> <span class=\"pl-en\">String</span> <span class=\"pl-smi\">first</span> = <span class=\"pl-smi\">tokens</span>.<span class=\"pl-smi\">next</span>()) {  <span class=\"pl-c\">// narrowing down types</span>\n            <span class=\"pl-smi\">rank</span> = <span class=\"pl-smi\">first</span>;\n        }\n        <span class=\"pl-k\">if</span> (<span class=\"pl-k\">is</span> <span class=\"pl-en\">String</span> <span class=\"pl-smi\">second</span> = <span class=\"pl-smi\">tokens</span>.<span class=\"pl-smi\">next</span>()) {\n            <span class=\"pl-smi\">comment</span> = <span class=\"pl-smi\">second</span>;\n        }\n    }\n}\n</code></pre>\n<p>In Kotlin, immutable variable <code>val</code> does not allow setter.\nCeylon's getter and setter are more flexible.\nIn the above example, we have a setter for immutable <code>review</code>.\nThe setter is valid, since it actually changes value of mutable <code>rank</code> and <code>comment</code>.</p>\n<h2>const</h2>\n<p>Kotlin has compile time <code>const</code>:</p>\n<pre><code class=\"language-kotlin\"><span class=\"pl-k\">const</span> <span class=\"pl-k\">val</span> <span class=\"pl-en\">VERSION</span><span class=\"pl-k\">:</span> <span class=\"pl-c1\">String</span> <span class=\"pl-k\">=</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>alpha<span class=\"pl-pds\">\"</span></span>\n</code></pre>\n<p><code>const</code> only allows <code>String</code> or a primitive type.</p>\n<p>Ceylon does not have this.</p>\n<p>I have no idea why this need to be explicitly marked in Kotlin.\nThe compiler cannot automatically optimize this?</p>\n<h2>late init</h2>\n<p>Kotlin has <code>lateinit</code> and Ceylon has <code>late</code> annotation.\nBut they are two different things.</p>\n<p>Kotlin only allows non-nullable, not-primitive types to use <code>lateinit</code>. Kotlin\nuses the <code>null</code> value to mark that a <code>lateinit</code> property has not been\ninitialized and to throw the appropriate exception when the property is\naccessed. But primitive Java types can't have a 'null' value. In other words,\nthe property must be not nullable in Kotlin level, but nullable in Java level.</p>\n<pre><code class=\"language-kotlin\"><span class=\"pl-k\">public</span> <span class=\"pl-k\">class</span> <span class=\"pl-en\">MyTest</span> {\n    <span class=\"pl-k\">lateinit</span> <span class=\"pl-k\">var</span> subject<span class=\"pl-k\">:</span> <span class=\"pl-en\">TestSubject</span>\n\n    @SetUp <span class=\"pl-k\">fun</span> <span class=\"pl-en\">setup</span>() {\n        subject <span class=\"pl-k\">=</span> <span class=\"pl-en\">TestSubject</span>()\n    }\n\n    @Test <span class=\"pl-k\">fun</span> <span class=\"pl-en\">test</span>() {\n        subject.method()\n    }\n}\n</code></pre>\n<p>Ceylon uses <code>late</code> to suppress definite initialization checks.\nIn Ceylon, all declaration is done after initialization,\nwhich may cause problems on circular reference.</p>\n<pre><code class=\"language-ceylon\"><span class=\"pl-k\">class</span> <span class=\"pl-en\">Child</span>(<span class=\"pl-smi\">parent</span>) {\n    <span class=\"pl-k\">shared</span> <span class=\"pl-k\">late</span> <span class=\"pl-en\">Parent</span> <span class=\"pl-smi\">parent</span>;\n}\n\n<span class=\"pl-k\">class</span> <span class=\"pl-en\">Parent</span>() {\n    <span class=\"pl-c\">// This won't work,</span>\n    <span class=\"pl-c\">// because `this` refers to an instance of Parent in its own initializer section,</span>\n    <span class=\"pl-c\">// where Parent has not been initialized yet.</span>\n    <span class=\"pl-c\">// shared Child child = Child(this);</span>\n    <span class=\"pl-k\">shared</span> <span class=\"pl-en\">Child</span> <span class=\"pl-smi\">child</span> = <span class=\"pl-en\">Child</span>();\n    <span class=\"pl-smi\">child</span>.<span class=\"pl-smi\">parent</span> = <span class=\"pl-k\">this</span>; <span class=\"pl-c\">// ok, since parent is late</span>\n}\n</code></pre>\n<h2>declaration-site variance</h2>\n<p>Both Kotlin and Ceylon uses declaration-site variance <code>&#x3C;out Bar></code>.</p>\n<p>Ceylon also support use-site variance for interoperation with Java code.\nSo does Kotlin, with a slightly different syntax <code>&#x3C;out Bar!>!</code>.</p>\n<h2>Generics constrains</h2>\n<p>Kotlin uses common <code>T : Upper</code> syntax:</p>\n<pre><code class=\"language-kotlin\"><span class=\"pl-k\">fun</span> &#x3C;<span class=\"pl-en\">T</span> <span class=\"pl-k\">:</span> <span class=\"pl-en\">Comparable</span>&#x3C;<span class=\"pl-en\">T</span>>> <span class=\"pl-en\">sort</span>(<span class=\"pl-smi\">list</span><span class=\"pl-k\">:</span> <span class=\"pl-c1\">List</span>&#x3C;<span class=\"pl-en\">T</span>>) {}\n</code></pre>\n<p>More than one upper bounds need to be specify in a where clause:</p>\n<pre><code class=\"language-kotlin\"><span class=\"pl-k\">fun</span> &#x3C;<span class=\"pl-en\">T</span>> <span class=\"pl-en\">cloneWhenGretter</span>(<span class=\"pl-smi\">list</span><span class=\"pl-k\">:</span> <span class=\"pl-c1\">List</span>&#x3C;<span class=\"pl-en\">T</span>>, <span class=\"pl-smi\">threshold</span><span class=\"pl-k\">:</span> <span class=\"pl-en\">T</span>): <span class=\"pl-c1\">List</span>&#x3C;<span class=\"pl-en\">T</span>>\n        where <span class=\"pl-en\">T</span> <span class=\"pl-k\">:</span> <span class=\"pl-en\">Cloneable</span>, <span class=\"pl-en\">T</span> <span class=\"pl-k\">:</span> <span class=\"pl-en\">Comparable</span> {\n    <span class=\"pl-k\">return</span> list.filter{it <span class=\"pl-k\">></span> threshold}.map{it.clone()}\n}\n</code></pre>\n<p>Ceylon has a more consistent syntax,\nand uses intersection type for more than one upper bounds.</p>\n<pre><code>Value genericFunction&#x3C;Value>(Value num, Value denom)\n        given Value satisfies Comparable&#x3C;Value> &#x26; Summable&#x3C;Value>\n        => if num > denom then num else num + denom;\n</code></pre>\n<p>Both Kotlin and Ceylon does not support raw type.\nKotlin has a similar star projection syntax:</p>\n<p>Given <code>interface Function&#x3C;in S, out T></code>, <code>Function&#x3C;*, *></code> is a shortcut for\n<code>Function&#x3C;in Nothing, out Any?></code></p>\n<p>Ceylon just supports explicit <code>Function&#x3C;in Nothing, out Anything></code>.</p>\n<p>Also note that Ceylon uses <code>Anything</code> instead of <code>Any?</code> in Kotlin.\n<code>Any</code> in Kotlin is not truly <code>Any</code> because it does not hold <code>null</code>.\nCeylon's <code>Anything</code> is an enumerated type:</p>\n<pre><code class=\"language-ceylon\"><span class=\"pl-k\">shared</span> <span class=\"pl-k\">abstract</span> <span class=\"pl-k\">class</span> <span class=\"pl-en\">Anything</span>()\n        <span class=\"pl-k\">of</span> <span class=\"pl-en\">Object</span> | <span class=\"pl-en\">Null</span> {}\n</code></pre>\n<p><code>of Object | Null</code> can be used in generics as enumerated constrain.</p>\n<h2>Anonymous function</h2>\n<p>Kotlin has both anonymous function and lambda:</p>\n<pre><code class=\"language-kotlin\"><span class=\"pl-c\">// anonymous function</span>\n<span class=\"pl-k\">fun</span>(): <span class=\"pl-c1\">Unit</span> { <span class=\"pl-c1\">println</span>(numbers.size) }\n<span class=\"pl-c\">// lambda</span>\n{ n<span class=\"pl-k\">:</span> <span class=\"pl-c1\">Int</span> <span class=\"pl-k\">-></span> n <span class=\"pl-k\">&#x3C;=</span> <span class=\"pl-c1\">0</span> }\n<span class=\"pl-c\">// one parameter lambda can be abbreviated,</span>\n<span class=\"pl-c\">// also parameter type can be omitted if it can be inferred by compiler</span>\n{ it <span class=\"pl-k\">&#x3C;=</span> <span class=\"pl-c1\">0</span> }\n</code></pre>\n<p>The difference between lambda and anonymous function is:</p>\n<ul>\n<li>lambda cannot specify a return type</li>\n<li>control flow <code>return</code> in lambda returns the outer function</li>\n</ul>\n<p>Ceylon just have anonymous function.</p>\n<pre><code class=\"language-ceylon\"><span class=\"pl-c\">// Same as lambda in Kotlin, an anonymous function cannot specify return type.</span>\n(<span class=\"pl-en\">Integer</span> <span class=\"pl-smi\">n</span>) => <span class=\"pl-smi\">n</span> &#x3C;= <span class=\"pl-c1\">0</span>\n<span class=\"pl-c\">// Except `void`.</span>\n<span class=\"pl-k\">void</span> (<span class=\"pl-en\">Integer</span> <span class=\"pl-smi\">n</span>, <span class=\"pl-en\">Integer</span> <span class=\"pl-smi\">m</span>) => <span class=\"pl-smi\">print</span>(<span class=\"pl-smi\">m</span> + <span class=\"pl-smi\">n</span>)\n<span class=\"pl-c\">// Mark it with `function`</span>\n<span class=\"pl-k\">function</span> (<span class=\"pl-en\">Integer</span> <span class=\"pl-smi\">n</span>) => <span class=\"pl-smi\">n</span> &#x3C;= <span class=\"pl-c1\">0</span>\n<span class=\"pl-c\">// Like `function`, `void` can be omitted.</span>\n() => <span class=\"pl-smi\">print</span>(<span class=\"pl-s\">\"Hi!\"</span>)\n<span class=\"pl-c\">// Same as above, with block</span>\n() { <span class=\"pl-smi\">print</span>(<span class=\"pl-s\">\"Hi!\"</span>); }\n<span class=\"pl-c\">// Similar to Kotlin's anonymus function</span>\n<span class=\"pl-k\">function</span> () { <span class=\"pl-smi\">print</span>(<span class=\"pl-s\">\"Hi!\"</span>); }\n</code></pre>\n<h2>case</h2>\n<p>Kotlin uses <code>when</code> for both <code>case</code> and <code>cond</code> in Scheme.</p>\n<pre><code class=\"language-kotlin\"><span class=\"pl-k\">when</span> {\n    i <span class=\"pl-k\">==</span> <span class=\"pl-c1\">0</span> <span class=\"pl-k\">-></span> <span class=\"pl-c1\">false</span>\n    <span class=\"pl-k\">else</span> <span class=\"pl-k\">-></span> <span class=\"pl-c1\">true</span>\n}\n<span class=\"pl-k\">when</span> (i) {\n    <span class=\"pl-c1\">0</span> <span class=\"pl-k\">-></span> <span class=\"pl-c1\">false</span>\n    <span class=\"pl-k\">else</span> <span class=\"pl-k\">-></span> <span class=\"pl-c1\">true</span>\n}\n</code></pre>\n<p>Ceylon just uses <code>switch</code> for <code>case</code>:</p>\n<pre><code class=\"language-ceylon\">  <span class=\"pl-k\">void</span> <span class=\"pl-smi\">printID</span>(<span class=\"pl-en\">String</span>|<span class=\"pl-en\">Integer</span> <span class=\"pl-smi\">id</span>) {\n      <span class=\"pl-k\">switch</span> (<span class=\"pl-smi\">id</span>)\n      <span class=\"pl-k\">case</span> (<span class=\"pl-k\">is</span> <span class=\"pl-en\">String</span>) {\n          <span class=\"pl-smi\">println</span>(<span class=\"pl-smi\">id</span>);\n      }\n      <span class=\"pl-k\">case</span> (<span class=\"pl-k\">is</span> <span class=\"pl-en\">Integer</span>) {\n          <span class=\"pl-k\">switch</span> (<span class=\"pl-smi\">id</span>)\n          <span class=\"pl-k\">case</span> (<span class=\"pl-c1\">0</span>) {\n            <span class=\"pl-smi\">println</span>(<span class=\"pl-s\">\"Error\"</span>);\n          }\n          <span class=\"pl-k\">else</span> {\n            <span class=\"pl-smi\">println</span>(<span class=\"pl-s\">\"id number: ``</span><span class=\"pl-smi\">id</span><span class=\"pl-s\">``\"</span>);\n          }\n      }\n      <span class=\"pl-c\">// No `else` clause since all cases of a union type is exhausted.</span>\n}\n</code></pre>\n<p>Ceylon uses <code>switch</code> as statements,\nwhile Kotlin uses <code>when</code> as both statements and expressions.</p>\n<p><code>case</code> must be both disjoint and exhausted in Ceylon.</p>\n<pre><code class=\"language-ceylon\"><span class=\"pl-k\">shared</span> <span class=\"pl-k\">abstract</span> <span class=\"pl-k\">class</span> <span class=\"pl-en\">Comparison</span>(<span class=\"pl-k\">shared</span> <span class=\"pl-k\">actual</span> <span class=\"pl-en\">String</span> <span class=\"pl-smi\">string</span>)\n        <span class=\"pl-k\">of</span> <span class=\"pl-smi\">larger</span> | <span class=\"pl-smi\">smaller</span> | <span class=\"pl-smi\">equal</span> {}\n<span class=\"pl-k\">switch</span> (<span class=\"pl-smi\">x</span>&#x3C;=><span class=\"pl-smi\">y</span>)  <span class=\"pl-c\">//  `&#x3C;=>`  produces an instance of `Comparison`.</span>\n<span class=\"pl-k\">case</span> (<span class=\"pl-smi\">equal</span>) {\n    <span class=\"pl-smi\">print</span>(<span class=\"pl-s\">\"same same\"</span>);\n}\n<span class=\"pl-k\">case</span> (<span class=\"pl-smi\">smaller</span>) {\n    <span class=\"pl-smi\">print</span>(<span class=\"pl-s\">\"x smaller\"</span>);\n}\n<span class=\"pl-k\">case</span> (<span class=\"pl-smi\">larger</span>) {\n    <span class=\"pl-smi\">print</span>(<span class=\"pl-s\">\"y smaller\"</span>);\n}\n</code></pre>\n<p>Cases must be exhausted in Kotlin only in <code>when</code> expression.</p>\n<p>In Ceylon, <code>switch</code> can declare a scoped local variable:</p>\n<pre><code class=\"language-ceylon\"><span class=\"pl-k\">switch</span> (<span class=\"pl-smi\">name</span> = <span class=\"pl-smi\">process</span>.<span class=\"pl-smi\">arguments</span>.<span class=\"pl-smi\">first</span>)\n<span class=\"pl-k\">case</span> (<span class=\"pl-smi\">null</span>) {\n    <span class=\"pl-smi\">print</span>(<span class=\"pl-s\">\"Hello world!\"</span>);\n}\n<span class=\"pl-k\">else</span> {\n    <span class=\"pl-smi\">print</span>(<span class=\"pl-s\">\"Hello ``</span><span class=\"pl-smi\">name</span><span class=\"pl-s\">``!\"</span>);\n}\n</code></pre>\n<p>This is frequently used in Ceylon,\nbecause Ceylon's case condition does not allow arbitrary expressions.\nOnly conditions like <code>exists</code>, <code>is Type</code>, <code>nonempty</code>\nand literal values of basic types are allowed.</p>\n<h2>Catch checked exceptions from Java</h2>\n<p>Kotlin does not have checked exceptions. So, normally, the Java signatures of\nKotlin functions do not declare exceptions thrown. If you want to call them in\ntry catch clause from Java, you need to annotate functions with\n<code>@Throws(IOException::class)</code>.</p>\n<p>The root of the exception hierarchy in Ceylon is <code>ceylon.language::Throwable</code>,\nUnlike Java's <code>Throwable</code>, <code>ceylon.language::Throwable</code> is sealed and the only\nsubclasses available to users are <code>ceylon.language::Exception</code> and\n<code>ceylon.language::AssertionError</code>.</p>\n<p>The JVM implementation of <code>ceylon.language::Exception</code> is a\n<code>java.lang.RuntimeException</code>. On the other hand,\n<code>ceylon.language::AssertionError</code> is a <code>java.lang.Error</code> at runtime. This means\nthat pure Ceylon code compiled for the JVM can only generate unchecked\nexceptions.</p>\n<p>Impure Ceylon (that is, Ceylon code which access Java code) may throw any\nexception that is thrown by that Java code, including checked exceptions. If a\nCeylon function may throw checked exceptions, you need to call it in a try\ncatch clause in Java.</p>\n<h2>Reassignment of function parameters</h2>\n<p>Kotlin does not allow reassignment of function parameters,\ni.e. function parameters are always implicitly <code>val</code>,\nlike function parameters are always implicitly <code>let</code> in Swift.</p>\n<p>Ceylon disallows this unless the function parameter is annotated as <code>variable</code>.\nThis is consistent with variable declaration.</p>","date_published":"Thu, 06 Dec 2018 00:53:57 GMT","date_modified":"Tue, 06 Sep 2022 05:05:55 GMT"},{"id":"https://mmap.page/log/","url":"https://mmap.page/log/","content_html":"<p>Date: <a id=\"1663086020\" href=\"https://mmap.page/log/#1663086020\">1663086020</a></p>\n<p>TypeScript is less apearing to me.</p>\n<p>If I want to write in a dynamic language\nwith a powerful gradual type system.\nThen Python ships with it.</p>\n<p>If I want a sound type system for JavaScript,\nthen there is ReScript.</p>\n<p>Date: <a id=\"1663085149\" href=\"https://mmap.page/log/#1663085149\">1663085149</a></p>\n<p>The order form of $JD website has a field to fill in the email address to receive the receipt.</p>\n<p>But it turns out they just sent me an email, containing a link to download the receipt from their site.</p>\n<p>Date: <a id=\"1663072643\" href=\"https://mmap.page/log/#1663072643\">1663072643</a></p>\n<p>Bad marketing is mostly harmless to users.</p>\n<p>Good marketing can be harmful.\nThe markketing of git, to some extent thanks to Linus and GitHub,\nis so sucessful that so many people are suffering.</p>\n<p>Date: <a id=\"1663055452\" href=\"https://mmap.page/log/#1663055452\">1663055452</a></p>\n<p>I watched spderosso's <a href=\"https://www.youtube.com/watch?v=31XZYMjg93o\" title=\"&#x22;What’s Wrong With Git?&#x22; from Git Merge 2017.\">presentation</a> and skimed the <a href=\"https://spderosso.github.io/oopsla16.pdf\" title=\"Purposes, Concepts, Misfits, and a Redesign of Git\">paper</a> on gitless.</p>\n<p>I find the summary presentation is much more approachable.\nPaper is like source code.\nPresentation or blog post is like a README.</p>\n<p>Date: <a id=\"1662903070\" href=\"https://mmap.page/log/#1662903070\">1662903070</a></p>\n<p>I used to have a <code>git switch</code> alias pointed to <code>legit switch</code>, and haven't checked the native switch command introduced by recent versions of git till today.</p>\n<p>Reading <code>git help switch</code> got me very confused.\nThen after some googling, I understood that basically git switch is just git checkout.</p>\n<p>It turns out that in <code>git checkout foo</code>, <code>foo</code> can mean a branch or a file.\nAnd if both branch foo and file foo exist, the branch takes priority.\nRecent versions of git introduces <code>switch</code> and <code>restore</code> to offer a cleaner user interface.</p>\n<p>Initially I got confused because I never knew <code>git checkout path</code> till today.\nI always did <code>git checkout rev path</code> before.</p>\n<p>Conclusion: git sucks.</p>\n<p>Date: <a id=\"1662883909\" href=\"https://mmap.page/log/#1662883909\">1662883909</a></p>\n<p>The advantage of 11ty is that it works with existing projects.</p>\n<ul>\n<li>It does not require a special project structure,\nsince files do not need to move around.</li>\n<li>Frontmatter can be absent on content files.</li>\n</ul>\n<p>Date: <a id=\"1662828447\" href=\"https://mmap.page/log/#1662828447\">1662828447</a></p>\n<p>Although deprecated since HTML 2 (1995), the HTML element plaintext is still supported by all major browsers.</p>\n<p><a href=\"https://caniuse.com/?search=plaintext\">https://caniuse.com/?search=plaintext</a></p>\n<p>The backward compatibility of web shines!</p>\n<p>Date: <a id=\"1659874628\" href=\"https://mmap.page/log/#1659874628\">1659874628</a></p>\n<p>Alternatives to homebrew are still alive!</p>\n<p><a href=\"https://trac.macports.org/\">MacPorts</a> supports all the current versions of macOS:\n10.15, 11, and 12.</p>\n<p><a href=\"https://www.finkproject.org/\">Fink</a> supports the oldest current version of macOS: 10.15.\nIn other words, it has not supported M1 yet.</p>\n<p><a href=\"https://pkgsrc.joyent.com/install-on-osx/\">pkgsrc</a> built packages against macOS 11 (x86 &#x26; M1) and 10.14,\nsuitable for users running recent macOS releases.</p>\n<p>Date: <a id=\"1659844869\" href=\"https://mmap.page/log/#1659844869\">1659844869</a></p>\n<p>A Survey on Social Networks</p>\n<ul>\n<li>\n<p><a href=\"https://www.fsf.org/\">FSF</a> is cautious on social networks:</p>\n<ul>\n<li>\n<p>Gnu Social (former StatusNet)</p>\n</li>\n<li>\n<p>Mastodon</p>\n</li>\n<li>\n<p>PeerTube</p>\n</li>\n<li>\n<p>Twitter</p>\n<p>FSF uses a custom script to post to their GNU social, Mastodon,\nand Twitter accounts simultaneously.\nThis avoids using the nonfree JS of the Twitter website.\nChoqok, a KDE application which supports Twitter and GNU Social,\nis used to view replies and retweet posts.\nUnlike Facebook, FSF have no ethical objection\nto <strong>merely</strong> having an account on Twitter.</p>\n</li>\n</ul>\n</li>\n<li>\n<p><a href=\"https://www.eff.org/\">EFF</a> tends to reach for more people:</p>\n<ul>\n<li>Twitter</li>\n<li>Facebook</li>\n<li>Instagram</li>\n<li>YouTube</li>\n<li>Flickr</li>\n</ul>\n</li>\n<li>\n<p><a href=\"https://wiki.debian.org/Teams/Publicity/micronews\">Debian</a> hosts a micronews site (a static site generated via pelican),\nand the feed is automatically syndicated to these non-official accounts:</p>\n<ul>\n<li>\n<p>Mastodon &#x26; GNU Social</p>\n<p>Since both use the ActivityPub protocol,\nthe non-official Debian Mastodon account can be subscribed from\nGNU Social.</p>\n</li>\n<li>\n<p>Twitter</p>\n<p>Besides the non-official @debian, @debconf, @planetdebian\naccounts, several Debian teams have accounts on Twitter.</p>\n</li>\n<li>\n<p>Facebook</p>\n</li>\n<li>\n<p>LinkedIn</p>\n</li>\n<li>\n<p>Hacker News</p>\n</li>\n</ul>\n</li>\n<li>\n<p><a href=\"https://www.gentoo.org/\">Gentoo</a> seemingly chooses the most popular social networks:</p>\n<ul>\n<li>\n<p>Twitter</p>\n</li>\n<li>\n<p>Facebook</p>\n</li>\n</ul>\n</li>\n<li>\n<p>Python, Slackware, FreeBSD, NetBSD, etc.</p>\n<p>They just do not care about social networks.</p>\n</li>\n</ul>\n<p>Summary</p>\n<ul>\n<li>Host content on your own site, optionally syndicate to social networks.</li>\n<li>Use distributed social networks such as Mastodon.</li>\n<li>Twitter is an acceptable choice among popular social networks.</li>\n</ul>\n<p>Date: <a id=\"1659752677\" href=\"https://mmap.page/log/#1659752677\">1659752677</a></p>\n<p>Stacked encryption systems</p>\n<p>tl;dr</p>\n<ul>\n<li>Compared to block level encryption or file system native encryption,\nstacked encrypted files can be easily backed up via popular cloud\nstorage services such as DropBox.</li>\n<li>Use cryfs for sensitive data.</li>\n<li>Use gocryptfs in reverse mode for other data if the cloud storage does\nnot support end to end encryption itself.</li>\n</ul>\n<p>Comparison:</p>\n<ul>\n<li>\n<p>ecryptfs</p>\n<ul>\n<li>pros: mature, merged in Linux kernel</li>\n<li>cons: Linux only</li>\n<li>cons: no protection over meta data such as file numbers or file\nsizes</li>\n</ul>\n</li>\n<li>\n<p>gocryptfs</p>\n<ul>\n<li>pros: also offers a <a href=\"https://nuetzlich.net/gocryptfs/reverse_mode_crypto/\">reverse mode</a>, which can be used to backup\nfiles on a block encrypted disk (e.g. LUKS) to a cloud storage\n(e.g. DropBox)</li>\n<li>pros: fastest in performance among stacked encryption solutions</li>\n<li>pros: available under Linux and macOS, with third party Windows\nand Android port</li>\n<li>cons: no protection over meta data</li>\n<li>cons: <a href=\"https://nuetzlich.net/gocryptfs/threat_model/\">weaker integrity protection</a></li>\n</ul>\n</li>\n<li>\n<p>cryfs</p>\n<ul>\n<li>pros: meta data protected via chunked storage</li>\n<li>pros: support Linux, macOS, and Windows (experimental)</li>\n<li>pros: included in <a href=\"http://www.slackware.com/releasenotes/packages15.0.php\">slackware 15</a></li>\n<li>cons: significant speed and size overhead</li>\n</ul>\n</li>\n</ul>\n<p>For more information, refer to comparisons on websites of <a href=\"https://nuetzlich.net/gocryptfs/comparison/\">gocryptfs</a>\nand <a href=\"https://www.cryfs.org/comparison\">cryfs</a>.</p>\n<p>Date: <a id=\"1659752237\" href=\"https://mmap.page/log/#1659752237\">1659752237</a></p>\n<p>Just tried installing EndeavourOS on a virtual machine.</p>\n<p>The Caramares installer can configure LUKS full disk encryption\nautomatically. However, when booting the freshly installed system,\nI can only type the encryption passphrase in US qwerty keyboard layout.</p>\n<p><a href=\"https://unix.stackexchange.com/a/174657\">frostschutz</a> suggests a workaround:</p>\n<blockquote>\n<p>add the passphrase twice. So the same sequence of key presses will be accepted\nin both US/qwerty layout and whatever you usually use (in my case, DE/qwertz).</p>\n</blockquote>\n<p>Inspired from frostschutz, I configured the installation with qwerty\nlayout. When I input the passphrase for LUKS encryption, I just input\nthe sequence of key presses as the same if I were on a dvorak layout.</p>\n<p>When setting up the user password during the installation, I input a\ntemporary password containing only numbers.</p>\n<p>After booting into the installed system, I changed the user password and\nthe keyboard layout.</p>\n<p>Date: <a id=\"1642437589\" href=\"https://mmap.page/log/#1642437589\">1642437589</a></p>\n<p>I used to think Dvorak layout is universal,</p>\n<p>until recently I became interested in text processors\nand learned that most of them do not support Dvorak layout.</p>\n<p>For example, Pomara <a href=\"https://www.kingjim.co.jp/faq/pomera/dm100/1413.html\">DM100</a> does not support Dovark:</p>\n<blockquote>\n<p>Q: DM100のキーボードは「QWERTY配列」だが「Dvorak配列」に変更はできませんか。</p>\n<p>A: 変更はできません。</p>\n</blockquote>\n<p>Date: <a id=\"1640792005\" href=\"https://mmap.page/log/#1640792005\">1640792005</a></p>\n<p>Recently I bought a HP Pavilion laptop.</p>\n<p>The setup process is terrible.\nI have to turn off my WiFi router to setup a local account.\nOtherwise it forces me to setup a Microsoft online account.</p>\n<p>Also, it requires me to setup a PIN after I have already setup a\npassword.\nHow stupid it is!</p>\n<p>Date: <a id=\"1633121264\" href=\"https://mmap.page/log/#1633121264\">1633121264</a></p>\n<p>I decided to take notes as git commit messages.</p>\n<p>Why?</p>\n<ul>\n<li>\n<p>It is distributed by nature. I do not need to rely on a central\nservice.</p>\n</li>\n<li>\n<p>I am familiar with git. Most of the time I take notes under the\nterminal, where I aliased <code>n</code> to <code>git commit --allow-empty</code>. And if\nnecessary, I can write commit messages via GitHub web UI or GitHub\nmobile application.</p>\n</li>\n<li>\n<p>GitHub provides ATOM feed for recent commits out of the box:</p>\n<pre><code>https://github.com/weakish/USER/REPO/master.atom\n</code></pre>\n</li>\n<li>\n<p>Since I wrote commit messages in Markdown format. It is trivial to\ngenerate a static html page:</p>\n<pre><code class=\"language-sh\">git log <span class=\"pl-k\">|</span> sed -r <span class=\"pl-s\"><span class=\"pl-pds\">'</span>s/^((commit |Author: |Date: ).+)/\\1&#x3C;br>/g<span class=\"pl-pds\">'</span></span> <span class=\"pl-k\">|</span>\nsed -r <span class=\"pl-s\"><span class=\"pl-pds\">'</span>s/^[ ]{4}//g<span class=\"pl-pds\">'</span></span> <span class=\"pl-k\">></span> log.md\n</code></pre>\n<p>Once I got the Markdown file, I can put it under almost any static\nsite generator.</p>\n</li>\n<li>\n<p>I may use branches for notes in different languages or categories in\nfuture.</p>\n</li>\n</ul>\n<p>Date: <a id=\"1633119948\" href=\"https://mmap.page/log/#1633119948\">1633119948</a></p>\n<p>Just switched from vim to neovim.</p>\n<p>neovim has sensible default configurations.\nThus I only enabled spell checking:</p>\n<pre><code class=\"language-sh\"><span class=\"pl-k\">;</span> cat <span class=\"pl-k\">~</span>/.config/nvim/init.vim\n<span class=\"pl-s\"><span class=\"pl-pds\">\"</span> exclude CJK characters from spell checking</span>\n<span class=\"pl-s\">set spelllang=en,cjk</span>\n<span class=\"pl-s\">set spell</span>\n</code></pre>\n<p>I also changed neovim to provide the <code>editor/vi/vim</code> command.</p>\n<pre><code class=\"language-sh\">sudo update-alternatives --config editor\nsudo update-alternatives --config vi\nsudo update-alternatives --config vim\n</code></pre>\n<p>The content above itself is written under neovim.</p>\n<p>Date: <a id=\"1633096028\" href=\"https://mmap.page/log/#1633096028\">1633096028</a></p>\n<p>The version history of Telegram for macOS looks normal <a href=\"https://macos.telegram.org/\">on its website</a>. But the release messages of <a href=\"https://install.appcenter.ms/users/keepcoder/apps/telegram-swift/distribution_groups/public\">its beta version is very interesting</a>.</p>\n<p>For example:</p>\n<blockquote>\n<p>Thought to be lost for decades, Rembrandt’s first portrait “The Farmer and the Service Message Fix” was recently discovered in the attic of a Belgian café.</p>\n<p>A spoonful of sugar makes the service message fix go down.</p>\n<p>What's cooler, fixes or a cucumber?</p>\n<p>I’ve got 99 problems but the fixes ain’t one.</p>\n<p>The secret ingredient to a good update is a tablespoon of fixes.</p>\n<p>No devs were harmed in the making of the widget/themes in this update.</p>\n<p>Mom, where did you put my fixes?</p>\n<p>Fixes are in the eye of the beholder.</p>\n<p>Fixes are now machine-washable.</p>\n<p>Roll a D20 to resist the fixes check.</p>\n</blockquote>\n<p>Date: <a id=\"1632231803\" href=\"https://mmap.page/log/#1632231803\">1632231803</a></p>\n<p>The ZWJ (Zero Width Joiner)  Unicode character can combine multiple emojis to be displayed as a single emoji. However, a platform may or may not include support for certain the emoji ZWJ sequences. For example, 👁‍🗨 is an emoji ZWJ sequence combining 👁 and 🗨. And if an Emoji ZWJ Sequence is not supported on the platform, it will be displayed as individual emojis, e.g. 🏔️‍🦁‍🏁</p>\n<p>Date: <a id=\"1611678565\" href=\"https://mmap.page/log/#1611678565\">1611678565</a></p>\n<p>From 20200702, the Internet has around 16 months to <a href=\"https://blog.torproject.org/v2-deprecation-timeline\">migrate from onion services v2 to v3</a> once and for all. Now there are less than half a year left, and <a href=\"https://onion.torproject.org/\">onion services run by the Tor projec itself still use v2</a>.</p>\n<p>Also, the future v2 deprecation will turn all existing v2 tor URLs to dead links. This incompatibility is really bad.</p>\n<p>Date: <a id=\"1611468447\" href=\"https://mmap.page/log/#1611468447\">1611468447</a></p>\n<p>Shell scripting is a very bad programming language. But YAML is worse.</p>\n<p>Date: <a id=\"1611423752\" href=\"https://mmap.page/log/#1611423752\">1611423752</a></p>\n<p>LinkedIn forces me to login &#x26; bind my mobile phone number to <strong>just view</strong> its content. Today I discovered an alternative way to check someone's work &#x26; education background, search \"NAME site:rocketreach.co\" or \"NAME COMPANY site:rocketreach.co\" in search engines.</p>\n<p>Date: <a id=\"1608965375\" href=\"https://mmap.page/log/#1608965375\">1608965375</a></p>\n<p>Pop!_OS advertises itself as a developer friendly Linux distribution. However, it uses flatpak, whose sandbox system has a lot of issues with IDEs and editors (they typically need to access system commands and files).</p>\n<p>Personally I prefer AppImage. It solves the \"with dependencies packaged in and run on any Linux distributions\" problem in a simple way and does not rely on  a centric distribution channel. If I want to use AppImage packaged programs in sandbox, I can use firejail. \"Do one thing and do it well.\" AppImage respects the old unix philosophy.</p>\n<p>Date: <a id=\"1608735948\" href=\"https://mmap.page/log/#1608735948\">1608735948</a></p>\n<p>The fish shell improves user experience a lot, both for interactive usage and scripting usage.</p>\n<p>For example, to convert some SVG wallpapers to JPG (I use feh to display wallpapers under the i3 window manage, and feh does not recognize SVG files):</p>\n<pre><code class=\"language-fish\"><span class=\"pl-k\">for</span> i <span class=\"pl-k\">in</span> /usr/share/wallpapers/<span class=\"pl-k\">**</span>/1920x1080.svg\n  convert <span class=\"pl-smi\">$i</span> (string <span class=\"pl-c1\">split</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>/<span class=\"pl-pds\">\"</span></span> <span class=\"pl-smi\">$i</span>)[5].jpg\n<span class=\"pl-k\">end</span>\n</code></pre>\n<p>Concise and clear.</p>\n<p>Date: <a id=\"1608656523\" href=\"https://mmap.page/log/#1608656523\">1608656523</a></p>\n<p>While immature distributions (Arch, Ubuntu, Fedora, etc.) dropped x86 support between 2017-2019, a lot of serious distributions (Slackware, Debian, Gentoo, OpenSUSE, Alpine, etc.) still support old x86 computers.</p>\n<p>FYI, CRUX dropped x86 support on <a href=\"https://crux.nu/Main/ReleaseNotes3-0\">2013</a>.</p>\n<p>Date: <a id=\"1608482666\" href=\"https://mmap.page/log/#1608482666\">1608482666</a></p>\n<p>Fedora Silverblue uses <a href=\"https://ostreedev.github.io/ostree/\">OSTree</a> for its base system, and it is the most mature distribution with an OSTree based base system.</p>\n<p>Since the base system is immutable, new software are installed via Flatpak (sandboxed GUI applications with all its dependencies packaged in) or toolbox (command line programs running inside docker like containers). There are a few exceptions (shell, drivers, etc.) need to be installed via layered rpm packages, which require a reboot.</p>\n<p>I think this is a cool idea. However, I am still unsure whether it is worth to trade in extra disk space and incompatibilities with some software for the confidence that I can  rollback to a usable base system quickly (just reboot) anytime (not require a Internet connection).</p>\n<p>Date: <a id=\"1608480882\" href=\"https://mmap.page/log/#1608480882\">1608480882</a></p>\n<p><a href=\"https://pop.system76.com/\">Pop!_OS</a> is a Ubuntu based distribution which features:</p>\n<ul>\n<li>A tiling extension for gnome shell (I am a happy i3 user and if you really want to use GNOME, you can install this extension yourself on Ubuntu).</li>\n<li>Flatpak (Although Ubuntu have snap preinstalled, you can still use Flatpak on Ubuntu, just as on most other Linux distributions).</li>\n<li>Automatic full-disk encryption during installation. (I'm astonished that Ubuntu still requires manual setup to enable full-disk encryption during installation in 2020. But to be honest, manual setup is not hard.)</li>\n</ul>\n<p>So nothing exciting here. But to be fair, \"just works out of the box\" is a big feature. Particularly, out of the box full-disk encryption is very important for inexperienced users to adapt it.</p>\n<p>Pop!_OS is what Ubuntu should have been.</p>\n<p>Date: <a id=\"1608399092\" href=\"https://mmap.page/log/#1608399092\">1608399092</a></p>\n<p>JAMStack is another buzzword targeting clients using LAMP stack (e.g. wordpress) to host their website. Static website generator will not work because it will confuse those clients: \"Static website? Our site was static N years ago and we use FTP to upload those static web pages to the server. Didn't you told us that static website is outdated with limited features? Why go back to a static site?\"</p>\n<p>I do not think it is a good idea to switch from one shitty language (PHP) to another shitty language (JavaScript), particularly when this switch usually means more CO2 emissions.</p>\n<p>Date: <a id=\"1608230563\" href=\"https://mmap.page/log/#1608230563\">1608230563</a></p>\n<p>Trying to manually resolve a dependencies conflict broken my KDE desktop. Almost all KDE applicants do not work. It seems that KDE Neon assumes you will never uninstall those preinstalled KDE packages and specifies their dependencies causally. Fortunately I can still log into the i3 session (previously I used i3 as the window manager of the KDE session), but I still miss dolphin (temporarily using nautilus) and konsole (temporarily using hyper).</p>\n<p>Maybe this is a good time to try out other distributions or even operating systems, e.g. Pop!_OS?</p>\n<p>Date: <a id=\"1606530944\" href=\"https://mmap.page/log/#1606530944\">1606530944</a></p>\n<p>surge.sh still focuses on static site hosting (Netlify used to focus on static site hosting but they added a lot of dynamic features later), with a command line UI (now.sh (rebranded as vercel now) used to feature this but now their documentation encourages you to do things via their web dashboard).</p>\n<p>Date: <a id=\"1605954392\" href=\"https://mmap.page/log/#1605954392\">1605954392</a></p>\n<p>Q: Why I do not have faith in God?</p>\n<p>A: As Larry Wall paraphrased, faith is just two bits away:</p>\n<blockquote>\n<ol>\n<li>God exists, and</li>\n<li>God is good to people who really look for him</li>\n</ol>\n</blockquote>\n<p>I am not able to prove the first bit is true but let me just assume the first bit is true.</p>\n<p>The second bit is I have to really look for the God. Jesus said you only have to have faith the size of a mustard seed. But no matter how small the size of the faith is, it is <strong>still an opt-in option</strong>. If God is really good, then why faith is <strong>not an opt-out option</strong>?</p>\n<p>Because we are sinners. And the sensible default option for sinners is no faith and going to hell. Salvation is a <strong>gift</strong> from the God.</p>\n<p>However, <strong>a gift is something declinable by its very definition</strong>. Thus I can choose to <strong>decline this gift and keep on the default option</strong>. I did so.</p>\n<p>Although I do not have faith in God, I am still grateful to God. <strong>Thank God for allowing such a sinner as I to have the free will to decline his gift</strong>.</p>\n<p>And what if the first bit is not true? Then I would like to thank god for being nonexistent.</p>\n<p>Date: <a id=\"1605426776\" href=\"https://mmap.page/log/#1605426776\">1605426776</a></p>\n<p><a href=\"https://github.com/txthinking/nico\">nico</a> is a minimalistic zero-configuration HTTP server. It can be used as a reverse proxy or a static file server, with auto applied SSL certificates. Nico have no options to configure. You can not even specify the ports to listen (it always listen on 80/443).</p>\n<p>The binary size on Linux amd64: 6.5 M (for comparison, Caddy is 35 M).</p>\n<p>Date: <a id=\"1603897272\" href=\"https://mmap.page/log/#1603897272\">1603897272</a></p>\n<p>Burmese names do not have surnames. And traditionally Bamars can change their name at will, often with no government oversight. In other words, Burmese names are both screen names and real names.</p>\n<p>Date: <a id=\"1603634286\" href=\"https://mmap.page/log/#1603634286\">1603634286</a></p>\n<p>Why the KISS (Keep it simple, stupid) principle looks so seductive to me? Because the world is too vast to explore.</p>\n<p>Date: <a id=\"1603540199\" href=\"https://mmap.page/log/#1603540199\">1603540199</a></p>\n<p>Macbook Pro 13 (2019) claimed to support \"up to 10 hours wireless web\", but in my daily use (two browsers with dozens of tabs, two IDEs, one electron based editor, one mail client, two IM applications, using both the internal and an external monitor) it can only last about 3 hours.</p>\n<p>Date: <a id=\"1599059053\" href=\"https://mmap.page/log/#1599059053\">1599059053</a></p>\n<p>The English words \"Republic of China\" is still preserved on the redesigned Taiwan passport. They are in a much smaller font wrapping around the national emblem, unnoticeable at a quick glance.</p>\n<p>IMHO, keeping it simple and stupid is much better using these creative tricks. The English words  \"Republic of China\" and all  Chinese words (including \"Republic of China\") should be removed. Also, national emblem can be replaced with Prunus mume (just like the design of the Japanese passport).</p>\n<p>Date: <a id=\"1597769012\" href=\"https://mmap.page/log/#1597769012\">1597769012</a></p>\n<p>There is no options in <a href=\"https://podcasts.google.com/\">Google Podcasts</a> to export subscriptions in OPML. Even Google Takeout does not include Google Podcasts subscriptions. (violation of GDPR?)</p>\n<p>Date: <a id=\"1596728115\" href=\"https://mmap.page/log/#1596728115\">1596728115</a></p>\n<p>According to Uniqlo's size chart, the perfect height is around 165 cm and 150 cm. A person of 165 cm height can choose from both Men's Clothing and Women's Clothing, and a person of 150 cm height can choose from both Women's Clothing and Kids' Clothing.</p>\n<p>Date: <a id=\"1596041215\" href=\"https://mmap.page/log/#1596041215\">1596041215</a></p>\n<p>suitezero.archive posted their collection, a pair of fake Nike sneakers on <a href=\"https://www.instagram.com/p/B3Ig37PlQqB/\">instagram</a>. Unlike most other fake Nike shoes, this pair has its own brand 登云 (meaning climbing the clouds in Chinese) and is produced by 上海皮鞋一厂 (Shanghai No.1 Leather Shoe Factory), a Chinese government-owned enterprise.</p>\n<p><picture><source srcset=\"/log/1596041471.avif\" type=\"image/avif\"><img src=\"https://mmap.page/log/1596041471.jpg\" alt=\"attached image\" width=\"700\" height=\"700\"></picture></p>\n<p>Date: <a id=\"1594691578\" href=\"https://mmap.page/log/#1594691578\">1594691578</a></p>\n<blockquote>\n<p>Also, vertical KDE panel is not supported under i3, so do not buy them.</p>\n</blockquote>\n<p>Oh, I must be very sleepy to write the above sentence. And maybe I dislike KDE subconsciously?</p>\n<p>Date: <a id=\"1594463078\" href=\"https://mmap.page/log/#1594463078\">1594463078</a></p>\n<p>First impression on <a href=\"https://app.hey.com/\">hey email</a>:</p>\n<ol>\n<li>I cannot write an email in plain text. There are no options in settings. All emails are HTML.</li>\n<li>To organize in emails in \"Imbox\"/\"The Feed\"/\"Paper Trail\", I have to manually classify them, or set up that all mails from a certain address go to one of these categories. I expected there will be something fancy magic based on the so called machine learning here, but there is not. And at least in Gmail I can create filters based on more conditions (e.g. subject or body content).</li>\n<li>I can select text in email and click \"save clips\". But they are only shown in the clips menu, there is no highlight in the original email. And in the clips page, I cannot click the clipped text to go to the exact position of the original email (I can only go to the beginning of the email). Therefore context is lost during clipping.</li>\n<li>I do not think a dedicated new mail services is necessary to implement most of the UX features hey offered.</li>\n</ol>\n<p>Date: <a id=\"1594449386\" href=\"https://mmap.page/log/#1594449386\">1594449386</a></p>\n<p>Shame on me: I had not checked whether the producer violates GPL before buying an ebook reader.</p>\n<p><a href=\"https://www.reddit.com/r/linux/comments/hl09g7/onyx_boox_chinese_company_will_not_share_their/\">Reddit: Onyx Boox will not share their linux kernel source code</a></p>\n<p>Date: <a id=\"1593936141\" href=\"https://mmap.page/log/#1593936141\">1593936141</a></p>\n<p><a href=\"http://sinatrarb.com/\">Sinatra</a> in Ruby:</p>\n<pre><code class=\"language-ruby\"><span class=\"pl-k\">require</span> <span class=\"pl-s\"><span class=\"pl-pds\">'</span>sinatra<span class=\"pl-pds\">'</span></span>\nget <span class=\"pl-s\"><span class=\"pl-pds\">'</span>/<span class=\"pl-pds\">'</span></span> <span class=\"pl-k\">do</span>\n      <span class=\"pl-s\"><span class=\"pl-pds\">'</span>Hello, World!<span class=\"pl-pds\">'</span></span>\n<span class=\"pl-k\">end</span>\n</code></pre>\n<p>In Python (a.k.a. Flask):</p>\n<pre><code class=\"language-python\"><span class=\"pl-k\">from</span> flask <span class=\"pl-k\">import</span> Flask\napp <span class=\"pl-k\">=</span> Flask(<span class=\"pl-c1\">__name__</span>)\n\n<span class=\"pl-en\">@app.route</span>(<span class=\"pl-s\"><span class=\"pl-pds\">'</span>/<span class=\"pl-pds\">'</span></span>)\n<span class=\"pl-k\">def</span> <span class=\"pl-en\">hello_world</span>():\n    <span class=\"pl-k\">return</span> <span class=\"pl-s\"><span class=\"pl-pds\">'</span>Hello, World!<span class=\"pl-pds\">'</span></span>\n</code></pre>\n<p>In JavaScript (a.k.a. Express):</p>\n<pre><code class=\"language-javascript\"><span class=\"pl-k\">const</span> <span class=\"pl-c1\">express</span> <span class=\"pl-k\">=</span> <span class=\"pl-c1\">require</span>(<span class=\"pl-s\"><span class=\"pl-pds\">'</span>express<span class=\"pl-pds\">'</span></span>)\n<span class=\"pl-k\">const</span> <span class=\"pl-c1\">app</span> <span class=\"pl-k\">=</span> <span class=\"pl-en\">express</span>()\n<span class=\"pl-k\">const</span> <span class=\"pl-c1\">port</span> <span class=\"pl-k\">=</span> <span class=\"pl-c1\">3000</span>\n\n<span class=\"pl-smi\">app</span>.<span class=\"pl-c1\">get</span>(<span class=\"pl-s\"><span class=\"pl-pds\">'</span>/<span class=\"pl-pds\">'</span></span>, (<span class=\"pl-smi\">req</span>, <span class=\"pl-smi\">res</span>) <span class=\"pl-k\">=></span> <span class=\"pl-smi\">res</span>.<span class=\"pl-c1\">send</span>(<span class=\"pl-s\"><span class=\"pl-pds\">'</span>Hello World!<span class=\"pl-pds\">'</span></span>))\n\n<span class=\"pl-smi\">app</span>.<span class=\"pl-en\">listen</span>(port, () <span class=\"pl-k\">=></span> <span class=\"pl-en\">console</span>.<span class=\"pl-c1\">log</span>(<span class=\"pl-s\"><span class=\"pl-pds\">`</span>Example app listening at http://localhost:<span class=\"pl-pse\"><span class=\"pl-s1\">${</span></span><span class=\"pl-s1\">port</span><span class=\"pl-pse\"><span class=\"pl-s1\">}</span></span><span class=\"pl-pds\">`</span></span>))\n</code></pre>\n<p>In Java (a.k.a. Javalin):</p>\n<pre><code class=\"language-java\"><span class=\"pl-k\">import</span> <span class=\"pl-smi\">io.javalin.Javalin</span>;\n\n<span class=\"pl-k\">public</span> <span class=\"pl-k\">class</span> <span class=\"pl-en\">HelloWorld</span> {\n    <span class=\"pl-k\">public</span> <span class=\"pl-k\">static</span> <span class=\"pl-k\">void</span> <span class=\"pl-en\">main</span>(<span class=\"pl-k\">String</span>[] <span class=\"pl-v\">args</span>) {\n        <span class=\"pl-smi\">Javalin</span> app <span class=\"pl-k\">=</span> <span class=\"pl-smi\">Javalin</span><span class=\"pl-k\">.</span>create(config <span class=\"pl-k\">-></span> config<span class=\"pl-k\">.</span>defaultContentType <span class=\"pl-k\">=</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>application/json<span class=\"pl-pds\">\"</span></span>)<span class=\"pl-k\">.</span>start(<span class=\"pl-c1\">7000</span>);\n        app<span class=\"pl-k\">.</span>get(<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>/<span class=\"pl-pds\">\"</span></span>, ctx <span class=\"pl-k\">-></span> ctx<span class=\"pl-k\">.</span>json(<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>Hello, World!<span class=\"pl-pds\">\"</span></span>));\n    }\n}\n</code></pre>\n<p>In Go (a.k.a. Gin):</p>\n<pre><code class=\"language-go\"><span class=\"pl-k\">package</span> main\n<span class=\"pl-k\">import</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>github.com/gin-gonic/gin<span class=\"pl-pds\">\"</span></span>\n\n<span class=\"pl-k\">func</span> <span class=\"pl-en\">main</span>() {\n        <span class=\"pl-smi\">r</span> <span class=\"pl-k\">:=</span> gin.<span class=\"pl-c1\">Default</span>()\n        r.<span class=\"pl-c1\">GET</span>(<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>/<span class=\"pl-pds\">\"</span></span>, <span class=\"pl-c1\">func</span>(c *gin.<span class=\"pl-smi\">Context</span>) {\n                c.<span class=\"pl-c1\">JSON</span>(<span class=\"pl-c1\">200</span>, gin.<span class=\"pl-smi\">H</span>{\n                        <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>hello<span class=\"pl-pds\">\"</span></span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>world<span class=\"pl-pds\">\"</span></span>,\n                })\n        })\n        r.<span class=\"pl-c1\">Run</span>()\n}\n</code></pre>\n<p>Date: <a id=\"1593885469\" href=\"https://mmap.page/log/#1593885469\">1593885469</a></p>\n<blockquote>\n<p>FastAPI is a modern, fast (high-performance), web framework for building APIs with Python 3.6+ based on standard Python type hints.</p>\n<p>-- <a href=\"https://fastapi.tiangolo.com/\">https://fastapi.tiangolo.com</a></p>\n</blockquote>\n<p><strong>\"based on standard Python type hints\"</strong>, so Let's just check the source code:</p>\n<pre><code class=\"language-python\"><span class=\"pl-k\">class</span> <span class=\"pl-en\">FastAPI</span>(<span class=\"pl-e\">Starlette</span>):\n    <span class=\"pl-k\">def</span> <span class=\"pl-c1\">__init__</span>(\n        <span class=\"pl-smi\">self</span>,\n        <span class=\"pl-k\">*</span>,\n        <span class=\"pl-smi\">debug</span>: <span class=\"pl-c1\">bool</span> <span class=\"pl-k\">=</span> <span class=\"pl-c1\">False</span>,\n        <span class=\"pl-smi\">routes</span>: List[BaseRoute] <span class=\"pl-k\">=</span> <span class=\"pl-c1\">None</span>,\n        <span class=\"pl-smi\">title</span>: <span class=\"pl-c1\">str</span> <span class=\"pl-k\">=</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>FastAPI<span class=\"pl-pds\">\"</span></span>,\n        <span class=\"pl-smi\">description</span>: <span class=\"pl-c1\">str</span> <span class=\"pl-k\">=</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"\"</span></span>,\n        <span class=\"pl-smi\">version</span>: <span class=\"pl-c1\">str</span> <span class=\"pl-k\">=</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>0.1.0<span class=\"pl-pds\">\"</span></span>,\n        <span class=\"pl-smi\">openapi_url</span>: Optional[<span class=\"pl-c1\">str</span>] <span class=\"pl-k\">=</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>/openapi.json<span class=\"pl-pds\">\"</span></span>,\n        <span class=\"pl-smi\">openapi_tags</span>: Optional[List[Dict[<span class=\"pl-c1\">str</span>, Any]]] <span class=\"pl-k\">=</span> <span class=\"pl-c1\">None</span>,\n        <span class=\"pl-smi\">servers</span>: Optional[List[Dict[<span class=\"pl-c1\">str</span>, Union[<span class=\"pl-c1\">str</span>, Any]]]] <span class=\"pl-k\">=</span> <span class=\"pl-c1\">None</span>,\n        <span class=\"pl-smi\">default_response_class</span>: Type[Response] <span class=\"pl-k\">=</span> JSONResponse,\n        <span class=\"pl-smi\">docs_url</span>: Optional[<span class=\"pl-c1\">str</span>] <span class=\"pl-k\">=</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>/docs<span class=\"pl-pds\">\"</span></span>,\n        <span class=\"pl-smi\">redoc_url</span>: Optional[<span class=\"pl-c1\">str</span>] <span class=\"pl-k\">=</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>/redoc<span class=\"pl-pds\">\"</span></span>,\n        <span class=\"pl-smi\">swagger_ui_oauth2_redirect_url</span>: Optional[<span class=\"pl-c1\">str</span>] <span class=\"pl-k\">=</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>/docs/oauth2-redirect<span class=\"pl-pds\">\"</span></span>,\n        <span class=\"pl-smi\">swagger_ui_init_oauth</span>: Optional[<span class=\"pl-c1\">dict</span>] <span class=\"pl-k\">=</span> <span class=\"pl-c1\">None</span>,\n        <span class=\"pl-smi\">middleware</span>: Sequence[Middleware] <span class=\"pl-k\">=</span> <span class=\"pl-c1\">None</span>,\n        <span class=\"pl-smi\">exception_handlers</span>: Dict[Union[<span class=\"pl-c1\">int</span>, Type[<span class=\"pl-c1\">Exception</span>]], Callable] <span class=\"pl-k\">=</span> <span class=\"pl-c1\">None</span>,\n        <span class=\"pl-smi\">on_startup</span>: Sequence[Callable] <span class=\"pl-k\">=</span> <span class=\"pl-c1\">None</span>,\n        <span class=\"pl-smi\">on_shutdown</span>: Sequence[Callable] <span class=\"pl-k\">=</span> <span class=\"pl-c1\">None</span>,\n        <span class=\"pl-smi\">openapi_prefix</span>: <span class=\"pl-c1\">str</span> <span class=\"pl-k\">=</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"\"</span></span>,\n        <span class=\"pl-smi\">root_path</span>: <span class=\"pl-c1\">str</span> <span class=\"pl-k\">=</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"\"</span></span>,\n        <span class=\"pl-k\">**</span><span class=\"pl-smi\">extra</span>: Dict[<span class=\"pl-c1\">str</span>, Any],\n    ) -> <span class=\"pl-c1\">None</span>: <span class=\"pl-c1\">...</span>\n</code></pre>\n<p><code>routes</code>, <code>middleware</code>, <code>exception_handlers</code>, <code>on_startup</code>, <code>on_shutdown</code> should be 'Optional', and types of <code>swagger_ui_init_oauth</code>, <code>exception_handlers</code>, <code>on_startup</code>, <code>on_shutdown</code> are inaccurate.</p>\n<p>It is 2020 and sadly the only mainstream dynamic programming language with a community which treats typing seriously is JavaScript.</p>\n<p>Date: <a id=\"1593707744\" href=\"https://mmap.page/log/#1593707744\">1593707744</a></p>\n<p>Recently I watched <a href=\"https://youtu.be/fzLz3LBMHz4\">Openbook 2019 talk by Audrey Tang on YouTube</a>. The talk is given in Chinese and here is some notes I have taken.</p>\n<h2>Assistant Intelligence</h2>\n<p>Audrey regards AI as Assistant Intelligence instead of Artificial Intelligence.</p>\n<h2>Reading</h2>\n<p>Audrey finds the following reading methods help her to understand the content:</p>\n<ol>\n<li>Translation or abstract translation.</li>\n<li>Taking notes and doodling with pens.</li>\n</ol>\n<p>When not having a pen at hand, Audrey will scan the book or pdf quickly (about 0.2s per page). Then she will rest for a while, maybe drinking some tea, and \"review\" those pages in mind with her eyes closed. If something occurred to her, she will note them down.</p>\n<p>When having a lot of materials to read, she will quickly scan them before sleep, and absorb them in sleep. She found out an 8 hour sleep can absorb around 400 pages of material.</p>\n<p>Audrey did most of her reading  on an iPad Pro (with a pen).\nShe uses the kindle app for iPad, but she converts all books she bought from different channels using calibre.</p>\n<h2>Emoji as a universal language</h2>\n<p>Audrey thinks emoji is a more universal language than English.</p>\n<p>However, I think while it is cool to <a href=\"https://speakerdeck.com/audreyt/reinventing-democracy\">making slides in pictures and emoji</a>. It is difficult to express complex ideas only with emoji. For example, can you <a href=\"https://paper.dropbox.com/doc/Reinventing-Democracy-EbWGsC1m7MTUqaxNNAmdC\">guess what these slides mean</a>?</p>\n<h2>Humor over Rumor</h2>\n<p>Audrey introduces the disinformation definition in Taiwan: intentional harmful untruth (harmful to the public). To counter disinformation, clarification need to take a humorous form, to become a meme spreading faster and wider than the disinformation. Also, humor helps to counter the irrational anger which motivates people to spread the disinformation.</p>\n<h2>iCloud</h2>\n<p>Unfortunately, although Audrey is a <a href=\"https://sandstorm.io/about\">key sponsor</a> of <a href=\"https://sandstorm.io/\">sandstorm</a> (self hosted platform for open source applications), and introduces sandstorm to Taiwan government, she herself still relies on iCloud to sync personal files.</p>\n<p>Date: <a id=\"1592234620\" href=\"https://mmap.page/log/#1592234620\">1592234620</a></p>\n<p>Go is influenced by Python. Now Go also influences Python, e.g. black (<code>go fmt</code>) and pytest (<code>go test</code>).</p>\n<p>Date: <a id=\"1591974550\" href=\"https://mmap.page/log/#1591974550\">1591974550</a></p>\n<p>It's  2020, and twitter &#x26; github still do not support IPv6.</p>\n<p>Date: <a id=\"1590256273\" href=\"https://mmap.page/log/#1590256273\">1590256273</a></p>\n<p>Go 1.14 allows <a href=\"https://github.com/golang/proposal/blob/master/design/6977-overlapping-interfaces.md\">embedding interfaces with identical method names</a>, as long as these methods have <strong>identical signatures</strong>.</p>\n<p>Again, Go avoided to attack the function subtyping problem.</p>\n<p>Date: <a id=\"1589983584\" href=\"https://mmap.page/log/#1589983584\">1589983584</a></p>\n<p>I though TED talks are amazing. Recently I listened a lot of TED talks and found out that TED talks on average are <em>not</em> interesting to me. Previously I have only listened popular TED talks shared on social networks where I only follow people I find interesting. That's why I had this wrong impression.</p>\n<p>Date: <a id=\"1589462469\" href=\"https://mmap.page/log/#1589462469\">1589462469</a></p>\n<p><a href=\"https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions#using-a-specific-shell\">GitHub action/workflow</a> offers these shells: cmd, sh, bash, power shell, and <strong>python</strong>.</p>\n<p>Date: <a id=\"1587833983\" href=\"https://mmap.page/log/#1587833983\">1587833983</a></p>\n<p><a href=\"https://github.com/rime/home/wiki/ComboPinyin\">Combo Pinyin</a> is an interesting Chinese input method, which is similar to chord-typing (pressing multiple keys at the same time to input a character). However, I find it difficult to type. For example, to type guang, I have to type five keys (F-U-K-L-SPC) at the same time, which is very difficult to my fingers.</p>\n<p>Date: <a id=\"1586705014\" href=\"https://mmap.page/log/#1586705014\">1586705014</a></p>\n<p>Haven't checked the RSS reader for two or three years. The RSS reader reported that about fifty RSS feeds are unreachable. By clicking the htmlUrl and googling author name and old post content, I managed to recover 17 blogs.</p>\n<p>Date: <a id=\"1586682753\" href=\"https://mmap.page/log/#1586682753\">1586682753</a></p>\n<p>The opening of Stanford's CS106A is full of propaganda and buzzwords <a href=\"http://web.stanford.edu/class/cs106a/lectures/1-Welcome/1-Welcome.pdf\">http://web.stanford.edu/class/cs106a/lectures/1-Welcome/1-Welcome.pdf</a></p>\n<p>Date: <a id=\"1585413708\" href=\"https://mmap.page/log/#1585413708\">1585413708</a></p>\n<p>Just discovered this in <a href=\"https://sentry.io/terms/\">Sentry's ToS</a>:</p>\n<blockquote>\n<ol start=\"5\">\n<li>Restrictions\n... you may not: ...  (e) build a competitive product or service, or copy any features or functions of the Site or the Services</li>\n</ol>\n</blockquote>\n<p>Date: <a id=\"1584724995\" href=\"https://mmap.page/log/#1584724995\">1584724995</a></p>\n<p>The new MacBook Air has the best keyboard in current Apple laptops: scissor mechanism without touchbar.</p>\n<p>Date: <a id=\"1583945292\" href=\"https://mmap.page/log/#1583945292\">1583945292</a></p>\n<p>On Apple laptops released in recent years, every key is a power button, and there is NO WAY to turn it off.</p>\n<p>Date: <a id=\"1579713423\" href=\"https://mmap.page/log/#1579713423\">1579713423</a></p>\n<p>golint is very noisy, and it gives a lot of false positive results. I just switched to the peaceful <code>staticcheck</code> instead.</p>\n<p>Date: <a id=\"1579531891\" href=\"https://mmap.page/log/#1579531891\">1579531891</a></p>\n<ol>\n<li>Open your browser, click <code>ctrl+L</code> to focus on address bar.</li>\n<li>Type <code>data:,anything you plan to do</code> (data and semicolon and comma)</li>\n<li>Click <code>ctrl+D</code> to bookmark it.</li>\n</ol>\n<p>That't it. A todo manager with browser bookmarks.\nYou can use folders to organize your todos (projects or lists).\nAnd todos can be exported as an HTML file, or get synced with multiple devices (e.g. you can check your todos on the browser of your mobile device).</p>\n<p>Bonus: If you need to input non-ascii characters, type <code>data:text/plain;charset=UTF-8,any content</code> instead.</p>\n<p>Date: <a id=\"1578822251\" href=\"https://mmap.page/log/#1578822251\">1578822251</a></p>\n<p>I am a bit uncertain about the future of JetBrains. They put a lot of efforts to ship great IDEs. But new languages are very serious about tooling and development productivity to attract more users. vscode has greater out of box support for TypeScript than WebStrom. And the Rust extension of vscode is developed by the IDE and editors team of the Rust language people (yes, they have a dedicated team for this).</p>\n<p>There is a conflict of interest for JetBrains. For new languages, language sever is the way to go. It is very difficult for JetBrains to develop an alternative competitive code intelligence system, particularly when new languages like TypeScript and Rust are evolving very fast. So the only choice of JetBrains is to embrace the language sever. But language server is neutral to all editors and IDEs, thus it will not give JetBrains any advantage. And to earn money from those \"professional\" versions, JetBrains may deliberately remove features from free versions. For example, <a href=\"https://areweideyet.com/#intellij\">debugger and profiler for Rust are only available in their nonfree CLion IDE</a>.</p>\n<p>The same thing happens to JetBrains' own language, Kotlin. Android Studio/IntelliJ have greatest support for Kotlin, and Eclipse have decent support for Kotlin. But JetBrains people are not willing to support other editors or develop a language server. There is a conflict of interest: to attract more developers to use Kotlin, they need to support more IDEs and editors, while to attract more developers to use their IDEs, they'd better only support their own IDEs.</p>\n<p>JetBrains IDEs still have the state of art IDEs for languages such as Java, Python, Go. But their language servers may catch up in future, puting JetBrains IDEs in an awkward situation.</p>\n<p>Date: <a id=\"1578668352\" href=\"https://mmap.page/log/#1578668352\">1578668352</a></p>\n<p>json-diff hung for one day to compare two big json files (~100 MB in file size, and ~40 k objects), while jsondiffpatch finished the comparison in less  than 20 seconds.</p>\n<p>Date: <a id=\"1578571754\" href=\"https://mmap.page/log/#1578571754\">1578571754</a></p>\n<p><a href=\"https://bellard.org/\">bellard.org</a> still uses html 4, as <a href=\"https://www.debian.org/\">debian.org</a> and <a href=\"http://www.netbsd.org/\">netbsd.org</a> does. They have an attitude.</p>\n<p>Date: <a id=\"1577539856\" href=\"https://mmap.page/log/#1577539856\">1577539856</a></p>\n<p>It seems that the story writer of MonsterMatch need to learn more physics.\n<picture><source srcset=\"/log/1577540089.avif\" type=\"image/avif\"><img src=\"https://mmap.page/log/1577540089.jpg\" alt=\"attached image\" width=\"430\" height=\"700\"></picture></p>\n<p>Date: <a id=\"1576460554\" href=\"https://mmap.page/log/#1576460554\">1576460554</a></p>\n<p>Firefox Notes does not support markdown. It only captures some key presses like <code># h1</code> to mimic Markdown but directly pasting <code># h1</code> does not work (Yes, the browser distinguishes key press event and text input event). Also there is only three levels of heading.  And the worst thing is it does not support code block! :-(</p>\n<p>Date: <a id=\"1576408762\" href=\"https://mmap.page/log/#1576408762\">1576408762</a></p>\n<p>I am not a fan of uniformed code formatting (like <code>gofmt</code>). I do not think issues like CamlCase v.s. snake_case or spaces are important. But I myself use <a href=\"https://prettier.io/\">Prettier</a> because I am too lazy to type tabs and semicolons. :-)</p>\n<p>Date: <a id=\"1576330994\" href=\"https://mmap.page/log/#1576330994\">1576330994</a></p>\n<p>The three most popular style guides in JavaScript community (airbnb, standard, google) are all unnecessarily lengthy.</p>\n<p>For example, they all contain a lot of rules on spacing. Is spacing that important? If so, why not just use prettier? If not, why bother to list them in a style guide?</p>\n<p>Another example is they all tell you to write <code>let arr = [];</code> instead of <code>let arr = new Array()</code>. I personally tend to write <code>[]</code> but if a <del>Java</del> developer writes <code>new Array()</code> instead, what's wrong with that? It is totally harmless.</p>\n<p>Style guides should keep focus on a dozen of matters truly important, in other words, pitfalls of JavaScript design, e.g. using <code>===</code> instead of <code>==</code>.</p>\n<p>Date: <a id=\"1575704213\" href=\"https://mmap.page/log/#1575704213\">1575704213</a></p>\n<p>Years ago I noticed that WebStorm (2016.3) was very slow to detect type errors with Flow, while vscode (with vscode-flow-ide extension) checked error on saving file instantly.</p>\n<p>Today I found out that <code>// @ts-check</code> against JSDoc comments works out of box with vscode, while WebStorm (2019.3) cannot recognize <code>@template</code> with <code>@typedef</code>.</p>\n<p>This is yet another example that WebStrom is becoming more and more less relevant in JavaScript development these years.</p>\n<p>Date: <a id=\"1575554930\" href=\"https://mmap.page/log/#1575554930\">1575554930</a></p>\n<p>On December 14, 2019, all yahoo groups become private (based on Yahoo Mails), the yahoo groups website will be shutdown and <strong>all yahoo groups content will be deleted</strong>!</p>\n<p>Date: <a id=\"1575553715\" href=\"https://mmap.page/log/#1575553715\">1575553715</a></p>\n<p>Just downloaded my Translator Toolkit data via Google Takeout. Google Translator Toolkit was shutdown on December 4, 2019. Yet another good service I used to be shutdown by Google.</p>\n<p>Date: <a id=\"1575549745\" href=\"https://mmap.page/log/#1575549745\">1575549745</a></p>\n<p>The ancient Chinese saying \"steal the whole country and they make you a prince, steal a hook and they hang you\" (竊國者侯，竊鉤者誅) probably describes integer overflow. In a system people with a positive sin value will be punished and those with a negative sin value will be rewarded, one who stole the whole country gained a lot of sin value, causing a sin value overflow.</p>\n<p>Date: <a id=\"1574582537\" href=\"https://mmap.page/log/#1574582537\">1574582537</a></p>\n<p>React components and hooks are just functions, nothing magical:</p>\n<pre><code class=\"language-js\"><span class=\"pl-k\">const</span> <span class=\"pl-c1\">SimpleReact</span> <span class=\"pl-k\">=</span> (<span class=\"pl-k\">function</span>() {\n    <span class=\"pl-k\">let</span> state\n    <span class=\"pl-k\">return</span> {\n      <span class=\"pl-en\">render</span>(<span class=\"pl-smi\">Component</span>) {\n        <span class=\"pl-k\">const</span> <span class=\"pl-c1\">C</span> <span class=\"pl-k\">=</span> <span class=\"pl-en\">Component</span>()\n        <span class=\"pl-c1\">C</span>.<span class=\"pl-en\">render</span>()\n        <span class=\"pl-k\">return</span> <span class=\"pl-c1\">C</span>\n      },\n      <span class=\"pl-en\">useState</span>(<span class=\"pl-smi\">initialValue</span>) {\n        state <span class=\"pl-k\">=</span> state <span class=\"pl-k\">||</span> initialValue\n        <span class=\"pl-k\">function</span> <span class=\"pl-en\">setState</span>(<span class=\"pl-smi\">newValue</span>) {\n          state <span class=\"pl-k\">=</span> newValue\n        }\n        <span class=\"pl-k\">return</span> [state, setState]\n      }\n    }\n})()\n\n<span class=\"pl-k\">const</span> <span class=\"pl-c1\">useState</span> <span class=\"pl-k\">=</span> <span class=\"pl-smi\">SimpleReact</span>.<span class=\"pl-smi\">useState</span>\n<span class=\"pl-k\">const</span> <span class=\"pl-c1\">render</span> <span class=\"pl-k\">=</span> <span class=\"pl-smi\">SimpleReact</span>.<span class=\"pl-smi\">render</span>\n\n<span class=\"pl-k\">function</span> <span class=\"pl-en\">useCountCharacters</span>(<span class=\"pl-smi\">str</span>) {\n    <span class=\"pl-k\">const</span> [<span class=\"pl-c1\">text</span>, <span class=\"pl-c1\">setText</span>] <span class=\"pl-k\">=</span> <span class=\"pl-en\">useState</span>(str)\n    <span class=\"pl-k\">const</span> <span class=\"pl-c1\">len</span> <span class=\"pl-k\">=</span> <span class=\"pl-smi\">text</span>.<span class=\"pl-c1\">length</span>\n    <span class=\"pl-k\">return</span> [len, setText]\n}\n\n<span class=\"pl-k\">function</span> <span class=\"pl-en\">Component</span>() {\n    <span class=\"pl-k\">const</span> [<span class=\"pl-c1\">len</span>, <span class=\"pl-c1\">setLen</span>] <span class=\"pl-k\">=</span> <span class=\"pl-en\">useCountCharacters</span>(<span class=\"pl-s\"><span class=\"pl-pds\">\"\"</span></span>)\n    <span class=\"pl-k\">return</span> {\n      <span class=\"pl-en\">type</span><span class=\"pl-k\">:</span> <span class=\"pl-smi\">txt</span> <span class=\"pl-k\">=></span> <span class=\"pl-en\">setLen</span>(txt),\n      <span class=\"pl-en\">render</span><span class=\"pl-k\">:</span> () <span class=\"pl-k\">=></span> <span class=\"pl-en\">console</span>.<span class=\"pl-c1\">log</span>({ len })\n    }\n}\n\n<span class=\"pl-k\">let</span> App <span class=\"pl-k\">=</span> <span class=\"pl-en\">render</span>(Component) <span class=\"pl-c\">// { len: 0 }</span>\n<span class=\"pl-smi\">App</span>.<span class=\"pl-c1\">type</span>(<span class=\"pl-s\"><span class=\"pl-pds\">'</span>hello<span class=\"pl-pds\">'</span></span>)\nApp <span class=\"pl-k\">=</span> <span class=\"pl-en\">render</span>(Component) <span class=\"pl-c\">// { len: 5 }</span>\n</code></pre>\n<p>Date: <a id=\"1574526354\" href=\"https://mmap.page/log/#1574526354\">1574526354</a></p>\n<p>Updated the jekyll templates of my personal website to get rid of JavaScript. Now mmap.page on <a href=\"https://mmap.page/\">clearnet</a> and <a href=\"https://mmap.page/16XMwj6YRNqRHWbmSD8oxYUZCKfM1uzwP9/\">zeronet</a> is JavaScript free. ^_^</p>\n<p>If you want to deploy a minimalistic JavaScript free site to GitHub Pages and/or ZeroNet, then you can checkout <a href=\"https://mmap.page/micro-gh-page/\">my Jekyll template</a>.</p>\n<p>Date: <a id=\"1573608922\" href=\"https://mmap.page/log/#1573608922\">1573608922</a></p>\n<p>For parsing simplicity, the existential operator from CoffeeScript turns into something like <code>foo ?? bar()</code>, <code>a?.[1]</code>, and <code>f.(x)</code> in JavaScript (stage 3), to avoid confusion with ternary expression (<code>a ? [b] :c</code>).</p>\n<p>IMO <code>??</code> is acceptable, but <code>a?.[1]</code> is really very ugly. And in fact this reveals a fundamental problem of JavaScript:</p>\n<p>JavaScript sucks. Thus people add more features as workarounds. But people cannot remove features from it (otherwise it may become a bigger tragedy than Python 2/3). So JavaScript still sucks, and becomes more bloated and uglier at the same time.</p>\n<p>Date: <a id=\"1571248232\" href=\"https://mmap.page/log/#1571248232\">1571248232</a></p>\n<p>Just upgrade to 0net-py3:</p>\n<ol>\n<li>Install from source.</li>\n<li>Copy the data directory from my old 0net-py2 directory.</li>\n</ol>\n<p>Seemingly it works fine.</p>\n<p>Date: <a id=\"1569035072\" href=\"https://mmap.page/log/#1569035072\">1569035072</a></p>\n<p>Just discovered the Files app (an android app by Google) is translated to Files Geek (文件极客) in Chinese UI.</p>\n<p>Date: <a id=\"1568989787\" href=\"https://mmap.page/log/#1568989787\">1568989787</a></p>\n<p>Sam Hartman sent the <a href=\"https://lists.debian.org/debian-devel-announce/2019/09/msg00001.html\">Bits from the DPL (August 2019)</a> letter yesterday (Sep 19, 2019). In the letter, Sam talked a lot about the complexity and anxiety on init system diversity within the  Debian project.</p>\n<p>Date: <a id=\"1566392824\" href=\"https://mmap.page/log/#1566392824\">1566392824</a></p>\n<p>BitBucket is <a href=\"https://bitbucket.org/blog/sunsetting-mercurial-support-in-bitbucket\">dropping hg support</a>. This reminds me the time when Macintosh computers dropped PowerPC CPUs.</p>\n<p>Date: <a id=\"1565806393\" href=\"https://mmap.page/log/#1565806393\">1565806393</a></p>\n<p>Just learned a new word \"Xi-ple\" today. To my surprise, this word is ungoogleable.</p>\n<p>Date: <a id=\"1565184664\" href=\"https://mmap.page/log/#1565184664\">1565184664</a></p>\n<p>The IRL podcast by mozilla is not only boring but also burning (it burns RAM very quickly under Firefox).</p>\n<p>Date: <a id=\"1565183145\" href=\"https://mmap.page/log/#1565183145\">1565183145</a></p>\n<p>Touch bar does have some advantages:</p>\n<ol>\n<li>providing context aware UI controls, like buttons, slides, etc</li>\n<li>showing explicitly the state of the button, e.g. the mute/unmute button</li>\n</ol>\n<p>But there is a long way to go:</p>\n<ol>\n<li>The touch bar need to provide more physical like feedback.</li>\n<li>The application need to allow user to configure controls, to keep some common operations in a fixed position, e.g. F5 (refresh) for browsers.</li>\n<li>The application need to pay great attention to design the touch bar controls, to offer a consistent and convenient  UI. For example, in Spark (an email client on Mac OS X), if I click the move button in the toolbar, the popup menu will list suggested folders first. However, if I press the move button on the touch bar, the touch bar just shows the full list (I have to slide for more folders), and the suggested list is missing.</li>\n</ol>\n<p>Date: <a id=\"1564923584\" href=\"https://mmap.page/log/#1564923584\">1564923584</a></p>\n<p>The dark theme of Spark (a mail client on osx) is a disaster. I've to change the setting to \"always use light theme\". The reason is few mail clients (including those Web Clients) have considered dark background in designing default HTML email templates. And it seems that Spark has not implement some smart algorithm to swap colors.</p>\n<p>The old fashioned plain text emails play nicely with dark theme. Another example of simple design is more future proof.</p>\n<p>Date: <a id=\"1564667614\" href=\"https://mmap.page/log/#1564667614\">1564667614</a></p>\n<p>After recent update of KDE Neon, the bluetooth adapter will power off after each hibernation. Unfortunately I need a mouse to turn on the bluetooth in KDE UI, but I use a bluetooth mouse.</p>\n<p>Finally, I found a way to turn on bluetooth via command line (I use a wired keyboard), entering <code>power on</code> in the bluetoothctl shell.</p>\n<pre><code class=\"language-sh\"><span class=\"pl-k\">;</span> bluetoothctl\n[bluetooth]<span class=\"pl-c\"># power on</span>\n[bluetooth]<span class=\"pl-c\"># exit</span>\n</code></pre>\n<p>Date: <a id=\"1564366037\" href=\"https://mmap.page/log/#1564366037\">1564366037</a></p>\n<p>Looks like the development of Ceylon has ceased. The latest commit is on <a href=\"https://github.com/eclipse/ceylon/commit/7e653a1cd0ff54e7b773f92e26af8ba56b85f308\">May 22, 2019</a>, removing words like \"crap\", \"shit\", \"fucked up\" from code comment. And the penultimate commit is on <a href=\"https://github.com/eclipse/ceylon/commit/d3994d6cd120c4df85952cd9432123b413cfd65a\">Feb 11, 2019</a>, fixing the CI build.</p>\n<p>Date: <a id=\"1564208313\" href=\"https://mmap.page/log/#1564208313\">1564208313</a></p>\n<p>The current version of IntelliJ (2019.2) has a built-in sublime keymap. And I once heard a JetBrainer referred to <code>ctrl+shift+a</code> as \"command palette\" (although actually IntelliJ introduced the \"find any action\" feature prior to Sublime). FYI, Micosoft released an extension \"Sublime Text Keymap and Settings Importer\" for vscode on 2016.</p>\n<p>Such an influential editor, Sublime Text.</p>\n<p>Date: <a id=\"1564069796\" href=\"https://mmap.page/log/#1564069796\">1564069796</a></p>\n<p>How I stop using proxy extension in Firefox?</p>\n<ol>\n<li>Use clash. Usually I'd rather add a rule in clash config, instead of switch proxy.</li>\n<li>Occasionally, when I need to switch proxy, I just press alt+home to open the proxy settings, because I have set homepage to <code>chrome://browser/content/preferences/connection.xul</code>.</li>\n</ol>\n<p>Date: <a id=\"1562091224\" href=\"https://mmap.page/log/#1562091224\">1562091224</a></p>\n<p>Future programmers may use different abstractions. Today we can write bytes to a file, and tomorrow we may write to a <a href=\"https://godoc.org/gocloud.dev/blob\">blob</a>. Whether the blob is ultimately a file or some cloud storage service is just implementation details.</p>\n<p>On writing this, it occurred to me that maybe these abstractions are not very different. Afterall, a <em>file</em> itself is quite abstract (e.g. <code>/dev/stderr</code> under Linux).</p>\n<p>Date: <a id=\"1561828723\" href=\"https://mmap.page/log/#1561828723\">1561828723</a></p>\n<p>Just find out that web developer tools of modern browsers (Firefox &#x26; Chrome)  can recognize webpack and typescript. Debugging on the original typescript source is much easier than on the generated JavaScript code.</p>\n<p>Date: <a id=\"1558103099\" href=\"https://mmap.page/log/#1558103099\">1558103099</a></p>\n<p>This patch to the legacy marriage framework just got approved today and will be merged into the <code>release</code> branch very soon! Congratulations! First patch of this kind in Asia!</p>\n<pre><code class=\"language-diff\">     func isMarriable(x Taiwanese, y Taiwanese) bool {\n<span class=\"pl-md\">-      if x.sex == y.sex {</span>\n<span class=\"pl-md\">-        return false</span>\n<span class=\"pl-md\">-      }</span>\n</code></pre>\n<p>Date: <a id=\"1557559590\" href=\"https://mmap.page/log/#1557559590\">1557559590</a></p>\n<p>Do not under stand why Beta users need to accept <a href=\"https://help.github.com/en/articles/github-pre-release-program\">Confidentiality agreement</a> of keeping special information secret. Isn't beta means public? It seems GitHub redefines Beta.</p>\n<p>I sign up for a Beta program because I am an impatient person, not want to wait for the official release. As such an impatient person, I do not bother reading these lengthy and senseless legal terms. I will check it again after it is officially released.</p>\n<p>Date: <a id=\"1557510100\" href=\"https://mmap.page/log/#1557510100\">1557510100</a></p>\n<pre><code class=\"language-python\">first, <span class=\"pl-k\">*</span>rest <span class=\"pl-k\">=</span> [<span class=\"pl-c1\">1</span>, <span class=\"pl-c1\">2</span>, <span class=\"pl-c1\">3</span>]  <span class=\"pl-c\"># first -> 1, rest -> [2, 3]  (1)</span>\n<span class=\"pl-k\">lambda</span> (<span class=\"pl-smi\">x</span>, y): (y, x)  <span class=\"pl-c\"># (2)</span>\n</code></pre>\n<p>Python 3 supports <code>(1)</code> but not <code>(2)</code>, and Python 2 supports <code>(2)</code> but not <code>(1)</code>.</p>\n<p>What a pity! If there is a python version supports both (Python 6?), I can write something like:</p>\n<pre><code class=\"language-python\"><span class=\"pl-k\">lambda</span> (<span class=\"pl-smi\">first</span>, <span class=\"pl-k\">*</span>rest): <span class=\"pl-c1\">...</span>\n</code></pre>\n<p>Date: <a id=\"1557327217\" href=\"https://mmap.page/log/#1557327217\">1557327217</a></p>\n<p>egghand's subtitles are auto generated (at least on some videos I watched), but they are not marked as such confusingly (unlike YouTube).</p>\n<p>Date: <a id=\"1557152038\" href=\"https://mmap.page/log/#1557152038\">1557152038</a></p>\n<p>Just realized that I can look at the bright side of JavaScript's switch structure. JavaScript's switch <strong>statement</strong> is <strong>fall-through</strong>, which sounds like a scream: \"Don't break! Return! Wrap me into a function!\"</p>\n<p>Date: <a id=\"1556967006\" href=\"https://mmap.page/log/#1556967006\">1556967006</a></p>\n<p>To those who dislikes systemd:</p>\n<ol>\n<li>Debian/Ubuntu/Fedora/OpenSUSE: try devuan</li>\n<li>Arch: try Void Linux</li>\n<li>Gentoo: Gentoo uses OpenRC by default</li>\n<li>Slackware:  Slackware is still systemd free</li>\n</ol>\n<p>Date: <a id=\"1556911623\" href=\"https://mmap.page/log/#1556911623\">1556911623</a></p>\n<p>Just watched the <a href=\"https://www.youtube.com/watch?v=o_AIw9bGogo\">The Tragedy of systemd</a>, which I thought is very misleading.</p>\n<p>Particularly, the video tries to justify systemd via connecting it with launchd. But although systemd is inspired by launchd,  launchd is not that bloated as systemd.  Also, besides macOS, iOS also uses launchd. However the video does not explain why Android (nowadays the majority of linux users are Android users) does not use systemd if systemd is as elegant as the video claims.</p>\n<p>And the video also talks about docker and containers, without realizing that containers make systemd irrelevant. On the server side, services are packaged as containers, which are managed by docker, k8s, etc. Technically there is still an init daemon starting the service program inside the container and communicating with <code>docker</code>, but this is somehow implementation detail not interested by developers. And to reduce resource overhaul, a lot of containers use alpine linux as base image, and alpine linux does not use systemd at all. Even if you intend to use Ubuntu or CentOS as base image for your container, Docker recommend you to use <a href=\"https://github.com/krallin/tini-images\">pre-built images with the tini init</a>.</p>\n<p>To be honest, I like neither android, docker, nor systemd. I am not sure the fact that both android and docker are not in favor of systemd makes me more depressive or less depressive.</p>\n<p>Date: <a id=\"1556714968\" href=\"https://mmap.page/log/#1556714968\">1556714968</a></p>\n<p>It seems the Japanese new era is not very welcome yet:</p>\n<ul>\n<li>glibc has a <a href=\"https://github.com/bminor/glibc/commit/466afec30896585b60c2106df7a722a86247c9f3#diff-33e83cd438ad668f1ff09e8680f6bf11\">commit</a> about 30 days ago, but there is no release yet. RHEL 7 and Fedora Stable has backported this about ten days ago. Debian Unstable has backported this about one week ago.</li>\n<li>Firefox Nightly still considers today is in 平成31年.</li>\n<li>Google Chrome Dev welcomes the new era (But only the dev channel, beta and stable still consider today is in 平成31年).</li>\n</ul>\n<p><picture><source srcset=\"/log/1556715169.avif\" type=\"image/avif\"><img src=\"https://mmap.page/log/1556715169.jpg\" alt=\"attached image\" width=\"900\" height=\"382\"></picture></p>\n<p>Date: <a id=\"1556290808\" href=\"https://mmap.page/log/#1556290808\">1556290808</a></p>\n<p>Just came across a <a href=\"https://www.zhihu.com/question/320757143/answer/663749715\">Q&#x26;A</a> on zhihu (a quora clone in CN):</p>\n<blockquote>\n<p>Q: What to do when I encountered a man better than my boyfriend?\nA: Three men living together is pretty good, isn't it?</p>\n</blockquote>\n<p>Brilliant! Never forget to check the presumption under the question first.</p>\n<p>Date: <a id=\"1556210096\" href=\"https://mmap.page/log/#1556210096\">1556210096</a></p>\n<p>React has so many opt-in, legacy, experimental features. Thus I suggest taking a look at ReasonReact first, which has a much smaller API surface. After a glance of ReasonReact, you can probably pick up React quickly by skipping a lot of concepts. I guess this will be faster than learning React directly, particularly when you are already familiar with some static typed functional languages such as OCaml, F#, and Haskell.</p>\n<p>Though I do not suggest diving deep into ReasonReact and actually write code in it, since TypeScript has a far more better ecosystem.</p>\n<p>Date: <a id=\"1555779592\" href=\"https://mmap.page/log/#1555779592\">1555779592</a></p>\n<p>And the first koan of \"Kotlin Koans\" from stepik and JetBrains annoyed me again.</p>\n<p>It requires to write a function returning <code>\"OK\"</code>, given the following hint:</p>\n<pre><code class=\"language-kotlin\"><span class=\"pl-k\">fun</span> <span class=\"pl-en\">start</span>(): <span class=\"pl-c1\">String</span> <span class=\"pl-k\">=</span> <span class=\"pl-en\">TODO</span>()\n</code></pre>\n<p>So easy (sounds familiar?)</p>\n<pre><code class=\"language-kotlin\"><span class=\"pl-k\">fun</span> <span class=\"pl-en\">start</span>(): <span class=\"pl-c1\">String</span> {\n  <span class=\"pl-k\">return</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>OK<span class=\"pl-pds\">\"</span></span>\n}\n</code></pre>\n<p>No, the EduTools plugin does not allow me to delete <code>=</code>!</p>\n<p>So I have to write the expected answer to pass the koan.</p>\n<pre><code class=\"language-kotlin\"><span class=\"pl-k\">fun</span> <span class=\"pl-en\">start</span>(): <span class=\"pl-c1\">String</span> <span class=\"pl-k\">=</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>OK<span class=\"pl-pds\">\"</span></span>\n</code></pre>\n<p>Hmm, stupid auto answer detection system. And I wonder why introduce learners the special single expression function in the very beginning, before the normal and more common used function with block body? A lot of functions are hard, if not impossible, to declare as a single expression function. Besides, learners familiar with other programming languages will pick up the normal function with block body syntax almost immediately. Why burden their progress insanely?</p>\n<p>Date: <a id=\"1555778252\" href=\"https://mmap.page/log/#1555778252\">1555778252</a></p>\n<p>Just tried the first three quizs of <a href=\"https://stepik.org/course/238\">Python introduction course on stepik</a>, which is included in JetBrains' PyCharm Educational (I tried it with the EduTools plugin on IntelliJ).</p>\n<p>The first quiz is:</p>\n<pre><code class=\"language-python\"><span class=\"pl-c1\">print</span>(<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>Hello, world! My name is type your name<span class=\"pl-pds\">\"</span></span>)\n</code></pre>\n<p>So easy.</p>\n<pre><code class=\"language-python\"><span class=\"pl-c1\">print</span>(<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>Hello, world! My name is weakish.<span class=\"pl-pds\">\"</span></span>)\n</code></pre>\n<p>Failed! It turns out that the auto answer detection system thinks it is wired that my name is <code>weakish.</code>! Obviously the first quiz is to teach you just follow the instruction brainlessly. \"My name ...\" starts with a capital character, so it is a sentence. It is reasonable to end a sentence with a period (<code>.</code>), although this will fail the quiz.</p>\n<p>The second quiz introduces comments, without telling the learner comment is used for what.</p>\n<p>And the third quiz introduces variable, but its first line is:</p>\n<pre><code class=\"language-python\">a <span class=\"pl-k\">=</span> b <span class=\"pl-k\">=</span> <span class=\"pl-c1\">2</span>\n</code></pre>\n<p>What? Introducing chained assignment before normal variable assignment (<code>a = 2</code>)?</p>\n<p>Chained assignment is not often used in practice. And I do not think it is necessary to introducing it to beginners.</p>\n<p>In fact it is not only unnecessary, but confusing.</p>\n<p>A beginner may guess that <code>a = b = 2</code> is equivalent to:</p>\n<pre><code class=\"language-python\">a <span class=\"pl-k\">=</span> <span class=\"pl-c1\">2</span>\nb <span class=\"pl-k\">=</span> <span class=\"pl-c1\">2</span>\n</code></pre>\n<p>For a value <code>2</code>, they are indeed equivalent, but:</p>\n<pre><code class=\"language-python\"><span class=\"pl-k\">import</span> random\na <span class=\"pl-k\">=</span> b <span class=\"pl-k\">=</span> random.random()\n</code></pre>\n<p>is not equivalent to:</p>\n<pre><code class=\"language-python\">a <span class=\"pl-k\">=</span> random.random()\nb <span class=\"pl-k\">=</span> random.random()\n</code></pre>\n<p>And programmers from other languages such as C and JavaScript, may think <code>a = b = 2</code> is equivalent to <code>a = (b = 2)</code> where <code>b = 2</code> evaluates to <code>2</code>. But this is not true in Python.</p>\n<p>And the course mentioned nothing about these quirks.</p>\n<p>I guess the author may think <code>a = 2</code> is too boringly obvious to introduce, thus turns to introducing chain assignment directly. No! In fact, considering that in Python variables are reassignable, they are not boring for beginners at all.</p>\n<p>Considering the following lines:</p>\n<pre><code class=\"language-python\">a <span class=\"pl-k\">=</span> <span class=\"pl-c1\">2</span>\na <span class=\"pl-k\">=</span> <span class=\"pl-c1\">3</span>\n</code></pre>\n<p>This is not boring for a beginner. How can <code>a</code> be equal to both <code>2</code> and <code>3</code>? Seems mathematically impossible!</p>\n<p>This is what the author really have to talk about, not chain assignment.</p>\n<p>I myself learned Python via reading the A Byte of Python book years ago. I am not sure if I should recommend it to beginners. Compared to <a href=\"https://htdp.org/\">HtDP</a> for the exotic Scheme language and the outdated <a href=\"https://poignant.guide/\">Why's Guide to Ruby</a>, it is somehow a boring book. And Python's official tutorial is well written. But at least it does not have such flaws.</p>\n<p>Date: <a id=\"1555771622\" href=\"https://mmap.page/log/#1555771622\">1555771622</a></p>\n<p>Just came across a video titled <a href=\"https://www.youtube.com/watch?v=o_AIw9bGogo\">Learn Python Programming Language in 2 Hours</a>.</p>\n<p>The speaker argues that the first reason to use Python is:</p>\n<blockquote>\n<p>Solve complex problems in <strong>less time</strong> and <strong>fewer lines of code</strong></p>\n</blockquote>\n<p>with the following example:</p>\n<pre><code>C# str.Substring(0, 3)\nJavaScript str.substr(0, 3)\nPython str[0:3]\n</code></pre>\n<p>I do not want to talk about technical details like C# 8.0 supports slicing notation (<code>str[0..3]</code>) and <code>substr</code> is a legacy function in JavaScript (use <code>slice</code> instead). What I want to say is that all of the three languages take one line of code to solve the problem, and with a decent editor/IDE, all three lines take equal time to type. Even assuming we all do programming with a basic text editor like Notepad on Windows or Leafpad in Linux, this example still has nothing to do with solving complex problems in less time. This problem is not complex at all. And most time of programming is not spent on typing.</p>\n<p>Currently this video has 411k views, 8.1k upvotes (less than 200 downvotes) on YouTube. I think this is a good example of why learning to code is hard: so many poor and popular teaching materials on Internet.</p>\n<p><picture><source srcset=\"/log/1555771818.avif\" type=\"image/avif\"><img src=\"https://mmap.page/log/1555771818.jpg\" alt=\"attached image\" width=\"900\" height=\"678\"></picture></p>\n<p>Date: <a id=\"1555769700\" href=\"https://mmap.page/log/#1555769700\">1555769700</a></p>\n<p>Android's Messages app does not provide a \"delete all\" function. Fortunately, most popular third-party sms apps all support \"delete all\" or \"select all then delete\", e.g. chompSMS, Handcent Next SMS, Textra.</p>\n<p>Considering the fact that in early versions of Android, the messaging app does have this feature, my conspiracy theory is Google do not like us to delete our SMS, which could be analyzed by Google to build smarter AI and sell more ads.</p>\n<p>Date: <a id=\"1555739252\" href=\"https://mmap.page/log/#1555739252\">1555739252</a></p>\n<p>I <a href=\"https://mmap.page/?Post/12h51ug6CcntU2aiBjhP8Ns2e5VypbWWtv/1GnJD7CXskmG8GywMbTvbP12wneCFW9XzR/1553695047\">complained about</a> Flask's official documentation lacks a dedicated page for REST APIs and suggested to use Flask-RESTful extension instead.</p>\n<p>But without using the extension, it is still possible to learn enough Flask to write your first REST API service in Flask within 30 minutes.</p>\n<ol>\n<li><a href=\"http://flask.pocoo.org/docs/1.0/testing/#testing-json-apis\">The sample code</a> showing how to do REST API and test it.</li>\n<li><a href=\"http://flask.pocoo.org/docs/1.0/quickstart/#variable-rules\">path variable</a></li>\n<li><a href=\"http://flask.pocoo.org/docs/1.0/quickstart/#the-request-object\">request method and parameters</a></li>\n<li><a href=\"http://flask.pocoo.org/docs/1.0/patterns/apierrors/\">implement API exceptions</a></li>\n<li><a href=\"http://flask.pocoo.org/docs/1.0/quickstart/#a-minimal-application\">launch the application</a></li>\n</ol>\n<p>Unfortunately, figuring out these five sections in three chapters (\"quickstart\", \"testing\", \"pattern\") are the relative pieces for a quick start of REST API service already costs me more than 30 minutes. :-(</p>\n<p>Date: <a id=\"1555231105\" href=\"https://mmap.page/log/#1555231105\">1555231105</a></p>\n<p>Most web video player lacks the feature of full browser window. Fortunately, with xrandr under Linux, we can split the physical monitor into multiple virtual monitors.</p>\n<p>For example, given a monitor 1920x1080 (476mm x 268mm) connected as <code>HDMI-1</code>, the following commands will split into two virtual monitors:</p>\n<pre><code class=\"language-sh\">xrandr --setmonitor left 960/254x1080/286+0+0 HDMI-1\nxrandr --setmonitor right 960/254x1080/286+960+0 none\n</code></pre>\n<p>Note that not all window managers respect this setting though. For example, I have no luck with KWin (KDE) and Mutter (Gnome). On the other hand, xfce and openbox do respect this.</p>\n<p>Date: <a id=\"1555097373\" href=\"https://mmap.page/log/#1555097373\">1555097373</a></p>\n<p><a href=\"https://defend.wikileaks.org/2019/04/11/emergency-julian-assange-has-been-arrested/\">https://defend.wikileaks.org/2019/04/11/emergency-julian-assange-has-been-arrested/</a></p>\n<p>Date: <a id=\"1553940393\" href=\"https://mmap.page/log/#1553940393\">1553940393</a></p>\n<p>Briefly tried Manjaro:</p>\n<p>The installation is smooth and it works out of the box.</p>\n<p>But it is problematic with package dependencies:</p>\n<ol>\n<li>The dependencies declaration of Arch package is less rigid, compared to Debian/Fedora/Opensuse, etc.</li>\n<li>New arch packages are postponed to enter Manjaro's repository, which causes missing dependencies.</li>\n</ol>\n<p>Date: <a id=\"1553823420\" href=\"https://mmap.page/log/#1553823420\">1553823420</a></p>\n<p>Recently I learned a new notion (or buzzword, if you prefer), <a href=\"https://en.wikipedia.org/wiki/Edge_computing\">edge computing</a>:</p>\n<blockquote>\n<p>Edge computing brings memory and computing power closer to the location where it is needed.</p>\n</blockquote>\n<p>Hmm, this let me rethink the statement that ZeroNet is uncensored.</p>\n<p>Maybe ZeroNet is not uncensored, instead, it is <em>edge censored</em>.</p>\n<p>Let me cite the definition of censorship from Wikipedia:</p>\n<blockquote>\n<p>Censorship is the suppression of speech, public communication, or other information, on the basis that such material is considered objectionable, harmful, sensitive, or \"inconvenient\".</p>\n</blockquote>\n<p>Such material is objectionable, harmful, sensitive, or \"inconvenient\" to who? To me, the content consumer. So, inspired by the idea of edge computing, the censorship system should bring memory and computing power closer to me, the location where censorship is needed.</p>\n<p>That is what ZeroNet does, <strong>edge censorship</strong>. Let the user/client/node/hub decide to mute and ban what content and which content producer.</p>\n<p>Date: <a id=\"1553821959\" href=\"https://mmap.page/log/#1553821959\">1553821959</a></p>\n<p>The download page of Manjaro offers 11 favors, xfce, kde, cinnamon, openbox, awesome, budgie, mate, I3, Architect (text), Deepin, Gnome. And there are tabs (it turns out these are actually pretended checkboxes) like \"beginner-friendly\", \"resource-efficient\", \"traditionally-workflow\".</p>\n<p>I clicked the \"resource-efficient\" tab, and there are 10 favors. In other words, only Gnome is considered as resource inefficient!</p>\n<p>So, according to Manjaro, all Linux Graphical Desktop Environments are efficient (and none Graphical Desktop Environment is also efficient, of course), except for Gnome.</p>\n<p>This must be joking.</p>\n<p>(I used KDE for two or three years and haven't used recent versions of Gnome, so I am unsure if Gnome is resource inefficient nowadays. If it is, then the resource inefficient Gnome is joking; if it is not, then Manjaro is making a joke about Gnome. That's why this must be joking. ;-)</p>\n<p>Date: <a id=\"1553794194\" href=\"https://mmap.page/log/#1553794194\">1553794194</a></p>\n<p>manjaro's advertise for developers features Godot, KDevelop, Geany.</p>\n<p>solus's advertise for developers features Atom, Idea, GNOME Builder, Qt Creator, Visual Studio Code.</p>\n<p>Seems there are two different groups of developers under Linux desktop.</p>\n<p>Date: <a id=\"1553694861\" href=\"https://mmap.page/log/#1553694861\">1553694861</a></p>\n<p>Although Flask is widely used to build REST API servers, <a href=\"http://flask.pocoo.org/docs/1.0/\">its official documentation</a> still cannot afford a dedicated page for REST APIs.</p>\n<p>I recommend go direct to check <a href=\"https://flask-restful.readthedocs.io/en/latest/quickstart.html#full-example\">the full example of the  quick start guide</a> of Flask-RESTful extension. Take a look at the code example and start coding within 15 minutes.</p>\n<p>Life is short. Pick up tools and libraries fast.</p>\n<p>Date: <a id=\"1553439182\" href=\"https://mmap.page/log/#1553439182\">1553439182</a></p>\n<p>With the <a href=\"https://github.com/Microsoft/pyright\">pyright</a> extension, vscode can check type annotations of Python code.</p>\n<p>Date: <a id=\"1553407876\" href=\"https://mmap.page/log/#1553407876\">1553407876</a></p>\n<p>Finally gandi.net added support for <code>ALIAS</code>.</p>\n<p>Date: <a id=\"1552832899\" href=\"https://mmap.page/log/#1552832899\">1552832899</a></p>\n<p>Just read an insightful blog post by <a href=\"https://staltz.com/\">André Staltz</a> talking about <a href=\"https://staltz.com/the-web-began-dying-in-2014-heres-how.html\">the dying web</a> replaced by the GOOG-FB-AMZN Trinet.</p>\n<p>Actually the web is dying faster in China, where FB = Tencent, AMZN = Ali. Baidu tries to follow Google's strategy, shifting from a search oriented company to an AI oriented one. But apparently it is a failure.</p>\n<p>Reasons why web is dying faster in China:</p>\n<ol>\n<li>As a developing country, mobile phones are the only devices to connect to Internet for a lot of people. And a lot of people first go online through mobile applications. And most likely these mobile applications are directly owned by Tencent or Ali, or by companies controlled by Tencent or Ali.</li>\n<li>Mobile payment is far more ubiquitous in China. (Unsurprisingly, the two most popular mobile payment methods are Ali's Alipay and Tencent's WeChat Pay.)</li>\n<li>Both Tencent and Ali make their products very inconvenient to use on the web, lacking a lot of important features. They force user to use the mobile application instead. And there is no  regulation preventing them to do so.</li>\n<li>On the other side, regulation requires every user to bind a mobile phone number to use every web service.</li>\n<li>And obviously the authority dislike the open and free web. It is inconvenient and somehow dangerous to host an ordinary website. Want to host a forum? Even harder. Want to host a video site? No way! (Well, technically it is possible if you are a giant company or have strong connections with government.)</li>\n</ol>\n<p>Date: <a id=\"1552746926\" href=\"https://mmap.page/log/#1552746926\">1552746926</a></p>\n<p>In golden old days, a simple web page has an index.html, linking to an index.js. I can just open the index.html in a web browser to see the effect. And after some edits of index.html or index.js, I just refresh the page to see the effect. Once I am satisfied, I can copy the directory to any static hosting space.</p>\n<p>Nowadays, a simple web application has an index.html, liking to an index.js, which may import a lot of npm packages. Assuming these npm dependencies are already fulfilled (via <code>npm install --save</code>), <a href=\"https://parceljs.org/\">parcel</a> bring me back to the golden old time:</p>\n<pre><code class=\"language-sh\">parcel index.html\n</code></pre>\n<p>Then I can just check the effect at <a href=\"http://localhost:1234/\">http://localhost:1234/</a>. And once I made an edit to index.html or index.js, it will get rebuilt and refresh automatically.</p>\n<p>Once the development is done, I just run <code>parcel build index.html</code>, then deploy/copy the <code>dist/</code> directory to any static hosting space.</p>\n<p>And if I get bored, I can replace index.js with index.ts, and start coding in TypeScript. This works out of box with parcel. This also applies to CoffeeScript, or Elm, or even Rust (via WebAssembly).</p>\n<p>None of webpack, browserify, and rollup is as zero configuration as parcel.</p>\n<p>Date: <a id=\"1552723275\" href=\"https://mmap.page/log/#1552723275\">1552723275</a></p>\n<p>Hmm, just noticed that <a href=\"https://www.w3.org/\">w3.org</a> still uses \"old-fashioned\" XHTML 1.0 Strict.</p>\n<p>Date: <a id=\"1552206417\" href=\"https://mmap.page/log/#1552206417\">1552206417</a></p>\n<p>Saw this piece of Go code when watching <a href=\"https://www.youtube.com/watch?v=yszygk1cpEc\">Advanced Testing With Go</a> by Mitchell Hashimoto:</p>\n<pre><code class=\"language-go\"><span class=\"pl-k\">func</span> <span class=\"pl-en\">testChdir</span>(<span class=\"pl-v\">t</span> *<span class=\"pl-v\">testing</span>.<span class=\"pl-v\">T</span>, <span class=\"pl-v\">dir</span> <span class=\"pl-v\">string</span>) <span class=\"pl-v\">func</span>() {\n  <span class=\"pl-smi\">old</span>, <span class=\"pl-smi\">err</span> <span class=\"pl-k\">:=</span> os.<span class=\"pl-c1\">Getwd</span>()\n  <span class=\"pl-c\">// change directory and handle potential errors</span>\n  <span class=\"pl-k\">return</span> <span class=\"pl-c1\">func</span>() { os.<span class=\"pl-c1\">Chdir</span>(old) }\n}\n\n<span class=\"pl-k\">func</span> <span class=\"pl-en\">TestThing</span>(<span class=\"pl-v\">t</span> *<span class=\"pl-v\">testing</span>.<span class=\"pl-v\">T</span>) {\n  <span class=\"pl-k\">defer</span> <span class=\"pl-c1\">testChdir</span>(t, <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>/other<span class=\"pl-pds\">\"</span></span>)()\n  <span class=\"pl-c\">// ...</span>\n}\n</code></pre>\n<p><code>defer testChdir(t, \"/other\")()</code> is a clever trick:</p>\n<ol>\n<li><code>defer</code> got <code>testChdir(t, \"/other\")()</code>, and to figure out what to register, <code>testChdir(t, \"/other\")</code> got evaluated. This let side effects contained in <code>testChdir</code> executed now.</li>\n<li>After the evaluation, <code>defer</code> registered the anonymous function <code>testChdir</code> returns, whose execution will be deferred.</li>\n</ol>\n<p>Just one line, brief and clever. But I think this is too brief and too clever.</p>\n<p>A quick google revealed that someone else already pointed out this pattern (<code>defer db.connect()()</code>) as <a href=\"https://blog.learngoprogramming.com/gotchas-of-defer-in-go-1-8d070894cb01\">bad practice</a>. Besides, they also listed <a href=\"https://blog.learngoprogramming.com/5-gotchas-of-defer-in-go-golang-part-ii-cc550f6ad9aa\">other</a> 14 <a href=\"https://blog.learngoprogramming.com/5-gotchas-of-defer-in-go-golang-part-iii-36a1ab3d6ef1\">gotchas</a> of <code>defer</code>.</p>\n<p>This makes me wondering whether the benefit of introducing <code>defer</code> justify its confusion and complexity.</p>\n<p>BTW, another reason that <code>defer testChdir(t, \"/other\")()</code> smells to me is it is error-prone. What if forget to type <code>()</code>? After all, <code>defer f()</code> looks quite innocent during a code review.</p>\n<p>The 15 gotchas author suggested an alternative style, which is clearer and less error-prone:</p>\n<pre><code class=\"language-go\"><span class=\"pl-smi\">close</span> <span class=\"pl-k\">:=</span> db.<span class=\"pl-c1\">connect</span>()\n<span class=\"pl-k\">defer</span> <span class=\"pl-c1\">close</span>()\n</code></pre>\n<p>But I do not feel nature that <code>connect()</code> should return a function on how to closing it. Thus I prefer the dumb way:</p>\n<pre><code class=\"language-go\">db.<span class=\"pl-c1\">connect</span>()\n<span class=\"pl-k\">defer</span> db.<span class=\"pl-c1\">close</span>()\n</code></pre>\n<p>Date: <a id=\"1552110906\" href=\"https://mmap.page/log/#1552110906\">1552110906</a></p>\n<p>GraalVM's native image feature is impressive to me:</p>\n<pre><code class=\"language-sh\"><span class=\"pl-k\">;</span> du -sh default<span class=\"pl-k\">*</span>\n11M     default  <span class=\"pl-c\"># stand alone</span>\n2.8M    default.jar <span class=\"pl-c\"># not counting the size of JVM</span>\n<span class=\"pl-k\">;</span> bench <span class=\"pl-s\"><span class=\"pl-pds\">'</span>/usr/bin/java -jar default.jar<span class=\"pl-pds\">'</span></span> <span class=\"pl-s\"><span class=\"pl-pds\">'</span>./default<span class=\"pl-pds\">'</span></span>\nbenchmarking bench//usr/bin/java -jar default.jar\n<span class=\"pl-k\">time</span>                 118.3 ms   (115.1 ms .. 120.1 ms)\n                     1.000 R²   (0.999 R² .. 1.000 R²)\nmean                 120.4 ms   (119.3 ms .. 122.7 ms)\nstd dev              2.331 ms   (1.086 ms .. 3.812 ms)\nvariance introduced by outliers: 11% (moderately inflated)\n\nbenchmarking bench/./default\n<span class=\"pl-k\">time</span>                 1.512 ms   (1.493 ms .. 1.531 ms)\n                     0.999 R²   (0.999 R² .. 1.000 R²)\nmean                 1.502 ms   (1.495 ms .. 1.511 ms)\nstd dev              26.17 μs   (20.76 μs .. 34.28 μs)\n</code></pre>\n<p>The startup time of a Java program is faster than a Python script, at the same level of Lua and Go.</p>\n<p>Currently GraalVM only supports amd64 linux/osx (there is preview distribution for Windows). No FreeBSD, no arm, etc.</p>\n<p>Also, native image for JVM languages other than Java are primitive. In fact the <code>default.jar</code> above is a Ceylon hello world program (generated via <code>ceylon fat-jar</code>). And the native image is generated from the following command:</p>\n<pre><code class=\"language-sh\">native-image --report-unsupported-elements-at-runtime --static -jar default.jar\n</code></pre>\n<p>(This is undocumented at GraalVM's official documentation. Thanks to <a href=\"https://stackoverflow.com/a/55068578/\">Lucas Werkmeister</a> to supply the command.)</p>\n<p>However, currently this only works for simple Ceylon programs.</p>\n<p>But graal does looks promising to me.</p>\n<p>Date: <a id=\"1552066645\" href=\"https://mmap.page/log/#1552066645\">1552066645</a></p>\n<p>I read the first 4 items of Effective Java 2nd. edition several years ago, and had an impression that the book better renamed to Ineffective Java. There are 78 items total in the Effective Java 2nd. editon. Today I just learned that Effective Java updated to 3rd. edition on the end of 2017, targeting Java 9 (2nd. edition is target at Java 6). Now there are 90 items in the book. I am wondering does this imply that Java is more ineffective now? Or maybe People have finally discovered far more pitfalls of Java, thus although recent versions of Java fixed some issues, the net known ineffectiveness increases?</p>\n<p>Date: <a id=\"1551619332\" href=\"https://mmap.page/log/#1551619332\">1551619332</a></p>\n<p>Go advertises itself as having first class functions:</p>\n<pre><code class=\"language-go\"><span class=\"pl-k\">return</span> <span class=\"pl-c1\">alternativeImpl</span>(\n    x, y,\n    <span class=\"pl-k\">func</span> (<span class=\"pl-v\">a</span> <span class=\"pl-v\">int</span>, <span class=\"pl-v\">b</span> <span class=\"pl-v\">int</span>) <span class=\"pl-v\">int</span> { <span class=\"pl-k\">return</span> a + b },\n    <span class=\"pl-k\">func</span> (<span class=\"pl-v\">a</span> <span class=\"pl-v\">int64</span>, <span class=\"pl-v\">b</span> <span class=\"pl-v\">int64</span>) <span class=\"pl-v\">int64</span> { <span class=\"pl-k\">return</span> a + b },\n    big.<span class=\"pl-c1\">NewInt</span>(<span class=\"pl-c1\">0</span>).<span class=\"pl-smi\">Add</span>)\n</code></pre>\n<p>With operator function and overloading/generics, this could have been shortened to:</p>\n<pre><code class=\"language-go\"><span class=\"pl-k\">return</span> <span class=\"pl-c1\">alternativeImpl</span>(x, y, +, big.<span class=\"pl-c1\">NewInt</span>(<span class=\"pl-c1\">0</span>).<span class=\"pl-smi\">Add</span>)\n</code></pre>\n<p>BTW:</p>\n<ul>\n<li><code>big.NewInt(0).Add</code> looks wired to me. It is not something like <code>curriedAdd = add 0</code>, but means initialize a big.Int (here <code>0</code> is the empty value on initialization, and Go forces to assign an empty value on initialization) which receives the result of Add.</li>\n<li>GoLand is not very good at analyzing these higher order functions. Sometimes GoLand reported \"No problems found\" but actually the code does not compile.</li>\n</ul>\n<p>Date: <a id=\"1551369924\" href=\"https://mmap.page/log/#1551369924\">1551369924</a></p>\n<p>Currently I'm using a tree based todo manager, roughly something like:</p>\n<pre><code class=\"language-lisp\">[task1\n  [subtask1\n   subtask2\n     subsubtask1\n  ...]]]\n task <span class=\"pl-c1\">2</span>\n ...]\n</code></pre>\n<p>I'm quite satisfied with it for a few months, and found that it is much more expressive than former flat todo managers I've used.</p>\n<p>But today I find out that I need to express something like this:</p>\n<pre><code class=\"language-lisp\">[task1\n  (cond1\n      [subtask1\n       subtask2\n          (cond1.1\n             [subsubtask1\n              subsubtask2]\n             [othersubtask1\n              othersubtask2])\n       subtask3]\n      [othersubtask1\n       othersubtask2\n...\n</code></pre>\n<p>Hmm, tree based todos are cool. But eventually I will need an AST (abstract syntax tree) to manage todos?</p>\n<p>Date: <a id=\"1551194474\" href=\"https://mmap.page/log/#1551194474\">1551194474</a></p>\n<p>Looks like there will be no more compact mobile phones. :-(</p>\n<p>Well, at least there are compact pad (Huawei Mate X) and compact camera/audio player (Sony Xperia 1) in 2019.</p>\n<p>Date: <a id=\"1551031294\" href=\"https://mmap.page/log/#1551031294\">1551031294</a></p>\n<p>小学时候写篇 300 字作文，常常绞尽脑汁，觉得怎么字数还不够啊，现在却为了把豆瓣短评控制在 350 字内大费周章（考虑空格和标点，大概等价于小学时代的 300 字）。</p>\n<p>Alita: Battle Angel (2019) 短评（恰好 350 字）：</p>\n<p>尽管神还原了原作中的许多经典画面，但恰如并不 Scrap 的 Iron City 一般，整部电影明快的调子，完全不同于 Gun Dream 的阴郁风味。强行分明善恶，操作粗暴，改编也有太多草率之处，甚至留下不少漏洞，比如原作中心脏仅为大脑提供养分，所以 Alita 用自己的心连接 Hugo 的头颅情理之中，而电影中将心脏改为发动机，实在让人很难假设它还有一个没交代的提供大脑养分的辅助功能；原作 Grewishka 有赏格，一众猎人只是畏其实力不敢出手，电影改成受上层庇护，那么 Hugo 被工厂通缉时，Alita 本应先质疑工厂是否弄虚作假；最后 Hugo 向上攀爬，电影中 Alita 劝解的话分明是对原作中执念破灭、一心求死的 Hugo 而说，对电影中逃避通缉求生的 Hugo，只需简单交代有防御轮即可。幸赖 CG 视效硬拉上五星，避免本片沦为 Ghost in the Shell 2017 一样的平庸之作。</p>\n<p>Date: <a id=\"1550941813\" href=\"https://mmap.page/log/#1550941813\">1550941813</a></p>\n<p>Google Play Store lacks the \"ignore this update/version of app\" function.</p>\n<p>Date: <a id=\"1550219881\" href=\"https://mmap.page/log/#1550219881\">1550219881</a></p>\n<p>The abandonware nuclide has a distinct feature \"<a href=\"https://nuclide.io/docs/features/remote/\">Remote Development</a>\" (use a remote machine as the workspace for compiling/building and language services via ssh).</p>\n<p>Unfortunately none of Atom, VS Code and JetBrains IDEs has support for this feature yet.</p>\n<p>Date: <a id=\"1549985272\" href=\"https://mmap.page/log/#1549985272\">1549985272</a></p>\n<p>RubyGems has a so-called  <em>twiddle-wakka</em> shortcut <code>~></code>. Therefore, assuming in a semver setup, you can write <code>~> 2.2</code> instead of the verbose <code>['>= 2.2.0', '&#x3C; 3.0']</code>. Seems neat, isn't it?</p>\n<p>However, later Alice reported a bug about the software, and Bob found out that the bug is caused by a bug from the library it depends, which has already be fixed in <code>2.2.2</code>. So Bob changed the dependency to <code>~> 2.2.2</code>. The bug was gone, all tests passed, and everything looked great.</p>\n<p>However, <code>~> 2.2.2</code> is not equivalent to  <code>['>= 2.2.2', '&#x3C; 3.0']</code> (Bob thought so), but <code>['>= 2.2.2', '&#x3C; 2.3.0']</code>!</p>\n<p>Date: <a id=\"1548356219\" href=\"https://mmap.page/log/#1548356219\">1548356219</a></p>\n<p>Recently the term \"headless CMS\" and \"decoupled CMS\" gain a lot of popularity. But these two terms are rather confusing to me.</p>\n<p>To me, \"headless CMS\" sounds like some system mainly intended to be used with <code>curl</code> etc. on command line, like <a href=\"http://ix.io/\">ix.io</a> the headless pastebin. However, obviously most people use the term \"headless CMS\" in a different way.</p>\n<table>\n<thead>\n<tr>\n<th>What people say</th>\n<th>What I would call it</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>headless CMS</td>\n<td>decoupled CMS</td>\n</tr>\n<tr>\n<td>decoupled CMS</td>\n<td>decoupled CMS with default UI and templates</td>\n</tr>\n</tbody>\n</table>\n<p>BTW, I wish the next generation of website will be both frontend agnostic and gateway agnostic. That is, a user of a website can directly access those micro-services. And optionally they may provide some default gateways and/or frontends. Just like a user of a programming library/framework can directly access those low-level functions/classes. And optionally the library/framework may provide some high level APIs and/or examples.</p>\n<p>Date: <a id=\"1547256529\" href=\"https://mmap.page/log/#1547256529\">1547256529</a></p>\n<p>I use <a href=\"https://github.com/jethrokuan/z\">the fish port of z</a> (alternative to autojump) and remap the command name to <code>h</code> (<code>set -U Z_CMD \"h\"</code>). <code>h</code> is easier to type (on dvorak keyboard layout) and remember (\"head to\").</p>\n<p>Date: <a id=\"1544101685\" href=\"https://mmap.page/log/#1544101685\">1544101685</a></p>\n<p>Wrote a simple script (<a href=\"https://github.com/weakish/zerome2md\">zerome2md</a>) to dump ZeroMe posts to a markdown file (for backup or publish eleswhere).</p>\n<p>Images are supported. Comments are not supported yet (patch welcome).</p>\n<p>The \"exported\" markdown file can be consumed by static site builders like Jekyll, e.g. a static mirror of my ZeroMe posts on clearnet: <a href=\"https://mmap.page/log/\">mmap.page/log/</a></p>\n<p>Date: <a id=\"1543935924\" href=\"https://mmap.page/log/#1543935924\">1543935924</a></p>\n<p>The image support of ZeroMe feels quite hacky to me:</p>\n<pre><code class=\"language-json\">{\n  <span class=\"pl-ent\">\"post_id\"</span>: <span class=\"pl-ii\">...,</span>\n  <span class=\"pl-ent\">\"body\"</span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>...<span class=\"pl-pds\">\"</span></span>,\n  <span class=\"pl-ent\">\"date_added\"</span>: <span class=\"pl-ii\">...,</span>\n  <span class=\"pl-ent\">\"meta\"</span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>{<span class=\"pl-cce\">\\\"</span>img<span class=\"pl-cce\">\\\"</span>:<span class=\"pl-cce\">\\\"</span>900,600,bddbaaedafc5ea9db5b85b97eba543766888111965754446,01233014420125671882171769A111BABCDC9BAABB7CEC9DAAAA69AC9AAABBA9FF9BBB<span class=\"pl-cce\">\\\"</span>}<span class=\"pl-pds\">\"</span></span>\n},\n</code></pre>\n<p>Date: <a id=\"1542433791\" href=\"https://mmap.page/log/#1542433791\">1542433791</a></p>\n<p>It is such a surprise for me that GitHub does not have any public available issue tracker for itself!</p>\n<p>Some users have created one (<a href=\"https://github.com/isaacs/github\">isaacs/github</a>). To  use it, you need to open an issue on it and email a copy to  <a href=\"mailto:support@github.com\">support@github.com</a>, then manually post replies from github staff. :-(</p>\n<p>Date: <a id=\"1542433143\" href=\"https://mmap.page/log/#1542433143\">1542433143</a></p>\n<p>Two exotic project ideas occurred to me on the bed. After getting up and turning on the computer, I found out that I had already forgot one of them.</p>\n<p>Date: <a id=\"1542391958\" href=\"https://mmap.page/log/#1542391958\">1542391958</a></p>\n<p>Ansible advertises itself as agent-less, but:</p>\n<ol>\n<li>The agent/client machine still needs to have a (compatible version of) python preinstalled.</li>\n<li>SaltStack supports an equivalent server-only  model (also requiring python). And SaltStack is more flexible since it also supports server-agent  and agent-only models.</li>\n</ol>\n<p>On the other hand, Patchwork (based on fabric) is true agentless (sending shell calls). Its functions is quite limited and it lacks high-level abstractions though.</p>\n<p>BTW, the cloud provider modules from both Ansible and SaltStack are disorderly and unsystematic. Some use cloud providers' SDK, some use libcloud (a unified interface for different cloud APIs), and some directly use requests.</p>\n<p>Date: <a id=\"1542376879\" href=\"https://mmap.page/log/#1542376879\">1542376879</a></p>\n<p>Flickr will limit free users' photos to 1000 (extra photos will get deleted in next year). Upon hearing this I am quite depressed, because downloading photos and uploading to a new platform (provided that I can find an alternative) will take a lot of time and effort.</p>\n<p>Later I learned that flickr will not delete old photos licensed under Creative Commons. Thank goodness! Almost all my photos on flickr are under cc-by-sa or public domain.</p>\n<p>Today I just checked my flickr account and found out that I only have less than five hundreds photos there...</p>\n<p>Date: <a id=\"1541249463\" href=\"https://mmap.page/log/#1541249463\">1541249463</a></p>\n<p>Upgraded KDE Neon from 16.04 to 18.04 today via its built-in \"Distribution Upgrade\" GUI. The whole process is mostly smooth, except it reports a mysterious error \"installArchives() Failed\" before restart. I just ignored it and had not discovered anything wrong.</p>\n<p>The system feels the same, without any dramatic change. I have not noticed any difference until I decided to change the wallpaper:</p>\n<ol>\n<li>Plasma Wallpaper now allows to use Bing's Picture of the Day.</li>\n<li>Plasma Mouse Actions now supports configuring all mouse buttons.</li>\n</ol>\n<p>I used to rebind middle key to forward button (so I can press it via my thumb, instead of clicking the hard-to-press wheel) via <code>xinput set-button-map</code>. I knew I had to add it to my startup script, but because: 1) I am lazy; 2) I seldom restart my computer these days; I did not write it. Now I do not need to write it -- another example of advantage of \"lazy evaluation\". ;-)</p>\n<p>Date: <a id=\"1541247161\" href=\"https://mmap.page/log/#1541247161\">1541247161</a></p>\n<p>IBM bought RedHat as a cloud computing company, thus irrelevant projects originally sponsored by RedHat may not receive bandwidth from IBM in future. Fortunately:</p>\n<ol>\n<li>Ceylon: it begins to migrate to Eclipse last year</li>\n<li>Cygwin: nowadays WSL seems a better option (if I have the opportunity to use Windows in future)</li>\n<li>Gnome: I switched to KDE last year</li>\n</ol>\n<p>Date: <a id=\"1541245426\" href=\"https://mmap.page/log/#1541245426\">1541245426</a></p>\n<p>I've seen a lot of note applications/services' export function does not support exporting attachments. Vivaldi Browser is just another example (its sync all feature does not include attachments of notes).</p>\n<p>Date: <a id=\"1540394823\" href=\"https://mmap.page/log/#1540394823\">1540394823</a></p>\n<p>The new palm phone reveals how ugly big today's phones are.</p>\n<p>3.3-inch, 445-ppi LCD display, 62.5 grams weight, IP68, cool! Type C, Android 8.1, 3GB RAM, 32GB storage, O.K. $349.99, expansive but still acceptable. Verizon Only, ShareNumber only, BAD!</p>\n<p>Photo credit: <a href=\"https://www.theverge.com/2018/10/15/17974850/new-palm-smartphone-android-lifemode-time-well-spent-verizon\">theverge.com</a>\n<picture><source srcset=\"/log/1540394982.avif\" type=\"image/avif\"><img src=\"https://mmap.page/log/1540394982.jpg\" alt=\"attached image\" width=\"900\" height=\"600\"></picture></p>\n<p>Date: <a id=\"1536929070\" href=\"https://mmap.page/log/#1536929070\">1536929070</a></p>\n<p>Oops, <code>python -m SimpleHTTPServer</code> does not support range request.</p>\n<p>The following three lines (not counting import statements etc.) of Go turns out to support range request out of box:</p>\n<pre><code class=\"language-go\"><span class=\"pl-k\">func</span> <span class=\"pl-en\">main</span>() {\n  <span class=\"pl-smi\">err</span> <span class=\"pl-k\">:=</span> http.<span class=\"pl-c1\">ListenAndServe</span>(<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>:8000<span class=\"pl-pds\">\"</span></span>,\n    http.<span class=\"pl-c1\">FileServer</span>(http.<span class=\"pl-c1\">Dir</span>(os.<span class=\"pl-c1\">Getwd</span>())))\n  log.<span class=\"pl-c1\">Fatal</span>(err)\n}\n</code></pre>\n<p>Date: <a id=\"1536759116\" href=\"https://mmap.page/log/#1536759116\">1536759116</a></p>\n<p>Go advertises first-class function, but to pass a function, you have to match the exact signature. No sub-typing of functions. Yes, even Java supports covariant return result (no contravariant parameter though), but Go supports neither.</p>\n<p>Date: <a id=\"1536678777\" href=\"https://mmap.page/log/#1536678777\">1536678777</a></p>\n<p>Programming needs practice. And I think \"how many lines of source code I have <strong>deleted</strong>\" estimates my experience on programming better (than how many lines I have written).</p>\n<p>A shell-fu to calculate how many lines I have deleted in a git repository:</p>\n<pre><code class=\"language-sh\">git log --shortstat --no-merges --author=<span class=\"pl-s\"><span class=\"pl-pds\">$(</span>whoami<span class=\"pl-pds\">)</span></span> <span class=\"pl-k\">|</span> grep <span class=\"pl-s\"><span class=\"pl-pds\">'</span>files\\? changed<span class=\"pl-pds\">'</span></span> <span class=\"pl-k\">|</span> awk <span class=\"pl-s\"><span class=\"pl-pds\">'</span>{deleted+=$6} END {print deleted}<span class=\"pl-pds\">'</span></span>\n</code></pre>\n<p>Date: <a id=\"1535774560\" href=\"https://mmap.page/log/#1535774560\">1535774560</a></p>\n<p>Refactoring with statically typed code (using Python's type hint) is an enjoyable process. To switch an  upstream library, I just replaced one import statement, one type definition, and one invoking statement. Then I just fix all the typing problems reported by PyCharm. After that, I run the program and find out that it just works! No \"find usage\" or \"search and replace\". And the project does not have any test (I am too lazy to write one.) Static typing is the preservative to slow down the inevitable decaying of code.</p>\n<p>Date: <a id=\"1535038856\" href=\"https://mmap.page/log/#1535038856\">1535038856</a></p>\n<p>Gists are second class citizen of GitHub. For example, GitHub API does not support searching gists (in both old v3 REST API and the new v4 GraphQL API).</p>\n<p>Date: <a id=\"1535037615\" href=\"https://mmap.page/log/#1535037615\">1535037615</a></p>\n<p>When will Java have \"real\" function type? What Java uses interface to mimic is <strong>nominal</strong>, not <strong>structural</strong>.</p>\n<p>Date: <a id=\"1534597565\" href=\"https://mmap.page/log/#1534597565\">1534597565</a></p>\n<p>Learning ML/Haskell deepened my understanding of typing.</p>\n<p>Date: <a id=\"1534051076\" href=\"https://mmap.page/log/#1534051076\">1534051076</a></p>\n<p>vscode does not have built-in syntax highlighting for Haskell, while it does support F# out of the box.</p>\n<p>Date: <a id=\"1533967519\" href=\"https://mmap.page/log/#1533967519\">1533967519</a></p>\n<p>Google Photo's \"free up device space\" (delete already backed up photos from device) and recover storage (compress already uploaded photos from original to high quality) applies to ALL photos. I cannot free up / recover storage selectively, for example, only archived photos or photos within certain albums.</p>\n<p>Date: <a id=\"1533955428\" href=\"https://mmap.page/log/#1533955428\">1533955428</a></p>\n<p>Not sure when GitHub changed its front page (they call it dashboard), slow to load. I miss the old GitHub front page, loaded almost instantly.</p>\n<p>Date: <a id=\"1533921116\" href=\"https://mmap.page/log/#1533921116\">1533921116</a></p>\n<p>I want to install an extension of JupyterLab (toc), then I found out that installing JupyterLab extensions requires nodejs (because JupyterLab extensions are npm packages). So I install nodejs via <code>conda</code>, which automatically downgrading my JupyterLab from v0.33 to v0.28. After all of this, I am about to install the extension, but it turns out it requires JupyterLab v0.33! :-( The Jupyter blog said JupyterLab is ready for users on Feb. 2018 ...</p>\n<p>Date: <a id=\"1532952443\" href=\"https://mmap.page/log/#1532952443\">1532952443</a></p>\n<p>Not sure whether BDFL's retirement is good or bad, but personally I dislike PEP 572 (I dislike a lot of aspects of Python, though).</p>\n<p>Date: <a id=\"1532783984\" href=\"https://mmap.page/log/#1532783984\">1532783984</a></p>\n<p>languagedetective.com predicts your native language with English text you wrote as input. I tested with <a href=\"https://weakish.github.io/StutteringTalkaholic/web/html-history/\">one of my blog post</a> and the result is: 70.6% Native, 29.4% Non-Native. Bingo!\nBut it is not good at predicting my native language: 37.9% Arabic, 16.1% Korean, 14.7% Hindi, 11.1% Chinese, 8.6% German, 6.5% Turkish, 2.1% Japanese, 1.6% French, 0.7% Italian, 0.7% Spanish.</p>\n<p>My native language is Chinese.</p>\n<p>Date: <a id=\"1529854155\" href=\"https://mmap.page/log/#1529854155\">1529854155</a></p>\n<p>Suddenly I wanted to eat tempura, but it is unavailable from the menu of the izakaya I went. So I ate some fried salmon sushi instead.</p>\n<p>Date: <a id=\"1529138055\" href=\"https://mmap.page/log/#1529138055\">1529138055</a></p>\n<p>My Razer DeathAdder has blue LED on wheel and logo, feeling very disturbing to me. Thanks to <a href=\"http://bues.ch/cms/hacking/razercfg.html\">razercfg</a>, I can turn them off under Linux.</p>\n<p>(I am not a game player. I bought this mouse just because there are not many left hand mouse available on my area.)</p>\n<p>Date: <a id=\"1528815034\" href=\"https://mmap.page/log/#1528815034\">1528815034</a></p>\n<p>I am really confused with those color modes with monitors. Cannot them show color temperature instead?</p>\n<p>Date: <a id=\"1528733744\" href=\"https://mmap.page/log/#1528733744\">1528733744</a></p>\n<p>How not to waste time on matching socks, i.e. O(1) to pick out socks to wear? Make all socks the same. How?</p>\n<ol>\n<li>Buy only one kind of socks.</li>\n<li>Shift your mind to realize that all socks are the same, regardless of their shapes and colors.</li>\n</ol>\n<p>I myself had shifted my mind and treated all socks equally without discrimination, from the beginning of my undergraduate.</p>\n<p>Date: <a id=\"1528202901\" href=\"https://mmap.page/log/#1528202901\">1528202901</a></p>\n<p>Microsoft is acquiring GitHub. GitHub in fact has an (maybe unintended) use: as a bootstrap mechanism to download tunnel software/tools to bypass firewall. After acquired by Microsoft, I doubt those  tunnel software/tools may be unavailable within the firewall.</p>\n<p>Date: <a id=\"1526298916\" href=\"https://mmap.page/log/#1526298916\">1526298916</a></p>\n<p>Recently I found out that MUJI French Linen shirts/pants have raw (undyed) color for adults.</p>\n<p>Date: <a id=\"1524061534\" href=\"https://mmap.page/log/#1524061534\">1524061534</a></p>\n<p>Just figured out why some people are so excited about Flutter (a mobile framework for Android/iOS in Dart by Google).</p>\n<p>Because Dart's FAQ said \"Isn’t Dart a lot like Java\", thus Dart ~= Java.</p>\n<p>If Dart is counted as Java, then Java becomes an alternative full stack language:</p>\n<ul>\n<li>Node.js (backend) + JavaScript (web) + React Native (mobile)</li>\n<li>Vert.x (backend) + Dart (web) + Flutter (mobile)</li>\n</ul>\n<p>(To me, this is not excited at all, though. ;-)</p>\n<p>Date: <a id=\"1523902414\" href=\"https://mmap.page/log/#1523902414\">1523902414</a></p>\n<blockquote>\n<p>God made a woman from the rib he had taken out of the man (Genesis 2:22)</p>\n</blockquote>\n<p>So heterosexual intercourse is excitation of one's own body part, i.e. self-gratification?</p>\n<p>Date: <a id=\"1523630163\" href=\"https://mmap.page/log/#1523630163\">1523630163</a></p>\n<p>My personal choices to score movies:</p>\n<ol>\n<li>WTF</li>\n<li>I do not want to waste my time on this</li>\n<li>to kill some time</li>\n<li>I probably will not watch it again, but I am not object to</li>\n<li>I will watch it again</li>\n</ol>\n<p>So forgive me for being harsh to a lot of movies,\nI am poor, thus:</p>\n<ul>\n<li>I am busy with earning a living, not having time to watch so many movies;</li>\n<li>I have to limit the money spending on extra movie tickets.</li>\n</ul>\n<p>However, I still watch quite a lot of movies after all.\nThanks to my just the right amount of poverty, I can afford buying movie tickets, and cannot afford some other more expensive forms of entertainment. In fact I am not sure, movie is entertainment to me. Maybe it is rather a form of escaping of the desert of reality? Or, maybe all forms of entertainment are ways of escaping to me?</p>\n<p>Date: <a id=\"1523201921\" href=\"https://mmap.page/log/#1523201921\">1523201921</a></p>\n<p>Both \"<strong>Three</strong> Billboards Outside Ebbing, Missouri\" and \"The <strong>Third</strong> Murder\" talk about the problems of the environment and the feeling of hopelessness, though in distinct (American/Japanese) ways.</p>\n<p>Date: <a id=\"1522629606\" href=\"https://mmap.page/log/#1522629606\">1522629606</a></p>\n<p>Digg Reader was dead at the end of last month (March 2018).</p>\n<p>Date: <a id=\"1522245247\" href=\"https://mmap.page/log/#1522245247\">1522245247</a></p>\n<p>debian.org is not available in CN (not sure whether it has been blocked by the great firewall or just some routing issue).</p>\n<p>Date: <a id=\"1522083867\" href=\"https://mmap.page/log/#1522083867\">1522083867</a></p>\n<p>Almost all smart phones today use a non-removable battery. And most smart phones do not use all-day battery. What an insane design combination!</p>\n<p>Date: <a id=\"1521376411\" href=\"https://mmap.page/log/#1521376411\">1521376411</a></p>\n<p>Saw \"novel blockchain gameplay\" in an elevator ad of a browser game. This reminds me of a time when a lot of products advertise themselves using \"novel nano-meter technology\".</p>\n<p>Date: <a id=\"1521037402\" href=\"https://mmap.page/log/#1521037402\">1521037402</a></p>\n<p>I learnt typing on a typewriter, so membrane keyboards, especially membrane keyboards with short key travel, feel unnatural to me. However, I found out that my fingers are more tired when typing a lot on mechanical keyboards. (Have not tried Topre keyboards.)</p>\n<p>Date: <a id=\"1520956541\" href=\"https://mmap.page/log/#1520956541\">1520956541</a></p>\n<p>One of my favorite poem of Li Ch'ing-chao (李清照) is \"As in a Dream\" (如夢令）.</p>\n<p>Light rain and gusty wind last night. （昨夜雨疏風驟）\nSound sleep did not dispel the slight drunkenness. （濃睡不消殘酒）\nI ask the one rolling up the curtain,　（試問卷簾人）\nbut she answers: \"The cherry-apple trees are the same.\"　（卻道海棠依舊）\n\"Don't you know? Don't you know? The red should languish while the green should plump.\"　（知否，知否，應是綠肥紅瘦）</p>\n<p>(I am a native speaker of Chinese but not a native speaker of English. I tried my best to translate it. Any feedback on translation is welcome.)</p>\n<p>\"The red should languish while the green should plump\" reveals the tenderness of the poet, while \"should\" implies the firmness of the poet.</p>\n<p>\"Don't you know? Don't you know?\" That is the reality distortion field of a groggy poet.</p>\n<p>Date: <a id=\"1520670847\" href=\"https://mmap.page/log/#1520670847\">1520670847</a></p>\n<p>Very pessimistic about mobile phones I would have to buy in future:</p>\n<ul>\n<li>Android: With the recent release of Xperia XZ2 Compact (5\"), Android phones finally stepped into the no more phones under 5\" era.</li>\n<li>GNU/Linux: Librem 5, as its name told, is a 5\" phone.</li>\n<li>iOS: Unfortunately it seems the only choice left, Defective by Design.</li>\n</ul>\n<p>Date: <a id=\"1520617250\" href=\"https://mmap.page/log/#1520617250\">1520617250</a></p>\n<p>Just published my first Firefox extension: <a href=\"https://addons.mozilla.org/en-US/firefox/addon/arxiv-url/\">arxiv-url</a>, a Firefox addon to replace arxiv pdf links to corresponding abstract links.</p>\n<p>Writing a firefox extension is actually easier than I thought. If you'd like to write one yourself, just follow mozilla's <a href=\"http://flask.pocoo.org/docs/1.0/\">doc</a>.</p>\n<p>Note:</p>\n<ol>\n<li>If you do not want to install <code>web-ext</code> (it depends on node and some npm packages) for <code>web-ext build</code>, you can just zip your extension.</li>\n<li>Submit the zip file to  <a href=\"https://addons.mozilla.org/\">AMO</a> directly. No need to <code>web-ext sign</code> it (if you did so, the signature will be replaced with AMO after all.)</li>\n</ol>\n<p>Date: <a id=\"1520607766\" href=\"https://mmap.page/log/#1520607766\">1520607766</a></p>\n<p>Compared to wine and tea, chocolate is inexpensive. The most expensive chocolate I've eaten is Amedei CRU, which is still affordable.</p>\n<p>Date: <a id=\"1519995238\" href=\"https://mmap.page/log/#1519995238\">1519995238</a></p>\n<p>extensiontest.com (test if a chrome extension is compatible with firefox) is not 100% accurate. Just encountered an chrome extension passing extensiontest.com but not usable in Firefox.</p>\n<p>Date: <a id=\"1519744209\" href=\"https://mmap.page/log/#1519744209\">1519744209</a></p>\n<p>Backing up to USB 3 external hard disk with <code>borg create -C lz4</code> is very fast.</p>\n<p>Date: <a id=\"1519205841\" href=\"https://mmap.page/log/#1519205841\">1519205841</a></p>\n<p>Moving one icon on my mobile phone, all icons between the old place and the new place of the moved icon, will shift their places.</p>\n<p>I am really upset by this.</p>\n<p>Image in an insane programming lanuage, there is a list, say,</p>\n<pre><code class=\"language-python\">l <span class=\"pl-k\">=</span> [a, b, c, d, e, f, g]\n</code></pre>\n<p>And when you eval <code>l[0] = l[6]</code>, the list becomes:</p>\n<pre><code class=\"language-python\">l <span class=\"pl-k\">=</span> [g, a, b, c, d, e, f]\n</code></pre>\n<p>What a big surprise!</p>\n<p>In such a programming language, imaging how many statements you have to write to accomplish simple tasks such as swaping <code>a</code> and <code>g</code>.</p>\n<p>On the other side, in any sane programming language, to swap <code>a</code> and <code>g</code>, you just need to write something like:</p>\n<pre><code class=\"language-python\">tmp <span class=\"pl-k\">=</span> l[<span class=\"pl-c1\">0</span>]\nl[<span class=\"pl-c1\">0</span>] <span class=\"pl-k\">=</span> l[<span class=\"pl-c1\">6</span>]\nl[<span class=\"pl-c1\">6</span>] <span class=\"pl-k\">=</span> tmp\n</code></pre>\n<p>That is basically the behavior of desktop shortcuts of old-fashioned desktop operating systems.</p>\n<p>I encountered this design fault on iOS devices before.\nAnd now it infects my Android phone.\n(Not sure whether Android 8.0 or the mobile phone producer introduced this design fault.)</p>\n<p>My workaround: Only put icons most frequently used on the first screen. Put all other icons in folders. And arrange those folders by their names, pretending that they cannot be arranged freely.</p>\n<p>Date: <a id=\"1507309298\" href=\"https://mmap.page/log/#1507309298\">1507309298</a></p>\n<p>Recently I started to read a book during wait time when I had taken a bag with me (a thin book is light and there is no more worries for short of battery), or just let my mind fly away when I had not. A win-win strategy for the life of my neck and the life of mobile phone battery.</p>\n<p>Date: <a id=\"1506863469\" href=\"https://mmap.page/log/#1506863469\">1506863469</a></p>\n<p><a href=\"https://github.com/tutao/tutanota/blob/ea1c1ef1c70c8f3c48dcfaa70f91cd41b7fbdd95/flow/libs.js#L86\">tutanota client side source code</a> contains Flow type definition for Mithril.</p>\n<p>Date: <a id=\"1506253651\" href=\"https://mmap.page/log/#1506253651\">1506253651</a></p>\n<p>Microsoft had suspended my outlook mail account for several weeks , saying my account is used to send a lot of junk mails, or violates their TOS in <em>unspecified</em> way.</p>\n<p>I totally have no idea what violates their TOS (I had not sent mails using this account, let alone junk mails). To unblock my account, I need a cellphone. I am very upset about the assumption that you have to have a cellphone.</p>\n<p>And to get help from Microsoft support for my locked account issue I need to have a working account. This is a deadlock. Thus I decide to stop use Microsoft account.</p>\n<p>Then I asked myself what will happen if the same thing happens to my gmail account? Then I realized the fact that I did not bother set up my own domain for emails put me into danger.</p>\n<p>Date: <a id=\"1505399377\" href=\"https://mmap.page/log/#1505399377\">1505399377</a></p>\n<p>I always prefer a small screen mobile device, which is easier to carry. I do not read/browse/view a lot with the mobile phone, since either neck or shoulders are in an unnatural angle.</p>\n<p>Date: <a id=\"1505298765\" href=\"https://mmap.page/log/#1505298765\">1505298765</a></p>\n<p>iPhone X shows that machine learning can be done on client side, without talking to a remote server. This is encouraging for privacy concerned services and users.</p>\n<p>I am not sure about the long term impact of animoji. Will it make people's  countenance more exaggerated in real life?</p>\n<p>iPhone {X, 8, 8P, 7, 7P, 6S, 6SP, SE}. Consumers need to choose one from <strong>eight</strong> models. Not sure if this is good or bad for consumers, but this is definitely not the Apple way.</p>\n<p>Date: <a id=\"1505198726\" href=\"https://mmap.page/log/#1505198726\">1505198726</a></p>\n<p>I found out that I could not understand some code I wrote 8 months ago.</p>\n<p>Then I checked the git commit message 8 months ago.\nThe commit message said</p>\n<blockquote>\n<p>I hope I implemented the algorithm right.</p>\n</blockquote>\n<p>So this is the fault of the previous version of me myself. If the previous version of me myself truly understood the algorithm, then I would have resumed or reinvented the algorithm quickly now.</p>\n<p>Date: <a id=\"1504997063\" href=\"https://mmap.page/log/#1504997063\">1504997063</a></p>\n<p>Years passed, and Google Contact still does not support exporting contacts. It still redirects me to the \"old version\" for exporting.</p>\n<p>Date: <a id=\"1504960007\" href=\"https://mmap.page/log/#1504960007\">1504960007</a></p>\n<p>I think sometimes a ML/Haskell like syntax may be a better alternative for math notation than lisp. Lisp is unambiguous but slightly harder to type manually (I am too lazy to use the lisp IDE/mode and copy-paste, or extend the editor to support auto completion in code blocks.) Compared to C like syntax, ML/Haskell saves some typing of commas and parenthesis.</p>\n<p>Date: <a id=\"1504847037\" href=\"https://mmap.page/log/#1504847037\">1504847037</a></p>\n<p>The intuition behind Curry-Howard correspondence:</p>\n<ol>\n<li>Staring from propositions (types of parameters),  we construct proof (function) to get other proposition (type of return value).</li>\n<li>The rule to construct proof (function) is called logic (type system).</li>\n<li>It is hard to construct a proof (function). But once the proof (function) has been constructed, it is easy to verify the proof is valid (the function does return the value of specified type).</li>\n</ol>\n<p>Notes:</p>\n<ol>\n<li>In practice, the verification of proof is not always easy, because real word proof tends to omit a lot of implicit knowledge and intermediate steps.</li>\n<li>The verification of returned type of function is so easy that we do not need to verify that manually, the interpreter/compiler will verify that for us automatically.</li>\n<li>The Curry-Howard correspondence is the basis of theorem prover such as Coq.</li>\n</ol>\n<p>Date: <a id=\"1504597757\" href=\"https://mmap.page/log/#1504597757\">1504597757</a></p>\n<p>Baidu Map iOS keeps requesting location on background when location info is not available, draining batteries and heating device very quickly.</p>\n<p>Date: <a id=\"1504540170\" href=\"https://mmap.page/log/#1504540170\">1504540170</a></p>\n<p>Now mail.google.com redirects to <a href=\"http://www.google.com/gmail/about/\">www.google.com/gmail/about/</a>, which has a fancy design. I miss the simple UI with a login form and storage space counter.</p>\n<p>Date: <a id=\"1504422932\" href=\"https://mmap.page/log/#1504422932\">1504422932</a></p>\n<p>To stop EME (Encrypted Media Extension) from entering W3C Standard, FSF asked people to <strong>dial up</strong> Tim Berners-Lee. First, asking people to dial up a person is not protest but <strong>DDOS</strong>. Second, no one cares W3C standard today. If Apple (safari), Google (chrome), Mozilla (firefox) and Microsoft (Edge) were dead-set, then the story is over. Neither W3C nor Tim Berners-Lee can do anything about it. (Fortunately Mozilla is not dead-set on EME, although Firefox Desktop has implemented it years ago.)</p>\n<p>Date: <a id=\"1504338200\" href=\"https://mmap.page/log/#1504338200\">1504338200</a></p>\n<p>MIT scheme taught me a chuunibyou way to say goodbye: \"Moriturus te saluto.\"</p>\n<p>Date: <a id=\"1504276342\" href=\"https://mmap.page/log/#1504276342\">1504276342</a></p>\n<p>Powershell aliases still do not support tab completion.</p>\n<p>Date: <a id=\"1503905257\" href=\"https://mmap.page/log/#1503905257\">1503905257</a></p>\n<p>Finally, concepts such as polymorphism, generics, type variable/parameter, overloading, and type class are united in my brain.</p>\n<p>Date: <a id=\"1503845426\" href=\"https://mmap.page/log/#1503845426\">1503845426</a></p>\n<p>Failed to understand the <code>fmap</code> signature in Haskell in about 15 minutes:</p>\n<pre><code class=\"language-haskell\"><span class=\"pl-k\">class</span> <span class=\"pl-e\">Functor</span> <span class=\"pl-smi\">f</span> <span class=\"pl-k\">where</span>\n    <span class=\"pl-en\">fmap</span> <span class=\"pl-k\">::</span> (<span class=\"pl-smi\">a</span> <span class=\"pl-k\">-></span> <span class=\"pl-smi\">b</span>) <span class=\"pl-k\">-></span> <span class=\"pl-smi\">f</span> <span class=\"pl-smi\">a</span> <span class=\"pl-k\">-></span> <span class=\"pl-smi\">f</span> <span class=\"pl-smi\">b</span>\n</code></pre>\n<p>It took me about 15 minutes to realize that\nI have seen too many curried functions\nso my brain instantly parses</p>\n<pre><code class=\"language-haskell\">(a <span class=\"pl-k\">-></span> b) <span class=\"pl-k\">-></span> f a <span class=\"pl-k\">-></span> f b\n</code></pre>\n<p>as</p>\n<pre><code class=\"language-swift\">((a <span class=\"pl-k\">-></span> b), <span class=\"pl-c1\">f</span>(a)) <span class=\"pl-k\">-></span> <span class=\"pl-c1\">f</span>(b)\n</code></pre>\n<p>instead of the intended</p>\n<pre><code class=\"language-swift\">(a <span class=\"pl-k\">-></span> b) <span class=\"pl-k\">-></span> (<span class=\"pl-c1\">f</span>(a) <span class=\"pl-k\">-></span> <span class=\"pl-c1\">f</span>(b))\n</code></pre>\n<p>So I have to:</p>\n<ol>\n<li>either admit that my brain is blunt</li>\n<li>or  profess that the currying way of ML/Haskell languages is confusing</li>\n</ol>\n<p>As an ignorant person, obviously  I chose 2.</p>\n<p>Date: <a id=\"1503815372\" href=\"https://mmap.page/log/#1503815372\">1503815372</a></p>\n<p>about.me has not been about me for a long time.</p>\n<p>about.me was a simple profile page before 2016.</p>\n<p>Now it is supposed to direct bandwidth to the site matters most to the user. about.me called it \"personal pages with a purpose\". While this feature may be useful, this is not the original about.me anymore. The original purpose of about.me is you can insert a <code>about.me/you</code> link in bios of other sites, less to type and easier to update.</p>\n<p>Date: <a id=\"1503633800\" href=\"https://mmap.page/log/#1503633800\">1503633800</a></p>\n<p>\"Go to definition\" does not work for shell scripts in vscode. <code>*</code> (from vscodevim extension) can be used as a workaround.</p>\n<p>Date: <a id=\"1503630583\" href=\"https://mmap.page/log/#1503630583\">1503630583</a></p>\n<p><code>sh</code> is the only language I am using that has dynamic scoping for variables. (Privacy leaked: I do not use Emacs.)</p>\n<p>Date: <a id=\"1503359848\" href=\"https://mmap.page/log/#1503359848\">1503359848</a></p>\n<p>A recent Windows update forced me to re-select options like no personalized ad, ruined my registry key for a customized keyboard layout (dvorak and swap esc &#x26; caps), and pined the Mail app on my taskbar. This is more like a regression than an update to me. (To be fair, it does allow me to launch some Windows applications under WSL.)</p>\n<p>Date: <a id=\"1485507471\" href=\"https://mmap.page/log/#1485507471\">1485507471</a></p>\n<p>Lantern only provides binary package in deb format for Linux. To install lantern on rpm based Linux distributions, first install <code>rpmbuild</code>, <code>alien</code> (to convert deb to rpm) and <code>libappindicator3-1</code> (lantern's dependency), then use <code>alien</code> to convert the deb to rpm, and finally install the converted rpm.</p>\n<p>Date: <a id=\"1485431319\" href=\"https://mmap.page/log/#1485431319\">1485431319</a></p>\n<p>Used openSUSE Leap 42.2 for a few days. You have to add a few repositories to install things like mp3, flash, and input methods. You have to configure mounting NTFS partitions yourself (via YaST or manually editing <code>/etc/fstab</code>). Default fonts setting for Chinese is terrible. Other things work out of the box mostly. KDE Plasma 5.8.2 roughly catches up the polishness of recent versions of Windows.</p>\n<p>Date: <a id=\"1485262536\" href=\"https://mmap.page/log/#1485262536\">1485262536</a></p>\n<p>Encountered ads with only one sentence \"Only bricks produced by The Lego Group are Lego ® bricks.\" and one Lego logo. This is advertising of silliness. No sense and no design.</p>\n<p>Date: <a id=\"1485079755\" href=\"https://mmap.page/log/#1485079755\">1485079755</a></p>\n<p>cdrtools author's viewpoint on <a href=\"http://cdrtools.sourceforge.net/private/linux-dist.html\">controversy of cdrtools license compatibility</a>.</p>\n<p>Date: <a id=\"1484756523\" href=\"https://mmap.page/log/#1484756523\">1484756523</a></p>\n<p>A programmer's client (a local cinema) website got hacked, with racist messages posted. The policy suspected the programmer hacked the site, and got a warrant to seize the programmer's computer. Then they sent <strong>21 armed polices</strong>, 3 of them to seize the computer, and <strong>18 of them as witness</strong>.</p>\n<p>On early morning, these polices <strong>broke in</strong> the programmer's home, and <strong>shot dead</strong> the programmer when he is talking to his lawyer on the phone (<strong>4 shots on chest and face</strong>).\nAnd the <strong>18 witness polices</strong> witnessed that the programmer fired a crossbow bolt at one of them (that police was protected by Kevlar thus slightly injured).</p>\n<p>This is <em>not</em> something happening in a magic realism novel or an absurdist  movie. This is what happened on <strong>December 23rd 2016</strong>, <strong>London, Ontario, Canada</strong>.</p>\n<p>The programmer is <strong>Sam Maloney</strong>, the creator of <a href=\"https://morph.is/\">morphis</a> (a free open source p2p distributed datastore), a husband and a father of two children.</p>\n<p>News reports:</p>\n<ol>\n<li><a href=\"http://news.nationalpost.com/news/canada/lawyer-tells-client-on-phone-during-predawn-raid-theyre-going-to-shoot-you-sam-put-your-hands-up\">first news report on nationalpost.com</a></li>\n<li><a href=\"https://motherboard.vice.com/read/why-did-police-kill-an-alleged-small-time-hacker-canada-sam-maloney\">more recent report on Motherboard</a> (<a href=\"http://127.0.0.1:43110/1uEc35aRpkDgVmJ35jcMEHm4D2JCcEejp/motherboard/\">ZeroNet mirror</a>)</li>\n</ol>\n<p>Date: <a id=\"1484574248\" href=\"https://mmap.page/log/#1484574248\">1484574248</a></p>\n<p>The so called whatsapp 'backdoor' was documented in the <a href=\"https://whispersystems.org/blog/whatsapp-complete/\">blog post of Open Whisper Systems on 05 Apr 2016</a>.</p>\n<p>I think the notification on security code for a contact changing should be \"opt out\" instead of \"opt in\". I guess Facebook made this \"opt in\" so users having no idea of public key encryption will not get confused by the security code change notification. They could make it \"opt out\" with a detailed explanation on first notification of security code change instead, in my own opinion.</p>\n<p>I would rather call it a less secure design choice. Anyway, no matter you think it is a backdoor or not, it is not news.</p>\n<p>Date: <a id=\"1484052490\" href=\"https://mmap.page/log/#1484052490\">1484052490</a></p>\n<p>Sign and publish your posts/comments from command line:</p>\n<pre><code class=\"language-sh\">zeronet.py siteSign site-address-of-other-people --inner_path data/users/address-of-myself/content.json --publish\n</code></pre>\n<p>It will asks the private key,\nunless you happen to be the site owner,\nfill in your cert's auth key.</p>\n<p>For example, if you are signed in with <code>you@zeroid.bit</code>, then you can find <code>certs</code>-><code>zeroid.bit</code>-><code>auth_privatekey</code> in <code>data/users.json</code>.</p>\n<p>Thanks to @nofish for this tip.</p>\n<p>Date: <a id=\"1483966944\" href=\"https://mmap.page/log/#1483966944\">1483966944</a></p>\n<blockquote>\n<p>the ideas enshrined in the Ubuntu Manifesto:\nthat software should be available free of charge,\nthat software tools should be usable by people in their local language\nand despite any disabilities,\nand that people should have the freedom to customize and alter their software\nin whatever way they see fit.</p>\n</blockquote>\n<p>This is what Ubuntu put on its front page about 10 years ago.</p>\n<p>Nowadays these words are missing from the entire site of ubuntu.com\n(the only place left is the handbook of LTS, maybe no one bothered to update the preface of the handbook?)</p>\n<p>And this is what now on the front page of ubuntu.com:</p>\n<blockquote>\n<p>Ubuntu is an open source software platform that runs from the cloud, to the smartphone, to all your things.</p>\n</blockquote>\n<p>Mark Shuttleworth used to think \"the next big thing\" is \"build a platform so people can share free (as in freedom) things such as software, music, etc\".</p>\n<p>Later \"the next big thing\" of Ubuntu gradually changed to \"universal user experience on all devices\", which is less uncertain since Apple has already been a successful example.\n(Apple is determined to make Mac OS X more and more like iOS, and make Apple laptops more and more like iPads.)</p>\n<p>Not know how well Ubuntu will do in next 10 years.\nAnywhere, \"universal user experience\" has nothing to do with the  original Nguni Bantu word \"Ubuntu\".</p>\n<p>Date: <a id=\"1483873500\" href=\"https://mmap.page/log/#1483873500\">1483873500</a></p>\n<p>Install ZeroNet as an auto-start service on FreeBSD:</p>\n<pre><code class=\"language-sh\">pkg install zeronet\nsysrc zeronet_enable=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>YES<span class=\"pl-pds\">\"</span></span>\nservice zeronet start\n</code></pre>\n<p>Run ZeroNet command:</p>\n<pre><code class=\"language-sh\">su -m nobody zeronet siteCreate\n</code></pre>\n<p>Date: <a id=\"1483798686\" href=\"https://mmap.page/log/#1483798686\">1483798686</a></p>\n<p>vscode's refactoring is still much less powerful than WebStorm, even for TypeScript.</p>\n<p>Date: <a id=\"1483701866\" href=\"https://mmap.page/log/#1483701866\">1483701866</a></p>\n<p>\"A Little Java, A Few Patterns\" uses a special coding style to remark mutability:</p>\n<p>Put semicolon on its own line.</p>\n<p>For example:</p>\n<pre><code class=\"language-java\">x <span class=\"pl-k\">=</span> x <span class=\"pl-k\">+</span> <span class=\"pl-c1\">1</span>\n; <span class=\"pl-c\">// Future references to `x` after this line reflect the change.</span>\nanArray<span class=\"pl-k\">.</span>append(<span class=\"pl-c1\">1</span>)\n; <span class=\"pl-c\">// Same as above.</span>\n</code></pre>\n<p>Date: <a id=\"1483614089\" href=\"https://mmap.page/log/#1483614089\">1483614089</a></p>\n<p>new History().repeat</p>\n<p>There is no first class functions in Java, so to pass functions, we wrap functions in classes. Now there is no first class function types in TypedRacket, so <a href=\"https://stackoverflow.com/a/27866496\">to predicate function types, we wrap functions in structs</a>.</p>\n<p>P.S. Same applies to TypeScript, Flow, Kotlin, and Swift. Ceylon's function type is first class, though.</p>\n<p>Date: <a id=\"1483533112\" href=\"https://mmap.page/log/#1483533112\">1483533112</a></p>\n<p>If you run ZeroNet on a remote machine, the doc recommends enabling <code>UiPassword</code>. But if your are using an unsafe network (public wifi, evil ISP, etc), password is transferred over insecure HTTP protocol. So for safety, you need to configure a reverse proxy with SSL for ZeroNet.</p>\n<p>Alternatively, you can just start ZeroNet on remote machine as normal,\nwithout <code>--ui_ip</code>, <code>UiPassword</code>, reverse proxy, SSL, etc.\nAnd run this command at local machine:</p>\n<pre><code>ssh -L 43110:127.0.0.1:43110 -N username@remote\n</code></pre>\n<p>Then you can just access <code>http://127.0.0.1:43110/</code> on your local machine, securely.</p>\n<p>Date: <a id=\"1483439543\" href=\"https://mmap.page/log/#1483439543\">1483439543</a></p>\n<p>Miss <code>finally</code> or <code>defer</code> in C.</p>\n<p>Date: <a id=\"1483358343\" href=\"https://mmap.page/log/#1483358343\">1483358343</a></p>\n<p>Yoda expressions are useful for tests in C, such as in <code>assert(true == ...</code> and <code>assert(false == ...</code>.</p>\n<p>Date: <a id=\"1483252068\" href=\"https://mmap.page/log/#1483252068\">1483252068</a></p>\n<p>Just found some old notes on K&#x26;R C book.</p>\n<p>The ink (I used a cheap ballpoint pen) is fading but still readable with some efforts.  Most notes are tricky parts of C, which are somehow irrelevant now (either being familiar with them or found out I rarely use them). Some notes I cannot agree now, e.g. \"Union really looks like a dirty hack on struct.\"  on p. 125. However, on p.89, there is a note on <code>while (*s++ = *t++)</code> saying \"Take me minutes to understand.\" Currently it would still take me minutes to understand it. Proud of it.^W^W^W</p>\n<p>Date: <a id=\"1483158324\" href=\"https://mmap.page/log/#1483158324\">1483158324</a></p>\n<p>Apache Portable Runtime is originally supporting library for Apache web server. Thus it uses memory pool heavily. So it may not be suitable to use APR as a standard library for general C programming.</p>\n<p>Date: <a id=\"1482929840\" href=\"https://mmap.page/log/#1482929840\">1482929840</a></p>\n<p>USB 3 external disks are 10-20% slower on VirtualBox.</p>\n<p>Date: <a id=\"1482853228\" href=\"https://mmap.page/log/#1482853228\">1482853228</a></p>\n<p>The confusing^W smarty Kotlin</p>\n<p>What would be the type of <code>f</code> in the following line?</p>\n<pre><code class=\"language-kotlin\"><span class=\"pl-k\">val</span> s<span class=\"pl-k\">:</span> <span class=\"pl-c1\">Int</span> <span class=\"pl-k\">=</span> f(<span class=\"pl-c1\">1</span>, <span class=\"pl-c1\">2</span>, <span class=\"pl-c1\">3</span>)\n</code></pre>\n<p>Not considering subtyping and generic,\nthe type f may be one of:</p>\n<ol>\n<li><code>(Int, Int, Int) -> Int</code>, the most  intuitive one</li>\n<li><code>(IntArray) -> Int</code>, a variadic function</li>\n<li><code>f</code>, an object named <code>f</code> with an <code>invoke</code> method</li>\n</ol>\n<p>Date: <a id=\"1482573034\" href=\"https://mmap.page/log/#1482573034\">1482573034</a></p>\n<p>Just fried some peanuts, which increased the PM 2.5 by 8 ug/m^3 in kitchen. So frying will not be a source of local air pollution  if you have extractor hood opened and keep the oil temperature low.</p>\n<p>Date: <a id=\"1482501352\" href=\"https://mmap.page/log/#1482501352\">1482501352</a></p>\n<p>Opened software manager in OpenSUSE and found in \"rpm groups\" there are <code>application</code> and <code>applications</code>, <code>developement</code> and <code>development</code>.</p>\n<p>Date: <a id=\"1482419450\" href=\"https://mmap.page/log/#1482419450\">1482419450</a></p>\n<p>PyCharm 2016.3 claims to support Python 3.6's f-strings (formatted literal). But in fact it just supports syntax highlight. All PyCharm's intelligent features are not enabled for code embedded in f-strings.</p>\n<p>Date: <a id=\"1482325338\" href=\"https://mmap.page/log/#1482325338\">1482325338</a></p>\n<p><a href=\"https://beakerbrowser.com/\">Beaker</a> is similar to ZeroNet. Their difference:</p>\n<ul>\n<li>Beaker does not host visited sites.  (You can enable it manually.)</li>\n<li>Beaker sites support versioning.</li>\n<li>Beaker API is much simpler than ZeroNet, no select user (id), no optional file, no encryption, etc. So dynamic sites are easier to create via ZeroNet.</li>\n<li>ZeroNet uses namecoin <code>.bit</code>. Beaker uses regular domain names (via <code>TXT</code> record. It's experimental, not man-in-the-middle attack proof ).</li>\n</ul>\n<p>Also, because Beaker requires  a customized browser:</p>\n<ul>\n<li>it uses <code>dat://</code> schema.</li>\n<li>Beaker sites need to ask user permission to access clearnet.</li>\n</ul>\n<p>(These are not substantial differences since anyone can make a customized browser for Zeronet.)</p>\n<p>Other differences are technical details, like ZeroNet is written in Python, while Beaker is written in JavaScript, and ZeroNet uses base58 encoded site address (compatible with bitcoin), while Beaker uses hex encoded address.</p>\n<p>Date: <a id=\"1482236480\" href=\"https://mmap.page/log/#1482236480\">1482236480</a></p>\n<p>Problems of Sia:</p>\n<ol>\n<li>It supports proof of storage but not proof of bandwidth.</li>\n<li>The Sia developers mined the first 100 blocks of Sia.</li>\n<li>3.9% of all successful storage contract payouts go to Siafund, of which 87.5% is owned by Sia's parent company.</li>\n</ol>\n<p>Date: <a id=\"1482152061\" href=\"https://mmap.page/log/#1482152061\">1482152061</a></p>\n<p>Problems of StorJ:</p>\n<ul>\n<li>Semi-central: storage is distributed, but the abstract object layer and payment is central.</li>\n<li>For every dollar a renter paid to StorJ, the host finally get 60 cents, StorJ keeps 40 cents.</li>\n</ul>\n<p>Date: <a id=\"1482056747\" href=\"https://mmap.page/log/#1482056747\">1482056747</a></p>\n<p>Just launched <a href=\"https://mmap.page/0git.bit\">0git.bit</a>, a list of git repositories on ZeroNet.</p>\n<p>I wrote it based on <a href=\"https://mmap.page/Blog.ZeroNetwork.bit/\">the ZeroChat tutorial on ZeroBlog</a>.</p>\n<p>Features:</p>\n<ul>\n<li>Also supports Kaffie ID.</li>\n<li>Responsive card based layout.</li>\n<li>Minimal design.</li>\n<li>Under 200 lines of code.</li>\n<li>Licensed under 0BSD.</li>\n</ul>\n<p>Its source code is hosted at ZeroNet, <a href=\"https://mmap.page/0git.0git.bit\">browsable and cloneable</a>.</p>\n<p>P.S. editing posts is not implemented yet.</p>\n<p>Date: <a id=\"1481907901\" href=\"https://mmap.page/log/#1481907901\">1481907901</a></p>\n<p>Currently FaceBook Message and Google Allo has optional end to end encryption. And WhatsApp has end to end encryption enabled for all messages. On the other hand, WeChat still uses http.  #ThisIsChina</p>\n<p>Date: <a id=\"1481815829\" href=\"https://mmap.page/log/#1481815829\">1481815829</a></p>\n<p><a href=\"https://mmap.page/setuplist.0web.bit/\">SetupList</a> now has its .bit domain <a href=\"https://mmap.page/setuplist.0web.bit/\">setuplist.0web.bit</a>.</p>\n<p>P.S. If you want to register a .bit domain, but do not want to setup a full namecoin node on your machine, you may get a .bit domain for your zeronet site at <a href=\"https://mmap.page/0web.bit/\">0web.bit</a> for 0.001BTC/0.1XMR.</p>\n<p>Date: <a id=\"1481718944\" href=\"https://mmap.page/log/#1481718944\">1481718944</a></p>\n<p>Yandex mail smtp refuses to send a GPG encrypted mail saying it looks like spam...</p>\n<p>Date: <a id=\"1481539922\" href=\"https://mmap.page/log/#1481539922\">1481539922</a></p>\n<p>Visual Studio Code only provides 32 bit downloads for Windows.</p>\n<p>Date: <a id=\"1481456773\" href=\"https://mmap.page/log/#1481456773\">1481456773</a></p>\n<p>Lesson learned: when your <code>data.json</code> local copy is outdated (e.g. rollback to an old version manually because of file system issue), do not post new content to the zite that outdated <code>data.json</code> belongs to. Otherwise you will publish your \"deletions\".</p>\n<p>Date: <a id=\"1481373014\" href=\"https://mmap.page/log/#1481373014\">1481373014</a></p>\n<p>When the function parameter is a function pointer, CLion (2016.3) cannot auto complete function name as parameter, like IntelliJ Idea for Java.</p>\n<p>Date: <a id=\"1481288689\" href=\"https://mmap.page/log/#1481288689\">1481288689</a></p>\n<p>Go back to use paper to manage my todos. (Some todos are still in WunderList, e.g. shopping list, cause I do not want to bring paper and pencil to supermarkets.)</p>\n<p>Date: <a id=\"1481203503\" href=\"https://mmap.page/log/#1481203503\">1481203503</a></p>\n<p>C is a hacky language. For example, string in C. If you think string in C is an array of characters, then you cannot put some characters in string (such as Unicode character) and you can put some noncharacters into string. If you think string is an an array of bytes, like a buffer, then you cannot put the byte <code>\\0</code> into string. So string in C is inconsistent viewed from both high level and low level.</p>\n<p>Go, advertised as modern C, inherits C's hacky mindset:</p>\n<ul>\n<li>\n<p>Error handling. Go uses multiple return values to represent union type <code>Result | SomeError</code> or optional type <code>Result | Null</code>: returning either <code>{result, nil}</code> or <code>{nil, error}</code>. The ordering of <code>result</code> and <code>error</code>, and one and only one of them must be <code>nil</code> is just a convention followed by programmers, not enforced by type system.</p>\n</li>\n<li>\n<p>For variable declaration without initialization, instead of checking it is correctly initialized later, Go just implicitly initialize it with a zero value. Even worse, Go uses <code>nil</code> as zero value for pointers, slices, interfaces, maps, channels, and functions.</p>\n</li>\n</ul>\n<p>Date: <a id=\"1481108543\" href=\"https://mmap.page/log/#1481108543\">1481108543</a></p>\n<p>@zeronetuseri6293 asked how to explain Systemd is bad \"like I am five\". I just prepare some text to brainwash five-year-old \"Systemd is bad\":</p>\n<p>You are five. You do not know how to cook pasta, how to bake bread, and how to clean the window, etc. Fortunately there are a lot of volunteers to help you to do all these things.</p>\n<p>The problem is these volunteers tend to commit suicide because of intrinsic depression. (They think helping a five year old may helps to reduce depression.)  And you are lazy and shy. You do not want to manage them yourself. There is a magician called Sysfive. When you go to sleep, Sysfive will kill those volunteers (not let them go home to avoid  traffic jam), and when you awake, Sysfive will reborn those volunteers. Also if you find some volunteer killed themselves, you can ask Sysfive to reborn them.</p>\n<p>These volunteers speak a language named Gnome. You happen to speak this language, too. And all those volunteers are from the same nation Debian. Debian is located at a continent called Linux. The continent Linux is located at a planet called unix.</p>\n<p>Your friends have volunteers speaking different languages like KDE and Xfce, from different places like OpenSUSE (also on Linux continent) and FreeBSD (on the BSD continent), and different magicians like OpenRC and RunIt (one magician can work for a lot of children.) You talked with your friends, and found out that you can find volunteers speaking Gnome from any nation and continent. Also, although volunteers from some certain countries only have experience with some magicians, all magicians can reborn volunteers from any country with some effort. \"This is good. Maybe one day I will ask FreeBSD volunteers to help me. One of my friends said FreeBSD volunteers are cool.\" You thought. \"And maybe one day I can ask RunIt the master to reborn volunteers for me. I heard that Sysfive the master is too old.\"</p>\n<p>Until one day, you learned that Systemd the master can only reborn volunteers from the Linux continent. Systemd refuses to reborn any volunteer from other continents such as BSD and Solaris.</p>\n<p>Also you learned that soon volunteers speaking Gnome can only be reborn by Systemd. They refuse to be reborn by other magicians.</p>\n<p>Also, there used to be different volunteers to do different things, for example, one helps you to do accounting (e.g. how much ham you have eaten, eating ham is bad for your health), and one configures your smart phone (smart phones are too smart to configure for a five year old). But\nSystemd said: \"I am very very powerful. I will do all these things. Send those volunteers away.\"</p>\n<p>You as a five year old may not think Systemd is bad.\nBut I hope you understand why some people consider Systemd as \"bad\".</p>\n<p>Date: <a id=\"1481017007\" href=\"https://mmap.page/log/#1481017007\">1481017007</a></p>\n<p>ZeroMail does not hide sender (and effectively timestamp and conversations may reveal receipt).</p>\n<p>Similarly, MaidSafe Email does not hide receipt.</p>\n<p>Date: <a id=\"1480945610\" href=\"https://mmap.page/log/#1480945610\">1480945610</a></p>\n<p>mypy is still incomplete.</p>\n<p>Date: <a id=\"1480767910\" href=\"https://mmap.page/log/#1480767910\">1480767910</a></p>\n<p><a href=\"https://www.youtube.com/watch?v=8DOnAn_PX6M\">911 The new pearl harbor</a> Politicians do not have imagination is totally a stereotype!</p>\n<p>Date: <a id=\"1480684396\" href=\"https://mmap.page/log/#1480684396\">1480684396</a></p>\n<p>Brace formatting style</p>\n<p>I used to prefer Java style (braces on the same line) over Allman style (braces on their own line). I use large fonts on a small screen, thus a condensed style is preferred.</p>\n<p>However, I recently found out that although Java style is clean for simple code, it does not work well with long parameter/conditional list. For example:</p>\n<pre><code class=\"language-c\"><span class=\"pl-k\">if</span> (starts_with(path, home, path_size, home_path_size) ||\n    <span class=\"pl-en\">check_with</span>(path, home, path_size, home_path_size) {\n    <span class=\"pl-c1\">recreate</span>(path, home);\n    <span class=\"pl-k\">return</span> home_path_size;\n} <span class=\"pl-k\">else</span> {\n    <span class=\"pl-k\">return</span> <span class=\"pl-c1\">0</span>;\n}\n</code></pre>\n<p>The simple statement <code>return 0</code> in else branch is clear.\nBut I cannot tell whether <code>recreate(path, home)</code> belongs to the conditional list or the function body at a glance.</p>\n<p>On the other side, I can get the whole structure at a glance with Allman style:</p>\n<pre><code class=\"language-c\"><span class=\"pl-k\">if</span> (starts_with(path, home, path_size, home_path_size) ||\n    <span class=\"pl-en\">check_with</span>(path, home, path_size, home_path_size)\n{\n    <span class=\"pl-c1\">recreate</span>(path, home);\n    <span class=\"pl-k\">return</span> home_path_size;\n}\n<span class=\"pl-k\">else</span>\n{\n    <span class=\"pl-k\">return</span> <span class=\"pl-c1\">0</span>;\n}\n</code></pre>\n<p>Also, since I use large fonts on small screen,\nI can not read <code>if (long || next_line ) {</code> at once.\nSo the Java style requires me to move my eyes to right, then move my eyes back to next line, which is slow.\nWith Allman style, to get an overview of structure,\nI only need to focus on the left half of the code block, and no eye movements are needed. This makes up the wasted lines.</p>\n<p>I guess for large screens a few wasted lines is affordable for clarity.</p>\n<p>Maybe the Java style is suitable for a setup with small fonts on a small screen, provided the syntax highlight scheme distinguishes braces clearly?</p>\n<p>Date: <a id=\"1480595655\" href=\"https://mmap.page/log/#1480595655\">1480595655</a></p>\n<p>ZeroNet's answer to CDN/cloud hosting industry: kill it. I think this is one of the most charming part of technology: rather than sloving a problem, make the problem irrelevant.</p>\n<p>Date: <a id=\"1480503877\" href=\"https://mmap.page/log/#1480503877\">1480503877</a></p>\n<p>Firefox version 41 to 50 (including 45 ESR used by the latest version of the Tor browser) has a memory corruption vulnerability allows malicious code to be executed on Windows, thus deanonymize Tor users.</p>\n<p>To protect yourself from similar possible future vulnerabilities:</p>\n<ol>\n<li>\n<p>the ultimate 2 physical machine solution: use two physical machine A and B. A has only one lan card to connect to B (make sure A does not have a wireless card, or has a physical switch to turn off wireless card).  B has 2 lan card, one for A, one for Internet. Running the browser on A and Tor on B,  and the connection between A and B is configured as NAT only. So A can only connect to Internet via Tor, and possible vulnerability in browser can only leak IP/MAC etc of A, not B. For max security, do not buy A online, incase the online seller may record A's hardware information together with your identity/address.</p>\n</li>\n<li>\n<p>the 2 virtual machine solution: similarly to the solution above, but use two Virtual machine instead. This does not protect you from virtual emualtor's escape vul­nerabilities though. However, virtual emualtor's escape vulnerabilities are rare (and your machine need to encounter both virtual emualtor's escape vulnerability and browser's vulnerability at the same time to leak the information of physical machine).</p>\n</li>\n<li>\n<p>Less secure than the above solutions, but the easiest: Use Tor Browser with JavaScript off, or at least block JavaScript by default, and whitelist sites you trusted.</p>\n</li>\n</ol>\n<p>Date: <a id=\"1480426260\" href=\"https://mmap.page/log/#1480426260\">1480426260</a></p>\n<p><a href=\"http://www.vultr.com/?ref=7046521-3B\">$20 credit for new users of Vultr</a> (KVM VPS with SSD, billed hourly/monthly, located in US, EU, Austrilia, Singapore, and Japan).</p>\n<p>Vultr v.s. DigitalOcean: They are quite similar except that Vultr has slightly more RAM for $5/m plan, and Vultr's snapshots are still free right now.</p>\n<p>Date: <a id=\"1480246329\" href=\"https://mmap.page/log/#1480246329\">1480246329</a></p>\n<p>Tunanota and ProtonMail looks promising, but they do not work with others, i.e. Tunanota users cannot exchange encrypted mails with ProtonMail users. Also, Tunanota and ProtonMail do not work with GPG users. Encryption is important, but openness is also important. And GPG is a good example of implementating encryption without reducing openness.</p>\n<p>An conterexample is Scryptmail, which supports import and export of GPG keys.</p>\n<p>Date: <a id=\"1480133479\" href=\"https://mmap.page/log/#1480133479\">1480133479</a></p>\n<p>Black Friday sales for VPS: <a href=\"https://www.lowendtalk.com/categories/offers\">https://www.lowendtalk.com/categories/offers</a></p>\n<p>Date: <a id=\"1480065029\" href=\"https://mmap.page/log/#1480065029\">1480065029</a></p>\n<p>Kotlin uses <code>Array&#x3C;T></code> for <code>vararg p: T</code> (variadic functions) underhood, but:</p>\n<ul>\n<li>Basic types are special, e.g. <code>IntArray</code> for <code>vararg p: Int</code>.</li>\n<li><code>p: Array&#x3C;T></code> and <code>vararg p: T</code> behaves differently. In other words, given a function <code>Array&#x3C;T> -> Unit</code>, we do not know how to invoke it just from its signature. (<code>Array&#x3C;T> -> Unit</code> may be an infix function, but all infix functions can be invoked as normal functions.)</li>\n</ul>\n<p>Date: <a id=\"1479994548\" href=\"https://mmap.page/log/#1479994548\">1479994548</a></p>\n<p>Overloading an operator should be consistent to all types supporting the operator.</p>\n<p>Date: <a id=\"1479900264\" href=\"https://mmap.page/log/#1479900264\">1479900264</a></p>\n<p>Flaws of TypeScript's type system:</p>\n<ul>\n<li>functions with fewer parameters are assignable to functions that take more parameters,</li>\n<li>non-void functions are assignable to void functions,</li>\n<li>all types are assignable to empty interfaces, and</li>\n<li>TypeScript cannot infer expected type with unused parameter in generics.</li>\n</ul>\n<p>Date: <a id=\"1479830201\" href=\"https://mmap.page/log/#1479830201\">1479830201</a></p>\n<p><a href=\"https://reason.com/blog/2016/11/18/watch-trumps-reported-pick-to-run-the-ci\">Watch Trump's Pick to Run the CIA Call Edward Snowden a 'Traitor' Who Should Be 'Given a Death Sentence'</a>.</p>\n<p>I said before the election result came out that Trump is evil. \"Make America great again!\" This sounds like what Beijing announced  in 2012: \"The Chinese Dream is the great rejuvenation of the Chinese nation.\"</p>\n<p>Bradley Manning is aleray in prison. Assange hides in Ecuadorian Embassy, and Snowden has been kept in Russia for 3 years.\nMake America great again so the great U.S. government could brought back Assange and Snowden and given them due process?</p>\n<p>I bet the greatest archivement of Trump would be what he had done before elected as U.S. President: stopping Hillary.</p>\n<p>Date: <a id=\"1479629037\" href=\"https://mmap.page/log/#1479629037\">1479629037</a></p>\n<p>TypeScript 2.0 brings in more fix of the poorly designed type system:</p>\n<pre><code class=\"language-sh\">tsc --strictNullChecks --noImplicitThis --noUnusedParameters --noUnusedLocals\n</code></pre>\n<p>Date: <a id=\"1479344216\" href=\"https://mmap.page/log/#1479344216\">1479344216</a></p>\n<p>Quora hides posts/answers to force you to register/login. Now its Chinese clone Zhihu finally borrows this \"feature\".</p>\n<p>Date: <a id=\"1479299795\" href=\"https://mmap.page/log/#1479299795\">1479299795</a></p>\n<p>JavaScript's ASI (auto semicolon insertion) is confusing. However, if I prefer to not omit semicolons, I only need to remember one rule: not  breaking line after <code>throw</code>. (There are other rules, but I am unlikely to write code related to other rules, e.g. <code>i\\n++\\nb</code>.)</p>\n<p>On the other side,  if I prefer to omit semicolons, I need to remember additional rules:</p>\n<ul>\n<li><code>(</code></li>\n<li><code>[</code></li>\n<li><code>.</code></li>\n<li><code>,</code></li>\n<li><code>+</code>, <code>-</code>, <code>*</code>, <code>/</code></li>\n<li><code>for</code> and <code>while</code></li>\n</ul>\n<p>Thus my choice is not omitting semicolons.</p>\n<p>Date: <a id=\"1479206065\" href=\"https://mmap.page/log/#1479206065\">1479206065</a></p>\n<p>After repositioning Windows 8.1's task bar to left, right, or top, hovering cursor to bottom left corner still reveals the windows start icon.</p>\n<p>Date: <a id=\"1479118683\" href=\"https://mmap.page/log/#1479118683\">1479118683</a></p>\n<p>Windows 8.1's Microsoft Pinyin input method:</p>\n<ol>\n<li>cannot change double pinyin schema</li>\n<li>no keyboard shortcut to switch between traditional Chinese and simplified Chinese</li>\n<li>no option to set default to English</li>\n</ol>\n<p>Date: <a id=\"1479051265\" href=\"https://mmap.page/log/#1479051265\">1479051265</a></p>\n<p>Use registery to swap keys under Windows.</p>\n<p>For example, use Caps Lock key as an addtional Escape key.</p>\n<pre><code class=\"language-reg\">Windows Registry Editor Version 5.00\n\n[<span class=\"pl-k\">HKEY_LOCAL_MACHINE</span>\\SYSTEM\\CurrentControlSet\\Control\\Keyboard Layout]\n\"Scancode Map\"=<span class=\"pl-k\">hex:</span>00,00,00,00,00,00,00,00,02,00,00,00,01,00,3a,00,00,00,00,00\n</code></pre>\n<p>Notes:</p>\n<ul>\n<li><code>00,00,00,00,00,00,00,00</code>: header.</li>\n<li><code>02</code>: data length (<code>n + 1</code> where <code>n</code> is numer of mapped keys).</li>\n<li><code>00,00,00</code>: end of data length.</li>\n<li><code>01,00</code>: Esc.</li>\n<li><code>3a,00</code>: Caps.</li>\n<li><code>00,00,00,00,00</code>: end.</li>\n</ul>\n<p>Date: <a id=\"1478263209\" href=\"https://mmap.page/log/#1478263209\">1478263209</a></p>\n<p>A quick review of germ.io:</p>\n<p>What is cool:</p>\n<ul>\n<li>Distinguish ideation with action.</li>\n<li>Distinguish completed with not taken.</li>\n<li>Nested sub list.</li>\n<li>In action view, tasks(germs) with sub-tasks actionable are marked with a lock icon.</li>\n</ul>\n<p>Missing:</p>\n<ul>\n<li>No export data.</li>\n<li>No mobile client.</li>\n<li>Status (Ideation, action, etc) is unclikable on overview.</li>\n<li>Note markup is Rich text, no option for markdown.</li>\n<li>No markup for code block.</li>\n<li>When change status from ideation to action, assign to no one by default, should assign to the one change status by default.</li>\n<li>No way to hide completed and not taken tasks.</li>\n</ul>\n<p>Date: <a id=\"1478184519\" href=\"https://mmap.page/log/#1478184519\">1478184519</a></p>\n<p>For any one want to pick up programming language , I recommend <a href=\"https://www.amazon.com/Little-Schemer-Daniel-P-Friedman/dp/0262560992\">The Little Schemer</a>，less than 200 pages and can be finished in a weekend. It starts from zero and gradually introduces concepts like recursion, higher-order functions, curry, Church encoding, halting problem, lambda calculus,  fixed point, Y combinator, continuation, CPS, Godel Incompleteness Theorem, and a basic interperator for a simplified progarmming language.</p>\n<p>If you think The Little Schemer is expensive, you can try <a href=\"https://leanpub.com/coffeescript-ristretto\">CoffeeScript Ristretto</a>, somehow a translation of The Little Schemer to CoffeeScript, which can be read on line for free.</p>\n<p>Do not worry the above books do not use a language you are going to use in your work. After all, the right approach to pick the certain programming language you are going to use is to focus on  semantics, instead of syntax; focus on concepts, instead of concrete details; focus on good parts, instead of all parts; also learning the implemantation of the language is a good way, since modeling is an effective way of learning (no need a full implement, also not worry about performance, just implement basic and import concepts).  The Littele Schemer fully conforms to this approach. Once you learned the scheme language with it, you know how to learn a new languge, and you know essential concepts of programing language. Then you can just pick up any language you are going to use in the same way. And because you only need to understand new semantics and concepts of the new language, it will be fast. For syntax, just use a good IDE or setup your editor properly.</p>\n<p>Date: <a id=\"1478179138\" href=\"https://mmap.page/log/#1478179138\">1478179138</a></p>\n<p>All Linux distributions where UEFI Secure Boot works out of the box (e.g. Fedora, OpenSuse, Ubuntu) are using systemd! #WTF</p>\n<p>Date: <a id=\"1478095569\" href=\"https://mmap.page/log/#1478095569\">1478095569</a></p>\n<p>Although Python still does not understand type hints, at least IDEs will give a warning. Or you can check types via <code>mypy</code>.</p>\n<p>Date: <a id=\"1477955778\" href=\"https://mmap.page/log/#1477955778\">1477955778</a></p>\n<p>The email to onfirm email address on dida365.com (Chinese version of TickTick) does not show any explicit url link. The link it is hide in HTML. It is wrong to assume every email client renders HTML correctly.</p>\n<p>Date: <a id=\"1477782781\" href=\"https://mmap.page/log/#1477782781\">1477782781</a></p>\n<p>mp3.163.com (a music distribution site in China) does not have any API. In fact it even encryptes post params with some home made algorithm (the algorithm is different on different clients and is evolving, the current API in web UI is based on AES, RSA and MD5) on HTTP (it does not support HTTPS). That's why I have never registered an account on it.</p>\n<p>Date: <a id=\"1477661384\" href=\"https://mmap.page/log/#1477661384\">1477661384</a></p>\n<p>WTF! New generation of MacBook Pro!</p>\n<p>It's Pro so it does not need to be so thin that it uses  a painful to type keyboard as on MacBook. Unified type-C is too cool to connect other devices. Even Apple self's devices are not unified, so you cannot charge iPhones without an adapter. Also replacing MagSafe with type-C is obivously a regression. And the 13\" version only has two slots! Also the price is much expensive than older genrations.</p>\n<p>In fact, Apple now effectly does not sell laptops. MacBook and MacBook Air only has 4 or 8GB unupgradable RAM. Now they ruied MacBook Pro, the only series of sufficient RAM.</p>\n<p>Date: <a id=\"1477398313\" href=\"https://mmap.page/log/#1477398313\">1477398313</a></p>\n<p>The main audience of code is human beings, not tests. Improving testability should not harm readability.</p>\n<p>Date: <a id=\"1477184548\" href=\"https://mmap.page/log/#1477184548\">1477184548</a></p>\n<p>citibank's \"change password\" gives misleading error info (\"must contain at least 1 digit and 1 letter\") if new password contains some special characters like <code>@</code>.</p>\n<p>Date: <a id=\"1477050333\" href=\"https://mmap.page/log/#1477050333\">1477050333</a></p>\n<p>In Ceylon, cases in <code>switch</code> need to be both disjoint and exhausted. Using a strict form helps to reduce bugs.</p>\n<p>For example, suppose we have the following code:</p>\n<pre><code class=\"language-ceylon\"><span class=\"pl-en\">Path</span> <span class=\"pl-smi\">path</span> = <span class=\"pl-smi\">current</span>;\n<span class=\"pl-k\">if</span> (<span class=\"pl-k\">is</span> <span class=\"pl-en\">Directory</span> <span class=\"pl-smi\">path</span>) { <span class=\"pl-c\">// typo, should be `path.resource`.</span>\n    <span class=\"pl-c\">// ...</span>\n} <span class=\"pl-k\">else</span> { <span class=\"pl-c\">// dead code</span>\n    <span class=\"pl-c\">// ...</span>\n}\n</code></pre>\n<p>There is a typo in the above code, <code>path</code> should be <code>path.resource</code>.\nSo the above code will never go into the else branch,\nsince a Path is always not a Directory.</p>\n<p>However, if we use switch with explicit cases:</p>\n<pre><code class=\"language-ceylon\"><span class=\"pl-k\">switch</span> (<span class=\"pl-smi\">path</span>)\n<span class=\"pl-k\">case</span> (<span class=\"pl-k\">is</span> <span class=\"pl-en\">Directory</span>) {\n    <span class=\"pl-c\">// ...</span>\n}\n<span class=\"pl-k\">case</span> (<span class=\"pl-k\">is</span> <span class=\"pl-en\">File</span>|<span class=\"pl-en\">Link</span>|<span class=\"pl-en\">Nil</span>) {\n    <span class=\"pl-c\">// ...</span>\n}\n</code></pre>\n<p>The compiler will refuse to compile, saying cases are not exhausted.</p>\n<p>Date: <a id=\"1476802731\" href=\"https://mmap.page/log/#1476802731\">1476802731</a></p>\n<p>I prefer explicit else branch over fall through flow.</p>\n<p>For example:</p>\n<pre><code class=\"language-ceylon\"><span class=\"pl-en\">Boolean</span> <span class=\"pl-smi\">if_else</span>(<span class=\"pl-en\">Integer</span> <span class=\"pl-smi\">x</span>) {\n    <span class=\"pl-k\">if</span> (<span class=\"pl-smi\">x</span> > <span class=\"pl-c1\">0</span>) {\n        <span class=\"pl-k\">if</span> (<span class=\"pl-smi\">x</span> &#x3C; <span class=\"pl-c1\">10</span>) {\n            <span class=\"pl-k\">return</span> <span class=\"pl-smi\">false</span>;\n        }\n    } <span class=\"pl-k\">else</span> <span class=\"pl-k\">if</span> (<span class=\"pl-smi\">x</span> &#x3C; <span class=\"pl-c1\">-10</span>) {\n        <span class=\"pl-k\">return</span> <span class=\"pl-smi\">false</span>;\n    }\n    <span class=\"pl-k\">return</span> <span class=\"pl-smi\">true</span>;\n}\n</code></pre>\n<p>It is short, but difficult to figure out the control flow.</p>\n<p>Rewrite it more explicitly, without omitting else branch:</p>\n<pre><code class=\"language-ceylon\"><span class=\"pl-en\">Boolean</span> <span class=\"pl-smi\">if_else</span>(<span class=\"pl-en\">Integer</span> <span class=\"pl-smi\">x</span>) {\n    <span class=\"pl-k\">if</span> (<span class=\"pl-smi\">x</span> > <span class=\"pl-c1\">0</span>) {\n        <span class=\"pl-c\">// This is for demonstration only.</span>\n        <span class=\"pl-c\">// `if (x > 0, x &#x3C; 10)` is clearer.</span>\n        <span class=\"pl-c\">// Pretend there were more complex branching here.</span>\n        <span class=\"pl-k\">if</span> (<span class=\"pl-smi\">x</span> &#x3C; <span class=\"pl-c1\">10</span>) {\n            <span class=\"pl-k\">return</span> <span class=\"pl-smi\">false</span>;\n        } <span class=\"pl-k\">else</span> {\n            <span class=\"pl-k\">return</span> <span class=\"pl-smi\">true</span>;\n        }\n    } <span class=\"pl-k\">else</span> <span class=\"pl-k\">if</span> (<span class=\"pl-smi\">x</span> &#x3C; <span class=\"pl-c1\">-10</span>) {\n        <span class=\"pl-k\">return</span> <span class=\"pl-smi\">false</span>;\n    } <span class=\"pl-k\">else</span> {\n        <span class=\"pl-k\">return</span> <span class=\"pl-smi\">true</span>;\n    }\n}\n</code></pre>\n<p>Also, avoid using <code>variable</code> to save else branch.</p>\n<p>For example:</p>\n<pre><code class=\"language-ceylon\"><span class=\"pl-k\">variable</span> <span class=\"pl-en\">Integer</span> <span class=\"pl-smi\">x</span> = <span class=\"pl-c1\">0</span>;\n<span class=\"pl-k\">if</span> (<span class=\"pl-smi\">condition</span>) {\n    <span class=\"pl-smi\">x</span> = <span class=\"pl-c1\">1</span>;\n}\n</code></pre>\n<p>can be rewritten to</p>\n<pre><code class=\"language-ceylon\"><span class=\"pl-en\">Integer</span> <span class=\"pl-smi\">x</span>;\n<span class=\"pl-k\">if</span> (<span class=\"pl-smi\">condition</span>) {\n    <span class=\"pl-smi\">x</span> = <span class=\"pl-c1\">1</span>;\n} <span class=\"pl-k\">else</span> {\n    <span class=\"pl-smi\">x</span> = <span class=\"pl-c1\">0</span>;\n}\n</code></pre>\n<p>Date: <a id=\"1476366067\" href=\"https://mmap.page/log/#1476366067\">1476366067</a></p>\n<p>Programming languages are clearer than natural languages. So \"well-commented code\" may not be well-written.</p>\n<p>To reduce commenting:</p>\n<ul>\n<li>Use meaningful function and variable/value name.</li>\n<li>Declare local variable near its usage.</li>\n<li>Avoid deep nested function call expression. Extract meaningful immediate value declaration.</li>\n</ul>\n<p>Here 'commenting' mainly refers to inline comments,\ni.e. comments explaining implementation details.\nDoc annotation of public modules and functions on their usage is fine.</p>\n<p>Date: <a id=\"1476107859\" href=\"https://mmap.page/log/#1476107859\">1476107859</a></p>\n<p>Windows Mobile does not support two factor auth, you have to use an app password. Now app password does not work on my phone (used to work on previous versions of Windows Mobile 10). I have to turn off two factor auth. Not too old Android versions support two factor auth out of the box.</p>\n<p>Date: <a id=\"1475908745\" href=\"https://mmap.page/log/#1475908745\">1475908745</a></p>\n<p>September 2015 Evernote Food shutdown. dianping.com (restaurant review site in China) also shutdown its public API service (individual developers cannot apply API access, APIs are only available to a few parterners) on that month.</p>\n<p>Date: <a id=\"1475846759\" href=\"https://mmap.page/log/#1475846759\">1475846759</a></p>\n<p>Thought there was something wrong with the sound configuration on my machine. Then I found out the mp3 I was playing is 32kbps.</p>\n<p>Date: <a id=\"1475794576\" href=\"https://mmap.page/log/#1475794576\">1475794576</a></p>\n<p>vscode is open source (MIT) and Visual Studio Code is proprietary. So confusing the names!</p>\n<p>Date: <a id=\"1475486435\" href=\"https://mmap.page/log/#1475486435\">1475486435</a></p>\n<p>Visual Studio Code: \"Code editing. Redefined.\" How a code editor borrowed a lot from SublimeText and TextMate dare to declare this?</p>\n<p>Date: <a id=\"1475402809\" href=\"https://mmap.page/log/#1475402809\">1475402809</a></p>\n<p>Finally iPhones get water resistent.</p>\n<p>Date: <a id=\"1475238402\" href=\"https://mmap.page/log/#1475238402\">1475238402</a></p>\n<p>GitHub helps spreading Git. But there is no balanced competitor currently. This is anti-decentred for a DVCS.</p>\n<p>Date: <a id=\"1475144789\" href=\"https://mmap.page/log/#1475144789\">1475144789</a></p>\n<p>Found an old macro (in a lisp like language) I wrote a year ago. Now I have difficulties to understand it.</p>\n<p>Date: <a id=\"1474806917\" href=\"https://mmap.page/log/#1474806917\">1474806917</a></p>\n<p><code>A then B else C</code> in Ceylon feels confusing to me.</p>\n<p><code>A then B else C</code> looks like <code>A ? B : C</code> in other languages, but they are <strong>not the same</strong>:</p>\n<ol>\n<li>\n<p><code>A then B else C</code> is actually <code>(A then B) else C</code>:</p>\n<pre><code>  * `A then B` evaluates to `B` if `A` is not `null`, otherwise evaluates to `null`.\n  * `X else Y` evaluates to `X` if `X` is not `null`, otherwise evaluates to `Y`.\n</code></pre>\n</li>\n<li>\n<p>Thus the type of <code>B</code> is <code>T given T satisfies Object</code>, i.e. requires to not be <code>null</code>.</p>\n</li>\n</ol>\n<p>I think <code>if (A) then B else C</code> is much cleaner.</p>\n<p>Date: <a id=\"1474550346\" href=\"https://mmap.page/log/#1474550346\">1474550346</a></p>\n<p><a href=\"https://github.com/weakish/0me-hubs-snapshots\">Snapshots of all current, non empty, functional ZeroMe hubs</a>,\npowered by <a href=\"https://github.com/weakish/0net-snapshot\">0net-snapshot</a>.</p>\n<p>Date: <a id=\"1474456689\" href=\"https://mmap.page/log/#1474456689\">1474456689</a></p>\n<p>All my todos are on wunderlist, which is down now. And I can hardly remember what to do. If wunderlist is implemented as a ZeroSite ...</p>\n<p>Date: <a id=\"1474102059\" href=\"https://mmap.page/log/#1474102059\">1474102059</a></p>\n<p>An ugly workaround of TypeScript's structural typing:</p>\n<pre><code class=\"language-typescript\"><span class=\"pl-k\">type</span> <span class=\"pl-en\">Kind1P</span> <span class=\"pl-k\">=</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>1p<span class=\"pl-pds\">\"</span></span>;\n<span class=\"pl-k\">type</span> <span class=\"pl-en\">Kind2P</span> <span class=\"pl-k\">=</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>2p<span class=\"pl-pds\">\"</span></span>;\n<span class=\"pl-k\">type</span> <span class=\"pl-en\">KindHUStrNum</span> <span class=\"pl-k\">=</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>string | number<span class=\"pl-pds\">\"</span></span>;\n\n<span class=\"pl-k\">function</span> <span class=\"pl-en\">f</span>(<span class=\"pl-v\">x</span><span class=\"pl-k\">:</span> <span class=\"pl-c1\">number</span>) {\n    <span class=\"pl-k\">return</span> <span class=\"pl-smi\">x</span>;\n}\n<span class=\"pl-k\">function</span> <span class=\"pl-en\">g</span>(<span class=\"pl-v\">x</span><span class=\"pl-k\">:</span> <span class=\"pl-c1\">number</span>, <span class=\"pl-v\">y</span><span class=\"pl-k\">:</span> <span class=\"pl-c1\">number</span>) {\n    <span class=\"pl-k\">return</span> <span class=\"pl-smi\">x</span> <span class=\"pl-k\">+</span> <span class=\"pl-smi\">y</span>;\n}\n\n<span class=\"pl-k\">let</span> <span class=\"pl-en\">no_f</span><span class=\"pl-k\">:</span> (<span class=\"pl-v\">x</span><span class=\"pl-k\">:</span> <span class=\"pl-c1\">number</span>, <span class=\"pl-v\">y</span><span class=\"pl-k\">:</span> <span class=\"pl-c1\">number</span>, <span class=\"pl-v\">kind</span><span class=\"pl-k\">:</span> <span class=\"pl-en\">Kind2P</span>) <span class=\"pl-k\">=></span> <span class=\"pl-c1\">number</span>;\n<span class=\"pl-k\">function</span> <span class=\"pl-en\">wrap_g</span>(<span class=\"pl-v\">x</span><span class=\"pl-k\">:</span> <span class=\"pl-c1\">number</span>, <span class=\"pl-v\">y</span><span class=\"pl-k\">:</span> <span class=\"pl-c1\">number</span>, <span class=\"pl-v\">kind</span><span class=\"pl-k\">:</span> <span class=\"pl-en\">KInd2P</span> <span class=\"pl-k\">=</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>2p<span class=\"pl-pds\">\"</span></span>) {\n    <span class=\"pl-k\">return</span> <span class=\"pl-en\">g</span>(<span class=\"pl-smi\">x</span>, <span class=\"pl-smi\">y</span>);\n}\n<span class=\"pl-smi\">no_f</span> <span class=\"pl-k\">=</span> <span class=\"pl-smi\">wrap_g</span>;\n\n<span class=\"pl-k\">function</span> <span class=\"pl-en\">higher</span>(\n        <span class=\"pl-en\">f</span><span class=\"pl-k\">:</span> (<span class=\"pl-v\">x</span><span class=\"pl-k\">:</span> <span class=\"pl-c1\">string</span> <span class=\"pl-k\">|</span> <span class=\"pl-c1\">number</span>, <span class=\"pl-v\">kind</span><span class=\"pl-k\">:</span> <span class=\"pl-en\">K1P</span>, <span class=\"pl-v\">kindH</span><span class=\"pl-k\">:</span> <span class=\"pl-en\">KUStrNum</span>) <span class=\"pl-k\">=></span> <span class=\"pl-c1\">string</span>,\n        <span class=\"pl-v\">y</span><span class=\"pl-k\">:</span> <span class=\"pl-c1\">string</span> <span class=\"pl-k\">|</span> <span class=\"pl-c1\">number</span>\n        ) {\n        <span class=\"pl-c1\">console</span>.<span class=\"pl-c1\">log</span>(<span class=\"pl-s\"><span class=\"pl-pds\">`</span>calling ${<span class=\"pl-smi\">f</span>}<span class=\"pl-pds\">`</span></span>);\n        <span class=\"pl-k\">return</span> <span class=\"pl-en\">f</span>(<span class=\"pl-smi\">y</span>);\n}\n\n<span class=\"pl-k\">function</span> <span class=\"pl-en\">sub</span>(<span class=\"pl-v\">x</span><span class=\"pl-k\">:</span> <span class=\"pl-c1\">number</span>)<span class=\"pl-k\">:</span> <span class=\"pl-c1\">string</span> {\n        <span class=\"pl-k\">return</span> <span class=\"pl-s\"><span class=\"pl-pds\">`</span>${<span class=\"pl-smi\">x</span> <span class=\"pl-k\">*</span> <span class=\"pl-smi\">x</span>}<span class=\"pl-pds\">`</span></span>;\n}\n<span class=\"pl-c\">// higher will not accept `sub`!</span>\n</code></pre>\n<p>Date: <a id=\"1474033858\" href=\"https://mmap.page/log/#1474033858\">1474033858</a></p>\n<p>There are currently 18 ZeroMe hubs (excluding empty hubs with no registered user). And I am seeding 5.  via <a href=\"https://weakish.github.io/zerome-crawler/\">zerome-crawler</a></p>\n<p>Date: <a id=\"1473685179\" href=\"https://mmap.page/log/#1473685179\">1473685179</a></p>\n<p><code>camelCaseAreHardToReadIfThereAreMoreThanThreeWords</code></p>\n<p><code>under_line_is_much_easier_to_read</code></p>\n<p>Exceptions:</p>\n<ul>\n<li><code>TypeName</code> since <code>TypeNamesWithMoreThanThreeWords</code> should be avoided.</li>\n<li><code>FooBar fooBar</code> so wherever we see <code>fooBar</code>, we know it is of type <code>FooBar</code>.</li>\n</ul>\n<p>Date: <a id=\"1473554294\" href=\"https://mmap.page/log/#1473554294\">1473554294</a></p>\n<p>Relieased that I have forgotten what does Hallelujah mean. To me it means some beautiful nonsense in music.</p>\n<p>Date: <a id=\"1473417604\" href=\"https://mmap.page/log/#1473417604\">1473417604</a></p>\n<p>In Python, whitespace (space or tab) can be used: (use dot to indicate whitespace)</p>\n<p>to <strong>indedent</strong> code (removing will cause error)</p>\n<pre><code class=\"language-python\"><span class=\"pl-k\">def</span> <span class=\"pl-c1\">id</span>(<span class=\"pl-smi\">x</span>):\n<span class=\"pl-c1\">...</span>.<span class=\"pl-k\">return</span> x\n</code></pre>\n<p>and <strong>align</strong> code (can be safely removed)</p>\n<pre><code class=\"language-python\">x<span class=\"pl-c1\">............</span>.<span class=\"pl-k\">=</span> <span class=\"pl-c1\">1</span>\nlong_variable <span class=\"pl-k\">=</span> <span class=\"pl-c1\">2</span>\n</code></pre>\n<p>Thus I think it is a good idea to distinguish them with different characters: use <code>tab</code> for <strong>indentation</strong>, and <code>space</code> for <strong>alignment</strong>.</p>\n<p>PEP 8 has a different opinion:</p>\n<ul>\n<li>Use <code>space</code> for indentation.</li>\n<li>Keep code unaligned.</li>\n</ul>\n<p>Date: <a id=\"1473253016\" href=\"https://mmap.page/log/#1473253016\">1473253016</a></p>\n<p>IDEs for static typed languages are so powerful, particularly for refactoring. The dark side is making me less acclimatized to dynamic typed languages IDEs, e.g. even PyCharm and RubyMine cannot match IntelliJ or Eclipse.</p>\n<p>Date: <a id=\"1472987577\" href=\"https://mmap.page/log/#1472987577\">1472987577</a></p>\n<p><code>i++</code> should be a pure side effect, a.k.a. <code>void</code>, just like <code>b = c</code> should be <code>void</code> (invalidating <code>if (a = 0)</code>).</p>\n<p>Date: <a id=\"1472908512\" href=\"https://mmap.page/log/#1472908512\">1472908512</a></p>\n<p>I used to confuse coding style with formatting style. Formatting style like <code>using n spaces to indent</code> and <code>closing brace on its own line</code> are unlikely to affect readability of code, and they can be auto adjusted via IDE or command line tools. What really matter is coding style, like <code>if (a=0)</code> and <code>++i</code>. PEP 8 for Python talks a lot about formatting style. This is a cost of Python's layout based (indentation sensitive) syntax: possibly cleaner for small pieces of code, while hard or impossible to be auto formatted by tools like IDEs (crucial for a large code base).</p>\n<p>Date: <a id=\"1472728889\" href=\"https://mmap.page/log/#1472728889\">1472728889</a></p>\n<p>Wish every programming language website has <a href=\"http://ceylon-lang.org/documentation/1.2/introduction/\">a gentle introduction like  Ceylon</a>, demostrating both basic usage and advanced features, but not lengthy.</p>\n<p>Date: <a id=\"1472648578\" href=\"https://mmap.page/log/#1472648578\">1472648578</a></p>\n<p><a href=\"http://127.0.0.1:43110/ZAlex.bit/photos/index.html\">An example of ZeroSite of photos</a></p>\n<p>Date: <a id=\"1472572000\" href=\"https://mmap.page/log/#1472572000\">1472572000</a></p>\n<p>Just add a 0BSD style license on my profile page: Permission to use, copy, modify, and/or distribute all my posts and comments at ZeroMe for any purpose with or without fee is hereby granted.</p>\n<p>Date: <a id=\"1472557661\" href=\"https://mmap.page/log/#1472557661\">1472557661</a></p>\n<p>Cloned site private key recovery:</p>\n<p>If <code>This is my site</code> in site menu does not works, you can try manually recover cloned site private key (they are generated from your master key in BIP32).</p>\n<p><strong>Warning</strong>: untested</p>\n<ul>\n<li>Make sure you are seeding your LostSite.</li>\n<li>Stop Zeronet.</li>\n<li>Get LostSite <code>address_index</code> in <code>data/LostSiteID/content.json</code>.</li>\n<li>Get your master key <code>master_seed</code> in <code>data/users.json</code>.</li>\n<li>Edit <code>Actions.main(self)</code> in <code>src/main.py</code>,  see below.</li>\n<li>Now start Zeronet, you will see site private key in output. Record it.</li>\n<li>Stop Zeronet. Delete recovery code added above.</li>\n<li>Edit <code>data/users.json</code>,  fill the record value (quoted) in <code>privatekey</code> at LostSiteID.</li>\n<li>Edit <code>data/sites.json</code>, set <code>own</code> in LostSiteID to <code>true</code>.</li>\n<li>Start Zeronet. Now you should be able to edit/publish your site.</li>\n</ul>\n<p>Added code in <code>src/main.py</code>:</p>\n<pre><code class=\"language-python\"><span class=\"pl-k\">class</span> <span class=\"pl-en\">Actions</span>(<span class=\"pl-c1\">object</span>):\n     <span class=\"pl-c\"># code omitted</span>\n     <span class=\"pl-k\">def</span> <span class=\"pl-en\">main</span>(<span class=\"pl-smi\">self</span>):\n          <span class=\"pl-c\"># code omitted</span>\n          <span class=\"pl-c\"># Add code below.</span>\n          logging.info(<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>--------------------DEBUG: Recovery Begin--------------------<span class=\"pl-pds\">\"</span></span>)\n          <span class=\"pl-k\">from</span> Crypt <span class=\"pl-k\">import</span> CryptBitcoin\n          logging.info(CryptBitcoin.hdPrivatekey(<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>YOUR_master_seed<span class=\"pl-pds\">\"</span></span>, <span class=\"pl-c1\">YOUR_address_index</span>))\n          logging.info(<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>------------------- DEBUG: Recovery End--------------------<span class=\"pl-pds\">\"</span></span>)\n          <span class=\"pl-c\"># Added code ended here.</span>\n\n          logging.info(<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>Starting servers....<span class=\"pl-pds\">\"</span></span>)\n          <span class=\"pl-c\"># code omitted</span>\n</code></pre>\n<p>Date: <a id=\"1472482054\" href=\"https://mmap.page/log/#1472482054\">1472482054</a></p>\n<p>The web flame: pretend that you cannot find exciting, new, modern technologies outside web.</p>\n<p>Date: <a id=\"1472481935\" href=\"https://mmap.page/log/#1472481935\">1472481935</a></p>\n<p>\"IPFS is the Distributed Web ... aims to replace HTTP\". WTF! A web of GET and PUT only HTTP? And FS is not file system but web?</p>\n<p>Date: <a id=\"1472480555\" href=\"https://mmap.page/log/#1472480555\">1472480555</a></p>\n<p>I think hg may fit ipfs more well than git. Like git's dumb http, hg supports <a href=\"https://www.mercurial-scm.org/wiki/StaticHTTP\">static http</a>. Unlike git's changing-all-the-time packfile, hg's revlog is predictable. So hosting hg repos on ipfs is simpler (no need to unpack objects manually), and saves bandwidth (git repos with unpacked objects is usually larger than hg).</p>\n<p>Date: <a id=\"1472474886\" href=\"https://mmap.page/log/#1472474886\">1472474886</a></p>\n<p>Duokan (ebook app) exports highlights and notes to Evernote <strong>without page numbers</strong>.</p>\n<p>Date: <a id=\"1472305397\" href=\"https://mmap.page/log/#1472305397\">1472305397</a></p>\n<p>List of all known ZeroMe hubs: <a href=\"https://weakish.github.io/ZeroMeHubList/\">https://weakish.github.io/ZeroMeHubList/</a></p>\n<p>Date: <a id=\"1472304911\" href=\"https://mmap.page/log/#1472304911\">1472304911</a></p>\n<p>Today I was bitten by <code>Refused to execute script from ... because its MIME type (text/plain) is not executable, and strict MIME type checking is enabled</code> when hot-linking a js file hosted on GitHub.</p>\n<p>Then I found out that <code>raw.github.com</code> is not truely raw access to file asset,\nbut a view rendered by Rails.\nSo accessing <code>raw.github.com</code> is much heavier than needed.\nI don't know why <code>raw.github.com</code> is implemented as a Rails view.\nInstead of fix this route issue, GitHub added a <code>X-Content-Type-Options: nosniff</code> header.</p>\n<p>It sounds like a hot fix to me:</p>\n<ul>\n<li><strong>A:</strong> Let's just make raw a Rails view, so it is simple to write routing code.</li>\n<li><strong>B:</strong> But this hurts performance.</li>\n<li><strong>A:</strong> No, programming time is more valuable than processing time. If more human beings view the raw, let's just convince VCs to invest more money for more machines since we are so successful that we have some many views.</li>\n<li><strong>B:</strong> But there are sites use GitHub to host scripts.</li>\n<li><strong>A:</strong> No, they should not do this because Rails view is heavy. Let's block them by adding an HTTP header. It's simple.</li>\n</ul>\n<p>Workaround:</p>\n<ul>\n<li>Put the script to <code>user.github.io/repo</code></li>\n<li>Use a third party CDN like rawgit.com.</li>\n</ul>\n<p>Date: <a id=\"1472271877\" href=\"https://mmap.page/log/#1472271877\">1472271877</a></p>\n<p>Google Buzz, Google Wave, Google Reader, Google Code. Now Google Chrome App (by 2018, except on ChromeOS).</p>\n<p>Date: <a id=\"1472129756\" href=\"https://mmap.page/log/#1472129756\">1472129756</a></p>\n<p>TeXmacs is still unstable. Make sure auto save is turned on.</p>\n<p>Date: <a id=\"1471707881\" href=\"https://mmap.page/log/#1471707881\">1471707881</a></p>\n<p>Considering a variant of <a href=\"http://semver.org/\">semver</a> major.nth_feature_introduced.YYMM</p>\n<p>Date: <a id=\"1471704922\" href=\"https://mmap.page/log/#1471704922\">1471704922</a></p>\n<h2>How to backup your favorite sites</h2>\n<p>tl;tr Favorite sites are stored in LocalStorage only. Switching browser or clearing browser data will reset all favorite sites.</p>\n<ol start=\"0\">\n<li>You are browsing a ZeroNet site.</li>\n<li>Open \"Web Developer Tool\" (or something similar) > Application > Storage > LocalStorage > <a href=\"http://127.0.0.1:43110/\">http://127.0.0.1:43110</a></li>\n<li>Find the key starting with <code>site.1HeLLo4uzjaLetFx6NH3PMwFP3qbRbTf3D</code></li>\n<li>Copy its value <code>{\"sites_orderby\":\"peers\",\"favorite_sites\":{\"1MeFqFfFFGQfa1J3gJyYYUvb5Lksczq7nH\":true,...}}</code></li>\n<li>Save its value to a safe place (a txt file on computer, a mail to yourself, etc)</li>\n</ol>\n<p>Restore: Right-click the value <code>Edit \"value\"</code> and replace with your backup.</p>\n<p>Date: <a id=\"1471526567\" href=\"https://mmap.page/log/#1471526567\">1471526567</a></p>\n<p>Zite (ZeroSite) publish procedure:</p>\n<ol>\n<li>publish your site (better with 15441 open)</li>\n<li>browser your site via <a href=\"https://bit.no.com:43110/\">ZeroNet proxy</a> to make sure everything is O.K.</li>\n<li>publish your site on <a href=\"http://127.0.0.1:43110/0list.bit\">0list</a>, <a href=\"http://127.0.0.1:43110/1Dt7FR5aNLkqAjmosWh8cMWzJu633GYN6u\">Zero Central</a> and <a href=\"http://127.0.0.1:43110/1LtvsjbtQ2tY7SCtCZzC4KhErqEK3bXD4n\">New 0Net Sites</a>.</li>\n</ol>\n<p>Date: <a id=\"1471526190\" href=\"https://mmap.page/log/#1471526190\">1471526190</a></p>\n<p>20191123: instructions updated for recent zeronet versions</p>\n<p>If zeronet's file server port is closed on your machine, you can use an ssh tunnel to accelerate publishing your zites:</p>\n<pre><code class=\"language-sh\">ssh -n -N -R 15441:127.0.0.1:15441 root@REMOTE_IP\n</code></pre>\n<p>Replace <code>15441</code> with the real file server port and fill the <code>REMOTE_IP</code> in the file server external ip of <a href=\"https://mmap.page/Config\">ZeroNet Config</a>.</p>\n<p>Note you need to enable <code>AllowTcpForwarding</code> and <code>GatewayPorts</code> of sshd service on the remote machine beforehand.</p>\n<pre><code class=\"language-sh\">sudo sh -c <span class=\"pl-s\"><span class=\"pl-pds\">'</span>echo AllowTcpForwarding yes<span class=\"pl-pds\">'</span></span> <span class=\"pl-k\">>></span> /etc/ssh/sshd_config\nsudo sh -c <span class=\"pl-s\"><span class=\"pl-pds\">'</span>echo GatewayPorts yes<span class=\"pl-pds\">'</span></span> <span class=\"pl-k\">>></span> /etc/ssh/sshd_config\nsudo service sshd restart  <span class=\"pl-c\"># On some OSes, replace `sshd` with `ssh`.</span>\n</code></pre>\n<p>Date: <a id=\"1471525789\" href=\"https://mmap.page/log/#1471525789\">1471525789</a></p>\n<p><a href=\"http://127.0.0.1:43110/1Mbwaw4Uxp1sq5GzWo3SCmYFTk7mgSWNmw\">SetupList</a> is online! (SetupList is a 0List clone for sharing software/hardware you are using.)</p>\n<p>Date: <a id=\"1471085743\" href=\"https://mmap.page/log/#1471085743\">1471085743</a></p>\n<p>Hello ZeroMe! (Hmm, I can follow myself!)</p>","date_published":"Wed, 05 Dec 2018 12:56:55 GMT","date_modified":"Thu, 14 Sep 2023 09:22:18 GMT"},{"id":"https://mmap.page/dapi/log/","url":"https://mmap.page/dapi/log/","content_html":"<p>想到一个 twitter 的翻译，粥粥（zhu⁴ zhu⁴）。【唐】韓愈《雉朝飛操》詩：「隨飛隨啄，群雌粥粥。」</p>\n<p>-- <a href=\"http://fanfou.com/statuses/kPaEFHQbnpU\">2017-08-19 09:55</a></p>\n<p>克隆本地倉庫，不是特別大的情況下，還是 <code>git clone --no-hardlinks</code> 吧。節省一點磁盤空間，相比在其中一個倉庫 rewrite history 污染另一個倉庫的風險，真的是不值得 (如果已經掉坑了，可以用 git reflog 找回丟失的 commit)</p>\n<p>-- <a href=\"http://fanfou.com/statuses/zWAvX8q_oCY\">2017-08-20 22:03</a></p>\n<p>饭否 web 需要登录才能查看用户发的推。好在通过 api 无需登录就可以看 <a href=\"http://t.cn/RC6Z13Q\">http://t.cn/RC6Z13Q</a> (api 文档中用的是 http, 实际上 https 也可以</p>\n<p>-- <a href=\"http://fanfou.com/statuses/vRHkqrVvq1Q\">2017-08-22 10:33</a></p>\n<p>SSD 的一大好处就是插 USB 的时候可以把机器调整到一个便于发力的角度。</p>\n<p>-- <a href=\"http://fanfou.com/statuses/dz2UQfaWjL8\">2017-08-24 11:31</a></p>\n<p>发现国产保护月我好像比平时去影院看了更多进口片——因为进口片都推迟放映（相比海外），我能获得的信息更多，也就更敢买票了。</p>\n<p>-- <a href=\"http://fanfou.com/statuses/4h6ujACgoKQ\">2017-08-26 17:40</a></p>\n<p>布歌东京也卖蛋糕和饼干了。原先不是号称只做布丁的么？</p>\n<p>-- <a href=\"http://fanfou.com/statuses/Lyxrc2W3pFU\">2017-09-05 15:48</a></p>","date_published":"Sun, 04 Nov 2018 16:31:02 GMT","date_modified":"Sat, 23 Nov 2019 19:11:50 GMT"},{"id":"https://mmap.page/dapi/not-a-blog/","url":"https://mmap.page/dapi/not-a-blog/","title":"这里并不是 blog","content_html":"<h1>这里并不是 blog</h1>\n<h2>blog 是 log</h2>\n<p>blog 是 web log 的简写。\n不管是原形，还是简写，都有 log 一词。\n顾名思义， blog 还是适合 log 性质的东西。</p>\n<p>比如：</p>\n<blockquote>\n<p>在乌镇「互联网之光」的展厅里逛到乐视的展台，\n居然真看到一辆自行车。\n我一边感叹我实在不明白乐视为什么连自行车都做，\n一边忍不住想骑上去试试。\n未遂，因为右边那个脚蹬子已经不知所踪。</p>\n</blockquote>\n<p>-- <a href=\"https://fanfou.com/statuses/KjjnG6FpCFo\">王兴</a></p>\n<p>再比如：</p>\n<blockquote>\n<p>昨天数据库遇到了一个 X 问题，\n损失了 Y 时间段内的 Z 数据。\nA-F 功能不受影响。\nR 时刻监测系统报告了问题后，\n我们进行了如下排查，...\n定位到是 S 造成了 X 问题。\n我们使用 T 修正了问题，\n同时尝试通过 I-K 恢复数据，\n分别取得了如下效果，...\n但 Y 时间段内的 Z 数据还是丢失了。\n这个事故暴露了我们系统中的 O-Q 缺陷，\n我们将采取 U-V 措施避免以后出现同类事故。</p>\n</blockquote>\n<p>-- 莫须有应用</p>\n<h2>被滥用的 blog</h2>\n<h3>别忘了滥用的代价</h3>\n<p>滥用无罪。\n但滥用基本上总是有代价的。</p>\n<p>比如，HTTP 的 GET 方法可以滥用为 POST,\n只要把 POST 的内容编码进请求的 url 就可以了。\n看起来效果不错，服务端可以偷懒，只实现 GET 方法，不用实现 POST 方法了。\n但是 GET 是为「读」设计的，滥用 GET 来「写」当然有代价。\n很容易想到的代价是可能超过 url 的长度限制，\n缓存、代理可能出问题。</p>\n<p>同样，滥用 blog 来承载非 log 性质的内容，\n可能让人忽视以下代价：</p>\n<ol>\n<li>内容可能和代码一样，是需要维护的</li>\n<li>内容可能和 log 不一样，按时间排序并不是最佳选择</li>\n</ol>\n<h3>发到 blog 上并不能改变内容的性质</h3>\n<p>甲月乙日，我配置了一台服务器，事后把流程记录下来，发到 blog 上。</p>\n<p>丙月丁日，我学习了如何使用 GitHub, 同样把学习所得发到 blog 上。</p>\n<p>某年某月某日，我记录了我做了什么事，这不就是 log 么？</p>\n<p>那可不一定。</p>\n<p>如果是这样的：</p>\n<blockquote>\n<p>丙月丁日，学习如何使用 GitHub.</p>\n</blockquote>\n<p>这是 log.\n实际上没有 blog 的年代，日记就是这么写的。</p>\n<p>当然，有时候日记不是这么干巴巴的：</p>\n<blockquote>\n<p>昨天我发现 GitHub 开放注册了。</p>\n<p>其实以前 M 曾问过需不需要 GitHub 的邀请，\n我不怎么感冒。\nGitorious 不需要邀请就能注册，整个平台也是开源的，\n我用 Gitorious 用得好好的，\n既然 GitHub 想控制新用户增长的速度，\n我又何苦去凑这个热闹呢？</p>\n<p>现在既然 GitHub 开放注册了，\n而且我看到 X、Y、Z 项目的仓库都放在 GitHub 上，\n那我也去注册一个账户吧。</p>\n</blockquote>\n<p>这同样也是 log.</p>\n<p>但下面的并不是 log:</p>\n<blockquote>\n<p>首先，在本地建立一个 git 仓库：</p>\n<p>(一些命令)</p>\n<p>接着，生成 ssh 密钥：</p>\n<p>(一些命令)</p>\n<p>在 GitHub web 界面粘贴刚刚生成的公钥：</p>\n<p>(下略)</p>\n</blockquote>\n<p>这其实是文档、说明书、手册、小抄，而不是 log.\n把这样的东西发到 blog 上，并不意味着它就不需要维护了。</p>\n<p>比如：</p>\n<ul>\n<li>git 新版本可能提供更加友好的 UI,</li>\n<li>ssh 新版本可能提供更安全的算法，</li>\n<li>GitHub 可能开发了命令行客户端，提交公钥不用去 web 界面了。</li>\n</ul>\n<p>即使一些比较「虚」的内容，看上去属于「感想」性质的内容，\n也不一定就属于 log 了，</p>\n<p>比如一篇题为「我看 Java 和 PHP」的「blog」，\n假如里面写到了 lambda 和类型标注，\n那么 Java 8 引入了 lambda, PHP 7 引入了函数参数和返回值的类型标注，\n相应的这篇「blog」就需要更新。\n这个维护工作是逃不掉的。\n即使当初严谨一点，把题目改成「我看 Java 7 和 PHP 5.5」，也逃不掉的。\n要不要升到 Java 8 或者 PHP 7?\n如果升级，是不是坚持不用新特性？\n如果不能避免升级，不能避免使用新特性，那就不能避免维护这篇「blog」.\n所以，很明显，其实这篇并不是「blog」.</p>\n<p>当然了，也可以另起炉灶，重新写一篇。\n实际上，很多「blog」就是这样「维护」的。\n原本的内容已经过时了，没有人维护。\n于是被其他人重新写的「blog」代替了。\n这也算是一种「维护」，\n可这种「维护」方式不太合理：</p>\n<ol>\n<li>老的内容流传广泛，可能比新内容更容易找到，也许读者会被其中过时的内容误导。</li>\n<li>每过一段时间就另起炉灶是一种浪费。</li>\n</ol>\n<h2>自然语言和程序一样是写给人看的</h2>\n<blockquote>\n<p>很多人头脑里清晰的程序设计原则，一遇到“写脚本”这样的任务就完全崩溃了似的，\n他们仿佛认为写脚本就是应该“松散”一些。\n很多平时写非常聪明的程序的人，\n到了需要处理“系统管理”任务的时候，就开始写一些 shell 脚本，或者 Perl 脚本。\n他们写这些脚本的时候，往往完全的忘记了程序设计的基本原则，\n例如“模块化”，“抽象”等等。</p>\n</blockquote>\n<p>-- <a href=\"http://www.yinwang.org/blog-cn/2013/03/29/scripting-language\">王垠</a></p>\n<p>滥用 blog 的问题是类似的。\n日记松散一点很正常，\n可是把不是 log 的内容当成 blog, 就容易写出不容易维护的东西。</p>\n<p>自然语言往往不如程序语言精确，但程序设计的很多原则一样适用。</p>\n<p>想象一下这样一个项目：</p>\n<ol>\n<li>代码不是按模块划分的，全部代码文件都挤在一个目录下，按编写的先后顺序排列</li>\n<li>有些文件有一些标签，但项目并不提供组合搜索标签的功能，只能按单个标签查看</li>\n<li>代码的修改没有记录，有时作者会在文件里记录一下</li>\n<li>代码的修改不是靠补丁，而是靠线性排列的「评论」，由作者手工合并</li>\n<li>过了一段时间后，无法提交「评论」了</li>\n</ol>\n<p>显而易见，这样的项目是不好维护的。</p>\n<p>然而很多 blog 系统就是这样的项目。\n当然，这些 blog 系统用来处理 log 性质的内容并没有什么大问题。\n但是当这样的 blog 系统被滥用来承载非 log 的内容时，就可能带来各种麻烦。</p>\n<p>回到上文提到的例子：</p>\n<blockquote>\n<p>甲月乙日，我配置了一台服务器，事后把流程记录下来，发到 blog 上。</p>\n</blockquote>\n<blockquote>\n<p>丙月丁日，我学习了如何使用 GitHub, 同样把所学发到 blog 上。</p>\n</blockquote>\n<p>如果里面都涉及到生成 ssh 密钥, 那我完全可以把这部分内容抽出来，单写一篇，\n让另外两篇引用它。\n以后再有别的文档涉及到生成 ssh 密钥，我都可以直接引用。\n如果打算把生成的算法从 rsa 改成 ed25519, 也只需要改动一处。\n这些和编程的原则是一模一样的。</p>\n<p>其实，编程时常常是直接引用第三方的库。\n同理，如果我找到一篇很好的生成 ssh 密钥的文档，我完全可以直接引用，不必自己写。\n当然，编程中相反的情况也是有的，有时候不想因为一个小函数引入第三方依赖，就自己写。\n同样地，有的时候内容不长，为了文档的完整性，避免阅读时太多跳转，也可以自己写。</p>\n<p>类似地：</p>\n<ul>\n<li>\n<p>传统的树形结构有时比标签更适合组织内容，</p>\n<p>就像章节往往更适合单本书，而标签更适合分类一大堆书。</p>\n</li>\n<li>\n<p>git 等管理代码的工具一样很有用，</p>\n<p>包括历史、分支、diff 等。</p>\n</li>\n<li>\n<p>补丁, issue 和 pull request 一样可以用于协作。</p>\n<p>所以这里没有提供一个写评论的框，而页脚有指向 GitHub issue 的链接。</p>\n</li>\n</ul>\n<h2>总结</h2>\n<ol>\n<li>blog 系统还是适合放 log 性质的内容。</li>\n<li>需要维护的内容总是需要维护的，发到 blog 上并不能避免维护。</li>\n<li>编程的经验一样可以应用于自然语言，降低维护的成本。</li>\n</ol>","date_published":"Sun, 04 Nov 2018 15:57:46 GMT","date_modified":"Sat, 23 Nov 2019 19:11:50 GMT"},{"id":"https://mmap.page/dapi/flutter/","url":"https://mmap.page/dapi/flutter/","title":"Flutter试玩","content_html":"<h1>Flutter试玩</h1>\n<h2>安装依赖（Android Studio）</h2>\n<p>flutter依赖Android Studio解决Android平台支持，\n即使你使用其他编辑器编写flutter程序，一样要装Android Studio。</p>\n<p>64位Ubuntu上，Android Studio依赖一些32位库：</p>\n<pre><code class=\"language-sh\">sudo apt install libc6:i386 libncurses5:i386 libstdc++6:i386 lib32z1 libbz2-1.0:i386\n</code></pre>\n<p>安装KVM（Android Studio依赖KVM实现虚拟机加速）：</p>\n<pre><code class=\"language-sh\">sudo apt install qemu-kvm libvirt-bin ubuntu-vm-builder bridge-utils\n</code></pre>\n<p>至<a href=\"https://developer.android.com/studio/index.html\">Android Studio官网</a>下载zip包，解压至钟意的目录（比如<code>/opt</code>）。</p>\n<p>访问<code>android-studio/bin/</code>，执行<code>studio.sh</code>。</p>\n<p>初次运行会自行下载安装Android SDK，如遇到网络问题，会弹出代理设置对话框。</p>\n<h2>安装Flutter</h2>\n<p>由于网络原因，CN内需要使用镜像：</p>\n<pre><code class=\"language-sh\"><span class=\"pl-k\">export</span> PUB_HOSTED_URL=https://pub.flutter-io.cn\n<span class=\"pl-k\">export</span> FLUTTER_STORAGE_BASE_URL=https://storage.flutter-io.cn\n</code></pre>\n<p>从GitHub代码仓库安装：</p>\n<pre><code class=\"language-sh\">git clone -b dev https://github.com/flutter/flutter.git\n<span class=\"pl-k\">export</span> PATH=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span><span class=\"pl-smi\">$PWD</span>/flutter/bin:<span class=\"pl-smi\">$PATH</span><span class=\"pl-pds\">\"</span></span> <span class=\"pl-k\">>></span> <span class=\"pl-smi\">$HOME</span>/.bash_profile\n<span class=\"pl-c1\">source</span> <span class=\"pl-smi\">$HOME</span>/.bash_profile\n<span class=\"pl-c1\">cd</span> ./flutter\n</code></pre>\n<p>关闭报告：</p>\n<pre><code class=\"language-sh\">flutter config --no-analytics\n</code></pre>\n<p>运行<code>flutter doctor</code>检查依赖：</p>\n<pre><code class=\"language-sh\">flutter doctor\n</code></pre>\n<h3>配置开发环境</h3>\n<p>flutter官方推荐的开发环境是Android Studio和Visual Studio Code.\n作为全家桶受害者，我选择Android Studio.</p>\n<p>其实没什么需要配置的，只需安装一个<code>Flutter</code>插件。</p>\n<p>还有就是Android开发常规的配置虚拟机：</p>\n<ol>\n<li>确保机器开了VM加速（如果机器不是太老的话，一般都开了）</li>\n<li>Android Studio > Tools > Android > AVD Manager: 选择Create Virtual Device</li>\n<li>选择你钟意的机型（屏幕尺寸和Android版本），注意选择<code>x86</code>或<code>x86_64</code>版本，否则会很慢。如果你之前没使用过这个“机型”的话，需要下载镜像，请耐心等待。</li>\n<li>点Next继续配置，Emulated Performance选择<strong>Hardware - GLES 2.0</strong>开启硬件加速。</li>\n<li>点Finish创建。之后试着运行下，看看有没有问题。</li>\n</ol>\n<p>然后跑一下自带的示例，看看能不能跑通。</p>\n<ol>\n<li>File > New Flutter Project: 项目类型选Flutter application</li>\n<li>右上方工具栏选择刚才创建的虚拟机（如果之前测试的时候开了虚拟机，但没关闭的话，需要先关掉再进行这一步）。</li>\n<li>工具栏点击运行（初次编译需要初始化环境，请耐心等待）。</li>\n</ol>\n<p>flutter支持hot-reload。修改代码后<code>ctrl+s</code>(save all)或点击工具栏的闪电图标，即可在虚拟机上实时看到效果。</p>\n<p>当然，也可以在真机上调试。设备开启<strong>Developer options</strong>和<strong>USB debugging</strong>，然后连接计算机即可。</p>\n<h2>Hello, World!</h2>\n<p>好了，总算把环境搭好了。下面开始写代码啰。</p>\n<p>我打算做一个显示PM 2.5的应用。在<code>lib/main.dart</code>内写入：</p>\n<pre><code class=\"language-dart\"><span class=\"pl-c\">// Material应用</span>\n<span class=\"pl-k\">import</span> <span class=\"pl-s\">'package:flutter/material.dart'</span>;\n\n<span class=\"pl-c\">// 入口函数（函数体只有一行时，可以用`=>`代替{ ... }）</span>\n<span class=\"pl-k\">void</span> <span class=\"pl-en\">main</span>() <span class=\"pl-k\">=></span> <span class=\"pl-en\">runApp</span>(<span class=\"pl-k\">new</span> <span class=\"pl-c1\">MyApp</span>());\n\n<span class=\"pl-c\">// 继承StatelessWidget（Stateless意味着不需要mutable状态）</span>\n<span class=\"pl-c\">// 使MyApp本身也成为一个Widget.</span>\n<span class=\"pl-c\">// 在Flutter下，几乎一切都是Widget.</span>\n<span class=\"pl-k\">class</span> <span class=\"pl-c1\">MyApp</span> <span class=\"pl-k\">extends</span> <span class=\"pl-c1\">StatelessWidget</span> {\n  <span class=\"pl-k\">@override</span>\n  <span class=\"pl-c1\">Widget</span> <span class=\"pl-en\">build</span>(<span class=\"pl-c1\">BuildContext</span> context) {\n    <span class=\"pl-k\">return</span> <span class=\"pl-k\">new</span> <span class=\"pl-c1\">MaterialApp</span>(\n      title<span class=\"pl-k\">:</span> <span class=\"pl-s\">'PM 2.5'</span>,\n      home<span class=\"pl-k\">:</span> <span class=\"pl-k\">new</span> <span class=\"pl-c1\">Scaffold</span>(\n        appBar<span class=\"pl-k\">:</span> <span class=\"pl-k\">new</span> <span class=\"pl-c1\">AppBar</span>(\n          title<span class=\"pl-k\">:</span> <span class=\"pl-k\">new</span> <span class=\"pl-c1\">Text</span>(<span class=\"pl-s\">'未知城市'</span>),\n        ),\n        body<span class=\"pl-k\">:</span> <span class=\"pl-k\">new</span> <span class=\"pl-c1\">Center</span>(\n          child<span class=\"pl-k\">:</span> <span class=\"pl-k\">new</span> <span class=\"pl-c1\">Text</span>(<span class=\"pl-s\">'-1'</span>),\n        ),\n      ),\n    );\n  }\n}\n</code></pre>\n<p>效果是这样的：</p>\n<p><picture><source srcset=\"/dapi/img/flutter/Screenshot_0.avif\" type=\"image/avif\"><img src=\"https://mmap.page/dapi/img/flutter/Screenshot_0.png\" alt=\"hello-world\" width=\"720\" height=\"1280\"></picture></p>\n<h2>使用Flutter包</h2>\n<p>上面我们的应用显示PM 2.5值为<code>-1</code>，表示没有数据。\n下面，让我们的应用从后端获取数据。</p>\n<p>我们通过HTTP协议获取数据，这需要用到Flutter包<code>http</code>。</p>\n<p>首先，我们声明依赖，在<code>pubspec.yaml</code>中加入<code>http</code>：</p>\n<pre><code class=\"language-yaml\"><span class=\"pl-ent\">dependencies</span>:\n  <span class=\"pl-ent\">flutter</span>:\n    <span class=\"pl-ent\">sdk</span>: <span class=\"pl-s\">flutter</span>\n\n  <span class=\"pl-ent\">http</span>: <span class=\"pl-s\">^0.11.0</span>\n</code></pre>\n<p>在Android Studio中点击<code>Packages get</code>拉取<code>http</code>包。</p>\n<p>接着在<code>lib/main.dart</code>内引入：</p>\n<pre><code class=\"language-dart\"><span class=\"pl-k\">import</span> <span class=\"pl-s\">'dart:async'</span>;\n<span class=\"pl-k\">import</span> <span class=\"pl-s\">'dart:convert'</span>;\n\n<span class=\"pl-k\">import</span> <span class=\"pl-s\">'package:http/http.dart'</span> <span class=\"pl-k\">as</span> http;\n</code></pre>\n<p>除了<code>http</code>之外，我们还引入了<code>dart:async</code>（异步获取结果，避免网络请求阻塞UI响应）和<code>dart:convert</code>（转换JSON）。</p>\n<p>编写异步函数，访问网络，解码JSON：</p>\n<pre><code class=\"language-dart\"><span class=\"pl-c\">// 异步函数（`async`和`await`为关键字）</span>\n<span class=\"pl-c1\">Future</span>&#x3C;<span class=\"pl-c1\">AQI</span>> <span class=\"pl-en\">fetchAQI</span>() <span class=\"pl-k\">async</span> {\n  <span class=\"pl-c\">// Android模拟器可以通过10.0.2.2访问主机。</span>\n  <span class=\"pl-c1\">String</span> url <span class=\"pl-k\">=</span> <span class=\"pl-s\">\"http://10.0.2.2:8000/aqis.json\"</span>;\n  <span class=\"pl-k\">final</span> response <span class=\"pl-k\">=</span> <span class=\"pl-k\">await</span> http.<span class=\"pl-en\">get</span>(url);\n  <span class=\"pl-k\">final</span> responseJson <span class=\"pl-k\">=</span> json.<span class=\"pl-en\">decode</span>(response.body);\n\n  <span class=\"pl-k\">return</span> <span class=\"pl-k\">new</span> <span class=\"pl-c1\">AQI</span>.<span class=\"pl-en\">fromJson</span>(responseJson);\n}\n\n<span class=\"pl-c\">// Flutter用不了dartson（dart下的gson）之类的需要运行时反射的库，</span>\n<span class=\"pl-c\">// 所以简单的json结构手工解析，复杂的json结构通过生成代码解析。</span>\n<span class=\"pl-k\">class</span> <span class=\"pl-c1\">AQI</span> {\n  <span class=\"pl-k\">final</span> <span class=\"pl-c1\">int</span> pm2_5;\n\n  <span class=\"pl-c1\">AQI</span>({<span class=\"pl-c1\">this</span>.pm2_5});\n  <span class=\"pl-c\">// json.decode返回Map&#x3C;String, dynamic></span>\n  <span class=\"pl-c\">// 这意味着，直到运行时才能确定具体类型</span>\n  <span class=\"pl-k\">factory</span> <span class=\"pl-c1\">AQI</span>.<span class=\"pl-en\">fromJson</span>(<span class=\"pl-c1\">Map</span>&#x3C;<span class=\"pl-c1\">String</span>, <span class=\"pl-c1\">dynamic</span>> json) {\n    <span class=\"pl-k\">return</span> <span class=\"pl-k\">new</span> <span class=\"pl-c1\">AQI</span>(\n      pm2_5<span class=\"pl-k\">:</span> json[<span class=\"pl-s\">'pm2_5'</span>],\n    );\n  }\n}\n</code></pre>\n<p>界面代码，只需改动<code>body</code>部分：</p>\n<pre><code class=\"language-dart\">   body<span class=\"pl-k\">:</span> <span class=\"pl-k\">new</span> <span class=\"pl-c1\">Center</span>(\n          child<span class=\"pl-k\">:</span> <span class=\"pl-k\">new</span> <span class=\"pl-c1\">FutureBuilder</span>&#x3C;<span class=\"pl-c1\">AQI</span>>(\n            future<span class=\"pl-k\">:</span> <span class=\"pl-en\">fetchAQI</span>(),\n            builder<span class=\"pl-k\">:</span> (context, snapshot) { <span class=\"pl-c\">// 匿名函数</span>\n              <span class=\"pl-k\">if</span> (snapshot.hasData) {\n                <span class=\"pl-k\">return</span> <span class=\"pl-k\">new</span> <span class=\"pl-c1\">Text</span>(<span class=\"pl-s\">\"${<span class=\"pl-v\">snapshot</span>.<span class=\"pl-v\">data</span>.<span class=\"pl-v\">pm2_5</span>}\"</span>);\n              } <span class=\"pl-k\">else</span> <span class=\"pl-k\">if</span> (snapshot.hasError) {\n                <span class=\"pl-k\">return</span> <span class=\"pl-k\">new</span> <span class=\"pl-c1\">Text</span>(<span class=\"pl-s\">\"${<span class=\"pl-v\">snapshot</span>.<span class=\"pl-v\">error</span>}\"</span>);\n              } <span class=\"pl-k\">else</span> {\n                <span class=\"pl-k\">return</span> <span class=\"pl-k\">new</span> <span class=\"pl-c1\">CircularProgressIndicator</span>();\n              }\n            },\n          )\n        ),\n</code></pre>\n<h2>完整代码</h2>\n<p>好了，到此为止，我们已经有了一个可以显示当前PM 2.5值的应用了。\n我们也大概知道Flutter应用是什么样子的了。</p>\n<p>完整代码如下：</p>\n<pre><code class=\"language-dart\"><span class=\"pl-k\">import</span> <span class=\"pl-s\">'dart:async'</span>;\n<span class=\"pl-k\">import</span> <span class=\"pl-s\">'dart:convert'</span>;\n\n<span class=\"pl-k\">import</span> <span class=\"pl-s\">'package:flutter/material.dart'</span>;\n<span class=\"pl-k\">import</span> <span class=\"pl-s\">'package:http/http.dart'</span> <span class=\"pl-k\">as</span> http;\n\n<span class=\"pl-c1\">Future</span>&#x3C;<span class=\"pl-c1\">AQI</span>> <span class=\"pl-en\">fetchAQI</span>() <span class=\"pl-k\">async</span> {\n  <span class=\"pl-c1\">String</span> url <span class=\"pl-k\">=</span> <span class=\"pl-s\">\"http://10.0.2.2:8000/aqis.json\"</span>;\n  <span class=\"pl-k\">final</span> response <span class=\"pl-k\">=</span> <span class=\"pl-k\">await</span> http.<span class=\"pl-en\">get</span>(url);\n  <span class=\"pl-k\">final</span> responseJson <span class=\"pl-k\">=</span> json.<span class=\"pl-en\">decode</span>(response.body);\n\n  <span class=\"pl-k\">return</span> <span class=\"pl-k\">new</span> <span class=\"pl-c1\">AQI</span>.<span class=\"pl-en\">fromJson</span>(responseJson);\n}\n\n<span class=\"pl-k\">class</span> <span class=\"pl-c1\">AQI</span> {\n  <span class=\"pl-k\">final</span> <span class=\"pl-c1\">int</span> pm2_5;\n\n  <span class=\"pl-c1\">AQI</span>({<span class=\"pl-c1\">this</span>.pm2_5});\n\n  <span class=\"pl-k\">factory</span> <span class=\"pl-c1\">AQI</span>.<span class=\"pl-en\">fromJson</span>(<span class=\"pl-c1\">Map</span>&#x3C;<span class=\"pl-c1\">String</span>, <span class=\"pl-c1\">dynamic</span>> json) {\n    <span class=\"pl-k\">return</span> <span class=\"pl-k\">new</span> <span class=\"pl-c1\">AQI</span>(\n      pm2_5<span class=\"pl-k\">:</span> json[<span class=\"pl-s\">'pm2_5'</span>],\n    );\n  }\n}\n\n\n\n<span class=\"pl-k\">void</span> <span class=\"pl-en\">main</span>() <span class=\"pl-k\">=></span> <span class=\"pl-en\">runApp</span>(<span class=\"pl-k\">new</span> <span class=\"pl-c1\">MyApp</span>());\n\n<span class=\"pl-k\">class</span> <span class=\"pl-c1\">MyApp</span> <span class=\"pl-k\">extends</span> <span class=\"pl-c1\">StatelessWidget</span> {\n  <span class=\"pl-k\">@override</span>\n  <span class=\"pl-c1\">Widget</span> <span class=\"pl-en\">build</span>(<span class=\"pl-c1\">BuildContext</span> context) {\n    <span class=\"pl-k\">return</span> <span class=\"pl-k\">new</span> <span class=\"pl-c1\">MaterialApp</span>(\n      title<span class=\"pl-k\">:</span> <span class=\"pl-s\">'PM 2.5'</span>,\n      home<span class=\"pl-k\">:</span> <span class=\"pl-k\">new</span> <span class=\"pl-c1\">Scaffold</span>(\n        appBar<span class=\"pl-k\">:</span> <span class=\"pl-k\">new</span> <span class=\"pl-c1\">AppBar</span>(\n          title<span class=\"pl-k\">:</span> <span class=\"pl-k\">new</span> <span class=\"pl-c1\">Text</span>(<span class=\"pl-s\">'PM 2.5'</span>),\n        ),\n        body<span class=\"pl-k\">:</span> <span class=\"pl-k\">new</span> <span class=\"pl-c1\">Center</span>(\n          child<span class=\"pl-k\">:</span> <span class=\"pl-k\">new</span> <span class=\"pl-c1\">FutureBuilder</span>&#x3C;<span class=\"pl-c1\">AQI</span>>(\n            future<span class=\"pl-k\">:</span> <span class=\"pl-en\">fetchAQI</span>(),\n            builder<span class=\"pl-k\">:</span> (context, snapshot) {\n              <span class=\"pl-k\">if</span> (snapshot.hasData) {\n                <span class=\"pl-k\">return</span> <span class=\"pl-k\">new</span> <span class=\"pl-c1\">Text</span>(<span class=\"pl-s\">\"${<span class=\"pl-v\">snapshot</span>.<span class=\"pl-v\">data</span>.<span class=\"pl-v\">pm2_5</span>}\"</span>);\n              } <span class=\"pl-k\">else</span> <span class=\"pl-k\">if</span> (snapshot.hasError) {\n                <span class=\"pl-k\">return</span> <span class=\"pl-k\">new</span> <span class=\"pl-c1\">Text</span>(<span class=\"pl-s\">\"${<span class=\"pl-v\">snapshot</span>.<span class=\"pl-v\">error</span>}\"</span>);\n              } <span class=\"pl-k\">else</span> {\n                <span class=\"pl-k\">return</span> <span class=\"pl-k\">new</span> <span class=\"pl-c1\">CircularProgressIndicator</span>();\n              }\n            },\n          )\n        ),\n      ),\n    );\n  }\n}\n</code></pre>\n<p>注意，PM 2.5数据从后端得到，实际项目中，后端将是一个提供数据的REST API服务。\n最简单的“模拟”后端的方法就是在本地放一个json文件<code>aqis.json</code>，内容如下：</p>\n<pre><code class=\"language-json\">{\n  <span class=\"pl-ent\">\"pm2_5\"</span>: <span class=\"pl-c1\">37</span>\n}\n</code></pre>\n<p>然后在<code>aqis.json</code>所在目录开一个http服务，比如通过python</p>\n<pre><code class=\"language-sh\">python2 -m SimpleHTTPServer\n</code></pre>\n<h2>练习</h2>\n<ol>\n<li>把字号调大。</li>\n<li>根据污染程度显示不同的颜色。</li>\n<li>根据污染程度提供健康建议。</li>\n<li>显示城市、监测点信息。</li>\n<li>选择城市、监测点。</li>\n<li>默认根据当前位置自动选择城市、监测点。</li>\n</ol>\n<p><strong>提示</strong> PM 2.5数据可从以下途径获得：</p>\n<ol>\n<li>国际： <a href=\"https://docs.openaq.org/\">OpenAQ</a></li>\n<li>国内： <a href=\"http://www.pm25.in/api_doc\">pm25.in</a>、<a href=\"https://github.com/geoinsights/ChinaAQIData/\">中国环境检测总站</a></li>\n</ol>","date_published":"Sun, 04 Nov 2018 15:57:46 GMT","date_modified":"Sat, 26 Jul 2025 05:29:46 GMT"},{"id":"https://mmap.page/dive-into/more/","url":"https://mmap.page/dive-into/more/","title":"Dive into more...","content_html":"<h1>Dive into more...</h1>\n<ul>\n<li><a href=\"https://mmap.page/dive-into/more/centos.md\">Centos</a></li>\n<li><a href=\"https://mmap.page/dive-into/more/cyclejs.md\">cycle.js</a></li>\n<li><a href=\"https://mmap.page/dive-into/more/fish.md\">Fish</a></li>\n<li><a href=\"https://mmap.page/dive-into/more/pry.md\">Pry</a></li>\n<li><a href=\"https://mmap.page/dive-into/more/rarcrack.md\">RarCrack</a></li>\n<li><a href=\"https://mmap.page/dive-into/more/tinygo.md\">Tinygo</a></li>\n</ul>","date_published":"Sun, 04 Nov 2018 15:04:32 GMT","date_modified":"Fri, 21 Apr 2023 11:03:43 GMT"},{"id":"https://mmap.page/dapi/shath-yar/","url":"https://mmap.page/dapi/shath-yar/","title":"Shath'Yar 语","content_html":"<h1>Shath'Yar 语</h1>\n<h2>语法</h2>\n<p>本节所有例句采用官方翻译。</p>\n<p><code>'</code>相当于连字符，其中一个用法是构成偏正结构的复合词。\n例如shath(old)加上yar(god)构成shath'yar，意为old gods，也指old gods使用的语言。\n类似地，Shuul'wah = Deathwing.</p>\n<p>主格、宾格、所有格：</p>\n<ul>\n<li>Y'za noq mah... Y'za noq ormz... = I am not (the) first... I am not (the) last...</li>\n<li>Sk'magg yawifk hoq. = Your suffering strengthens me.</li>\n<li>Uulwi ifis halahs gag erh'ongg w'ssh. = (The) shadow (of) my corpse will choke (this) land for all eternity.</li>\n</ul>\n<p>类似英语，第二人称的主格和宾格同形（iilth）：</p>\n<ul>\n<li>Iilth ma paf'qi'ag sk'halahs. =  You are a prisoner (in) your own body.</li>\n<li>N'Zoth ga zyqtahg iilth. = The will of N'Zoth corrupts you.</li>\n</ul>\n<p>作主语时，所有格和名词间用<code>'</code>连接，作宾语时所有格和名词直接相连：</p>\n<ul>\n<li>Sk'shgn eqnizz hoq. = Your fear drives me.</li>\n<li>Ywaq puul skshgn. = They drink your fear.</li>\n</ul>\n<p>第一人称复数的主格和所有格、第一人称复数和第二人称的所有格很齐整：</p>\n<ul>\n<li>Ag'THYZAK agthu. = We RECLAIM (this) world!</li>\n<li>Ak'agthshi ma uhnish. = Our numbers are endles.</li>\n<li>Sk'uuyat guulphg hoq. = Your agony sustains me.</li>\n</ul>\n<p>但第二人称的主格为iilth，宾格为ilfah（或原形）。\n这可能体现Shath-Yar语的历史演变，就像英语里第二人称主格、宾格原本不同（thou/ye, thee/you)，后来统一。</p>\n<ul>\n<li>Iilth ma paf'qi'ag sk'halahs. GAZ SKSHGN! = You are a prisoner in your own body. A SERVANT OF FEAR!</li>\n<li>N'Zoth ga zyqtahg iilth. = (The) will (of) N'Zoth corrupts you.</li>\n<li>Ez, Shuul'wah! Sk'woth'gl yu'gaz yog'ghyl ilfah! = O, Deathwing! Your faithful servant has failed you!</li>\n</ul>\n<p>ma相当于are或do，否定形态为maq:</p>\n<ul>\n<li>Ak'agthshi ma uhnish. = Our numbers are endles.</li>\n<li>Iilth ma paf'qi'ag sk'halahs. GAZ SKSHGN! = You are (a) prisoner (in) your (own) body. (A) SERVANT (OF) FEAR!</li>\n<li>Ywaq maq oou; ywaq maq ssaggh. Ywaq ma shg'fhn. = They do not die; they do not live. They are outside (the) cycle.</li>\n</ul>\n<p>ma可能不用于第一人称，至少noq相当于am not（猜想noq的原形为no）：</p>\n<ul>\n<li>Y'za noq mah... Y'za noq ormz... = I am not (the) first... I am not (the) last...</li>\n</ul>\n<p>ma不用于第三人称单数，第三人称单数用al:</p>\n<ul>\n<li>Yoq'al shn ky ywaq nuul. = It is (the) perpetuity in (which) they dwell. (sha = in)</li>\n</ul>\n<p>ma的将来时为qi：</p>\n<ul>\n<li>Iilth qi mah'shar fhn oorql N'Zoth! = You will be (the) first (of) many (to) glimpse (the) madness (of) N'Zoth!</li>\n</ul>\n<p>本句的结构分析：</p>\n<p>已知词汇：iilth, qi, mah, N'Zoth.</p>\n<p>「Ywaq ma shg'fhn. 」中shg'fhn对应outside the cycle，猜想shg意为outside，fhn意为cycle.\n又「ak'uq shg'cul vwahuhn」翻译为「our power beyond reckoning」，推断shg'cul对应beyond.\n基于shg意为outside的猜想，进一步猜想shg'cul也是合成词，cul大概是line或side的意思。</p>\n<p>Cataclysm in the Catacombs中有NPC台词「Gillari, geth'shar. Gillari, teko'shar. It sees. It knows.\ngeth'shar和teko'shar大约对应see和know.\n那么shar应该有see的意思。</p>\n<p>那么mah'shar fhn就应该作为一个词组理解，大概是circle of first see，最早见到...的圈子。</p>\n<p>最后剩下的oorql应该对应madness.</p>\n<p>qi还可以作为前缀，以<code>'</code>与动词原形连接，表示将来时：</p>\n<ul>\n<li>Sk'yahf qi'plahf PH'MAGG! = Your soul will know ENDLESS TORMENT!</li>\n<li>Ilith qi'uothk shn'ma yeh'glu Shath'Yar! = You will drown in (the) blood (of the) Old Gods!</li>\n</ul>\n<p>前面已经提到shn为in，这里的shn'ma大概衍生自sha，意思相近，可能是underneath.</p>\n<p>也可以用gag表示将来时：</p>\n<ul>\n<li>H'iwn iggksh Phquathi gag OOU KAAXTH SHUUL! = All (who) oppose the Destroyer will DIE A THOUSAND DEATHS!</li>\n</ul>\n<p>gag的名词形态为ga:</p>\n<p>N'Zoth ga zyqtahg iilth. = The will of N'Zoth corrupts you.</p>\n<p>agth意为shall:</p>\n<ul>\n<li>Sk'shuul agth vorzz N'Zoth naggwa'fssh. = Your deaths shall sing of N'Zoth's unending glory.</li>\n<li>Iilth vwah, uhn'agth fhssh za. = Where one falls, many shall take its place.</li>\n</ul>\n<p>第二个例句直译为：You fall, many shall take place.</p>\n<p>sythn表示进行时：</p>\n<ul>\n<li>Iilth sythn aqev... aqev... aqev... = You are going mad... mad... mad...</li>\n<li>Yeh'glu N'Zoth okom hoq... Y'za sythn oou... = (The) blood (of) N'Zoth runs through me... I cannot die...</li>\n</ul>\n<p>第二个例句中，Y'za sythn oou直译为I am dying.\n不死族不断腐烂，不断走向死亡，可以说是不死，也可以说是正在死。</p>\n<p>疑问句和英语一样，将动词提前：</p>\n<ul>\n<li>Al'ksh syq iir awan? = Is this real or (an) illusion?</li>\n</ul>\n<p>an作前缀，与名词连写，表示into:</p>\n<ul>\n<li>Gul'kafh an'shel. = Gaze into (the) void.</li>\n<li>Gul'kafh an'qov N'Zoth. = Gaze into (the) heart (of) N'Zoth.</li>\n</ul>\n<h2>词汇表</h2>\n<pre><code>Tense\nShu = A prefix denoting past tense;\nSythn = A prefix denoting progressive tense;\nQi = A prefix denoting future tense;\nAgth = Denoting future tense for plural and uncountable nouns;\nGag = Exact equivalent of English word \"Will\";\nMaq = Negative prefix for personal pronouns;\nNoq = Negative prefix;\n\nconj.\nZz = And;\nIir = Or;\nXig = (Suffix)How;\n\nprep.\nAn = Into;\nCul = (Suffix)On;\nKsh = Atop;\nQwor = Above;\nShg = Beyond;\nShn = In;\nThoq = For;\nUulg = After;\n\npron.\nY = My;\nHoq = Me;\nAg = We;\nAk = Our;\nIilth = You;\nIlfah = (Objective)You;\nSk = Your;\nOn = It;\nYwaq = They;\nKy = Which;\n\nv.\nAmqa = Come;\nEqnizz = Drive;\nErh = Choke;\nEt = Rule;\nFssh = Replace; Glorify;\nGuulphg = Sustain;\nGul'kafh = Gaze;\nHuqth = Sate;\nIggksh = Oppose;\nKyth = See;\nLwhuk = Devour;\nMagg = Wander; Suffer;\nNuq = Adorn;\nNuul = Dwell;\nOorql = Glimpse;\nOou = Die;\nPhgwa = Whisper;\nPlahf = Know;\nQam = Return;\nSshk = (auxil.v.)Do; (=Sshoq?);\nSshoq = Twist;\nThyzak = Reclaim;\nUothk = Drown;\nVorzz = Sing; Sing of;\nVwah = Fall;\nYawifk = Strengthen;\nWorg = Fade;\nZaix = Praise;\nZyqtahg = Corrupt;\n\nadj.\nAnagg = Endless;\nAqev = Mad;\nEth = Light;\nH'iwn = All;\nIiqaath = Curse;\nKssh = Bleakest;\nMah = First;\nMh = Only;\nMg = Writhing;\nNaggwa = Unending;\nOrmz = Last;\nQor = Endless;\nShath = (adj. form of Shel?); Black; Old;\nSshoq = Twisted;\nSyq = Real;\nUhnish = (adj.)Many; Endless;\nVwyq = (adv.)Once; Once more;\nW'ssh = (=W'ssht)Eternal; (adv.)Eternally;\nW'ssht = (=W'ssh)Eternal; (adv.)Eternally;\nWoth'gl = Faithful;\nYe = (adv.)Again;\n\nn.\nAgash = Despair;\nAgthshi = Number;\nAgthu = World;\nAwan = Illusion;\nFhn = Cycle; Many of the cycle;\nFssh = Glory;\nGaz = (=Yu'gaz)Servant;\nHalahs = Body; Corpse;\nHnakf = Wind; Shivering Wind;\nIiyoq = Will;\nKaaxth = Thousand;\nLuk = Road;\nMa = Millennia;\nMag = Empire;\nMagg = Suffering; Torment;\nMah = The first;\nMaqdahl = Sorrow;\nMeg = Banner; Flesh-banner;\nNaus = Hunger;\nOkom = Run through; Run;\nOngg = Earth; Land;\nOr = Hundred;\nOrmz = The last;\nPaf = Prisoner;\nPaf'qi'ag = One who will be our prisoner;\nPahg = Kindom;\nPhquati = Destroyer;\nPuul = Drink;\nQen = Spiral;\nQornaus = Endless hunger;\nQov = Heart;\nRazzqi = Light;\nShath'mag = The Black Empire;\nShath'Yar = Old Gods;\nShath'yar = Language of Old Gods;\nShel = Void;\nShgla'yos = They who dine on lost souls; Yogg-Saron;\nShgn = Fear;\nShfk = Howl;\nShuul = Death;\nSsaggh = Live;\nTek = Skull;\nUq = Power;\nUull = (=Uulwi)Shadow; Darkness;\nUulwi = (=Uull)Shadow;\nUuyat = Agony;\nVra = Chitter;\nVwahuhn = Reckoning; (Vwah + Uhn)Many fallens; Too many;\nWah = Wing;\nYahf = Soul;\nYar = God;\nYeh'glu = Blood;\nYel = Citadel;\nYoq'al = Perpetuity;\nYu'gaz = (=Gaz)Servant;\nYyqzz = Throne;\nZa = Place;\nZig = Depth; Deeps;\nZuq = Life;\nZzof = Victory;\n</code></pre>\n<p>词汇表据 Ningyou <a href=\"http://bbs.nga.cn/read.php?tid=10021411\">古神语写作不完全指北·修订第二版</a>.\n仅作参考，部分词汇的释义我们有不同意见。</p>\n<h3>增补</h3>\n<p>int.</p>\n<p>Ez = O/Oh</p>\n<h2>语料</h2>\n<p>见 <a href=\"http://wow.gamepedia.com/Shath&#x27;yar\">WOWPedia</a></p>\n<h2>习题</h2>\n<p>翻译：</p>\n<p>Q1:</p>\n<blockquote>\n<p>Light of my life, fire of my loins. My sin, my soul.</p>\n</blockquote>\n<p>-- Vladimir Nabokov, Lolita</p>\n<p>Q2:</p>\n<blockquote>\n<p>May the force be with you.</p>\n</blockquote>\n<p>-- Star Wars</p>\n<p>Q3:</p>\n<blockquote>\n<p>See you soon.</p>\n</blockquote>\n<p>Q4:</p>\n<blockquote>\n<p>Hello world!</p>\n</blockquote>\n<p>A1: 这些词汇未知fire、loin、sin, 可用近义词代替：fire/fssh (glory), loin/qornaus (endless hunger), sin/uull(darkness).</p>\n<pre><code>Razzqi ifis zuq, fssh ifis qornaus. Ifis uull. Ifis yahf.\n\n当然原文的头韵就没法保留了。\n</code></pre>\n<p>A2: 同样，用近义词替换未知词汇。</p>\n<pre><code>Agth uq eqnizz ilfah.\n\n也就是Shall (the) power drive you. 这个语义和原文其实有一段距离，不过我想不到更好的翻译了。\n</code></pre>\n<p>A3: soon 未知，翻译同义句 see you again.</p>\n<pre><code>Kyth ilfah ye.\n</code></pre>\n<p>A4: Ez, agthu!</p>","date_published":"Sat, 25 Aug 2018 12:53:43 GMT","date_modified":"Sat, 23 Nov 2019 19:16:00 GMT"},{"id":"https://mmap.page/java/a-little/","url":"https://mmap.page/java/a-little/","title":"Notes on A little Java, a Few Patterns","content_html":"<h1>Notes on A little Java, a Few Patterns</h1>\n<h2>Advantages of Java</h2>\n<ul>\n<li>a small core language with a simple semantic model</li>\n<li>gc</li>\n</ul>\n<h2>Design Patterns</h2>\n<p>Design patterns are used:</p>\n<ul>\n<li>to organize your code</li>\n<li>to communicate with others</li>\n</ul>\n<h2>Introductory Language</h2>\n<p>Recommended introductory language: Scheme or ML.</p>\n<h2>Too Much Coffee</h2>\n<p><strong>Q:</strong> Is it confusing that we need to connect <code>int</code> with <code>Integer</code> (e.g. <code>Integer(5)</code>)\nand <code>boolean</code> with <code>Boolean</code> (e.g. <code>Boolean(false)</code>)?</p>\n<p><strong>A:</strong> Too much coffee does that.</p>\n<p>Note the book uses an early version of Java.\nCurrent Java can do auto boxing and unboxing for primitive types.</p>\n<p>Also, in this book, if the method specified its return type as <code>Object</code> in interface,\nthen its implementation also annotated as returning <code>Object</code>,\neven when the implementation in fact always returns <code>Boolean</code>.</p>\n<p><strong>Q:</strong> There is no number <code>x</code> in the world for which</p>\n<pre><code>x = x + 1\n</code></pre>\n<p>So why should we expect there to be a Java <code>p</code> such that</p>\n<pre><code class=\"language-java\">p <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> <span class=\"pl-smi\">Top</span>(<span class=\"pl-k\">new</span> <span class=\"pl-smi\">Anchovy</span>(), p)\n</code></pre>\n<p><strong>A:</strong> That's right. But that's what happens when you have one too many double espresso.</p>\n<h2>Semicolon on Its Own Line for Mutability</h2>\n<pre><code class=\"language-java\"><span class=\"pl-k\">class</span> <span class=\"pl-en\">PutSemicolonOnItsOwnLineForMutability</span>\n{\n    <span class=\"pl-smi\">Pie</span> p <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> <span class=\"pl-smi\">Crust</span>();\n    <span class=\"pl-smi\">Pie</span> p <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> <span class=\"pl-smi\">Top</span>(<span class=\"pl-k\">new</span> <span class=\"pl-smi\">Anchovy</span>(), p)\n    ; <span class=\"pl-c\">// the future begins, i.e. from this line on, references to `p` reflect the change</span>\n    <span class=\"pl-smi\">Pieman</span> yy <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> <span class=\"pl-smi\">Bottom</span>();\n    yy.<span class=\"pl-en\">addTop</span>(<span class=\"pl-v\">new</span> <span class=\"pl-smi\">Anchovy</span>())\n    ; <span class=\"pl-c\">// same as above</span>\n}\n</code></pre>\n<h2>LittleJava.java</h2>\n<pre><code class=\"language-java\"><span class=\"pl-c\">// `D` means this is a data class.</span>\n<span class=\"pl-k\">abstract</span> <span class=\"pl-k\">class</span> <span class=\"pl-en\">Numᴰ</span> {}\n\n<span class=\"pl-k\">class</span> <span class=\"pl-en\">Zero</span> <span class=\"pl-k\">extends</span> <span class=\"pl-e\">Numᴰ</span> {}\n\n<span class=\"pl-k\">class</span> <span class=\"pl-en\">OneMoreThan</span> <span class=\"pl-k\">extends</span> <span class=\"pl-e\">Numᴰ</span> {\n    <span class=\"pl-smi\">Numᴰ</span> predecessor;\n\n    <span class=\"pl-c\">// Constructor</span>\n    <span class=\"pl-en\">OneMoreThan</span>(<span class=\"pl-smi\">Numᴰ</span> <span class=\"pl-v\">_p</span>) {\n        predecessor <span class=\"pl-k\">=</span> _p;\n    }\n}\n\n<span class=\"pl-c\">/*</span>\n<span class=\"pl-c\">We did not tell you these are Peano axioms.</span>\n<span class=\"pl-c\">We din not give formal definition.</span>\n<span class=\"pl-c\">So you can form your own definition.</span>\n<span class=\"pl-c\">Try to give it a name by yourself.</span>\n<span class=\"pl-c\">This helps you to remember and understand it better.</span>\n<span class=\"pl-c\"> */</span>\n\n\n\n\n\n<span class=\"pl-c\">/* This book shows how to protect direct access to property without the `private` access modifier.</span>\n<span class=\"pl-c\"></span>\n<span class=\"pl-c\">   Wrap it into an interface. In that interface, only expose public methods, not the \"private\" property.</span>\n<span class=\"pl-c\"> */</span>\n\n<span class=\"pl-c\">/* Visitor pattern */</span>\n<span class=\"pl-k\">abstract</span> <span class=\"pl-k\">class</span> <span class=\"pl-en\">Shishᴰ</span>\n{\n    <span class=\"pl-smi\">OnlyOnionsⱽ</span> ooFn <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> <span class=\"pl-smi\">OnlyOnionsⱽ</span>();\n    <span class=\"pl-k\">abstract</span> <span class=\"pl-k\">boolean</span> <span class=\"pl-en\">onlyOnions</span>();\n}\n\n<span class=\"pl-k\">class</span> <span class=\"pl-en\">OnlyOnionsⱽ</span>\n{\n    <span class=\"pl-k\">boolean</span> <span class=\"pl-en\">forSkewer</span>()\n    {\n        <span class=\"pl-k\">return</span> <span class=\"pl-c1\">true</span>;\n    }\n\n    <span class=\"pl-k\">boolean</span> <span class=\"pl-en\">forOnion</span>(<span class=\"pl-smi\">Shishᴰ</span> <span class=\"pl-v\">s</span>)\n    {\n        <span class=\"pl-k\">return</span> s<span class=\"pl-k\">.</span>onlyOnions();\n    }\n\n    <span class=\"pl-k\">boolean</span> <span class=\"pl-en\">forLamb</span>(<span class=\"pl-smi\">Shishᴰ</span> <span class=\"pl-v\">s</span>)\n    {\n        <span class=\"pl-k\">return</span> <span class=\"pl-c1\">false</span>;\n    }\n\n    <span class=\"pl-k\">boolean</span> <span class=\"pl-en\">forTomato</span>(<span class=\"pl-smi\">Shishᴰ</span> <span class=\"pl-v\">s</span>)\n    {\n        <span class=\"pl-k\">return</span> <span class=\"pl-c1\">false</span>;\n    }\n}\n\n<span class=\"pl-k\">class</span> <span class=\"pl-en\">Skewer</span> <span class=\"pl-k\">extends</span> <span class=\"pl-e\">Shishᴰ</span>\n{\n    <span class=\"pl-k\">boolean</span> <span class=\"pl-en\">onlyOnions</span>()\n    {\n        <span class=\"pl-k\">return</span> ooFn<span class=\"pl-k\">.</span>forSkewer();\n    }\n}\n\n<span class=\"pl-k\">class</span> <span class=\"pl-en\">Onion</span> <span class=\"pl-k\">extends</span> <span class=\"pl-e\">Shishᴰ</span>\n{\n    <span class=\"pl-smi\">Shishᴰ</span> s;\n    <span class=\"pl-en\">Onion</span>(<span class=\"pl-smi\">Shishᴰ</span> <span class=\"pl-v\">_s</span>)\n    {\n        s <span class=\"pl-k\">=</span> _s;\n    }\n\n    <span class=\"pl-k\">boolean</span> <span class=\"pl-en\">onlyOnions</span>()\n    {\n        <span class=\"pl-k\">return</span> ooFn<span class=\"pl-k\">.</span>forOnion(s);\n    }\n}\n<span class=\"pl-k\">class</span> <span class=\"pl-en\">Lamb</span> <span class=\"pl-k\">extends</span> <span class=\"pl-e\">Shishᴰ</span>\n{\n    <span class=\"pl-smi\">Shishᴰ</span> s;\n    <span class=\"pl-en\">Lamb</span>(<span class=\"pl-smi\">Shishᴰ</span> <span class=\"pl-v\">_s</span>)\n    {\n        s <span class=\"pl-k\">=</span> _s;\n    }\n\n    <span class=\"pl-k\">boolean</span> <span class=\"pl-en\">onlyOnions</span>()\n    {\n        <span class=\"pl-k\">return</span> ooFn<span class=\"pl-k\">.</span>forLamb(s);\n    }\n}\n<span class=\"pl-k\">class</span> <span class=\"pl-en\">Tomato</span> <span class=\"pl-k\">extends</span> <span class=\"pl-e\">Shishᴰ</span>\n{\n    <span class=\"pl-smi\">Shishᴰ</span> s;\n    <span class=\"pl-en\">Tomato</span>(<span class=\"pl-smi\">Shishᴰ</span> <span class=\"pl-v\">_s</span>)\n    {\n        s <span class=\"pl-k\">=</span> _s;\n    }\n\n    <span class=\"pl-k\">boolean</span> <span class=\"pl-en\">onlyOnions</span>()\n    {\n        <span class=\"pl-k\">return</span> ooFn<span class=\"pl-k\">.</span>forTomato(s);\n    }\n}\n<span class=\"pl-c\">/* Before introducing visitor pattern,</span>\n<span class=\"pl-c\">   every subclass of Shishᴰ need to contain the logic of `onlyOnions()` in its definition.</span>\n<span class=\"pl-c\">   And the book asked \"Wasn't this overwhelming?\"</span>\n<span class=\"pl-c\">   I had thought it would introduce generics next.</span>\n<span class=\"pl-c\">   But it turned out to be the visitor pattern.</span>\n<span class=\"pl-c\">   Oh, I forgot Java's generics are not reified.</span>\n<span class=\"pl-c\"></span>\n<span class=\"pl-c\">   If Java had reified generics:</span>\n<span class=\"pl-c\"></span>\n<span class=\"pl-c\">       class Shishᴰ</span>\n<span class=\"pl-c\">       {</span>\n<span class=\"pl-c\">           &#x3C;S: Shishᴰ> boolean onlyOnions(S s)</span>\n<span class=\"pl-c\">           {</span>\n<span class=\"pl-c\">               if (s instanceof Sewer)</span>\n<span class=\"pl-c\">               {</span>\n<span class=\"pl-c\">                   return true;</span>\n<span class=\"pl-c\">               }</span>\n<span class=\"pl-c\">               else if (s instanceof Onion)</span>\n<span class=\"pl-c\">               {</span>\n<span class=\"pl-c\">                   return onlyOnions(s.s);</span>\n<span class=\"pl-c\">               }</span>\n<span class=\"pl-c\">               else</span>\n<span class=\"pl-c\">               {</span>\n<span class=\"pl-c\">                   return false;</span>\n<span class=\"pl-c\">               }</span>\n<span class=\"pl-c\">           }</span>\n<span class=\"pl-c\">       }</span>\n<span class=\"pl-c\"> */</span>\n\n\n\n<span class=\"pl-c\">/* This is for the loyal Schemers and MLers. */</span>\n\n<span class=\"pl-k\">interface</span> <span class=\"pl-en\">Tᴵ</span>\n{\n    <span class=\"pl-c\">// It seems Java does not allow unicode arrows in identity name.</span>\n    <span class=\"pl-c\">// So we use the Chinese character `一` (one), which has a similar shape.</span>\n    o一oᴵ <span class=\"pl-en\">apply</span>(<span class=\"pl-smi\">Tᴵ</span> <span class=\"pl-v\">x</span>);\n}\n\n<span class=\"pl-k\">interface</span> <span class=\"pl-en\">o一oᴵ</span>\n{\n    <span class=\"pl-smi\">Object</span> <span class=\"pl-en\">apply</span>(<span class=\"pl-smi\">Object</span> <span class=\"pl-v\">x</span>);\n}\n\n<span class=\"pl-k\">interface</span> <span class=\"pl-en\">oo一ooᴵ</span>\n{\n    o一oᴵ <span class=\"pl-en\">apply</span>(<span class=\"pl-v\">o一oᴵ</span> <span class=\"pl-v\">x</span>);\n}\n\n<span class=\"pl-k\">interface</span> <span class=\"pl-en\">oo一oo一ooᴵ</span>\n{\n    o一oᴵ <span class=\"pl-en\">apply</span>(<span class=\"pl-v\">oo一ooᴵ</span> <span class=\"pl-v\">x</span>);\n}\n\n<span class=\"pl-k\">class</span> <span class=\"pl-en\">Y</span> <span class=\"pl-k\">implements</span> oo一oo一ooᴵ\n{\n    <span class=\"pl-k\">public</span> o一oᴵ <span class=\"pl-en\">apply</span>(<span class=\"pl-v\">oo一ooᴵ</span> <span class=\"pl-v\">f</span>)\n    {\n        <span class=\"pl-k\">return</span> <span class=\"pl-k\">new</span> <span class=\"pl-smi\">H</span>(f)<span class=\"pl-k\">.</span>apply(<span class=\"pl-k\">new</span> <span class=\"pl-smi\">H</span>(f));\n    }\n}\n\n<span class=\"pl-k\">class</span> <span class=\"pl-en\">H</span> <span class=\"pl-k\">implements</span> <span class=\"pl-e\">Tᴵ</span>\n{\n    oo一ooᴵ f;\n    <span class=\"pl-c1\">H</span>(oo一ooᴵ _f)\n    {\n        f <span class=\"pl-k\">=</span> _f;\n    }\n\n    public o一oᴵ apply(<span class=\"pl-smi\">Tᴵ</span> x)\n    {\n        return f.<span class=\"pl-en\">apply</span>(<span class=\"pl-v\">new</span> <span class=\"pl-smi\">G</span>(<span class=\"pl-v\">x</span>));\n    }\n}\n\n<span class=\"pl-k\">class</span> <span class=\"pl-en\">G</span> <span class=\"pl-k\">implements</span> o一oᴵ\n{\n    <span class=\"pl-smi\">Tᴵ</span> x;\n\n    <span class=\"pl-c1\">G</span>(<span class=\"pl-smi\">Tᴵ</span> _x)\n    {\n        x <span class=\"pl-k\">=</span> _x;\n    }\n\n    public Object apply(<span class=\"pl-smi\">Object</span> y)\n    {\n        <span class=\"pl-en\">return</span> (<span class=\"pl-v\">x</span>.<span class=\"pl-v\">apply</span>(<span class=\"pl-v\">x</span>)).<span class=\"pl-en\">apply</span>(<span class=\"pl-v\">y</span>);\n    }\n}\n\n<span class=\"pl-k\">class</span> <span class=\"pl-en\">MKFact</span> <span class=\"pl-k\">implements</span> oo一ooᴵ\n{\n    <span class=\"pl-k\">public</span> o一oᴵ <span class=\"pl-en\">apply</span>(<span class=\"pl-v\">o一oᴵ</span> <span class=\"pl-v\">fact</span>)\n    {\n        <span class=\"pl-k\">return</span> <span class=\"pl-k\">new</span> <span class=\"pl-smi\">Fact</span>(fact);\n    }\n}\n\n<span class=\"pl-k\">class</span> <span class=\"pl-en\">Fact</span> <span class=\"pl-k\">implements</span> o一oᴵ\n{\n    o一oᴵ fact;\n    <span class=\"pl-en\">Fact</span>(<span class=\"pl-v\">o一oᴵ</span> <span class=\"pl-v\">_fact</span>)\n    {\n        fact <span class=\"pl-k\">=</span> _fact;\n    }\n\n    <span class=\"pl-k\">public</span> <span class=\"pl-smi\">Object</span> <span class=\"pl-en\">apply</span>(<span class=\"pl-smi\">Object</span> <span class=\"pl-v\">i</span>)\n    {\n        <span class=\"pl-k\">int</span> inti <span class=\"pl-k\">=</span> ((<span class=\"pl-smi\">Integer</span>) i)<span class=\"pl-k\">.</span>intValue();\n        <span class=\"pl-k\">if</span> (inti <span class=\"pl-k\">==</span> <span class=\"pl-c1\">0</span>)\n        {\n            <span class=\"pl-k\">return</span> <span class=\"pl-k\">new</span> <span class=\"pl-smi\">Integer</span>(<span class=\"pl-c1\">1</span>);\n        }\n        <span class=\"pl-k\">else</span>\n        {\n            <span class=\"pl-k\">return</span>\n                <span class=\"pl-k\">new</span> <span class=\"pl-smi\">Integer</span>(\n                    inti\n                    <span class=\"pl-k\">*</span>\n                    ((<span class=\"pl-smi\">Integer</span>)\n                        fact<span class=\"pl-k\">.</span>apply(<span class=\"pl-k\">new</span> <span class=\"pl-smi\">Integer</span>(inti <span class=\"pl-k\">-</span> <span class=\"pl-c1\">1</span>)))<span class=\"pl-k\">.</span>intValue());\n        }\n    }\n}\n\n<span class=\"pl-c\">// Try to figure out how the above code works.</span>\n<span class=\"pl-c\">// First the concrete one `Fact`.</span>\n<span class=\"pl-c\">// To construct a `Fact`, we need a `fact`.</span>\n<span class=\"pl-c\">// Suppose we already have `fact`, then we call `fact.apply(n - 1)`.</span>\n<span class=\"pl-c\">// To successfully continue the recursion,</span>\n<span class=\"pl-c\">// `fact.apply(n - 1)` should be equivalent to something like `New Fact(...).apply(n - 1)`.</span>\n<span class=\"pl-c\">// Oh! We need to construct a new `Fact`, which requires a `fact` again.</span>\n<span class=\"pl-c\">// But wait. We already have `fact`, so we can reuse it.</span>\n<span class=\"pl-c\">// That's it -- self reference.</span>\n<span class=\"pl-k\">class</span> <span class=\"pl-en\">Dummy</span> <span class=\"pl-k\">implements</span> o一oᴵ\n{\n    <span class=\"pl-k\">public</span> <span class=\"pl-smi\">Object</span> <span class=\"pl-en\">apply</span>(<span class=\"pl-smi\">Object</span> <span class=\"pl-v\">x</span>)\n    {\n        <span class=\"pl-k\">return</span> <span class=\"pl-k\">new</span> <span class=\"pl-smi\">Fact</span>(<span class=\"pl-c1\">this</span>)<span class=\"pl-k\">.</span>apply(x);\n    }\n}\n\n<span class=\"pl-c\">// It works.</span>\n<span class=\"pl-c\">// And it also what `MKFact.apply` needs.</span>\n<span class=\"pl-c\">//</span>\n<span class=\"pl-c\">// Let's move on.</span>\n<span class=\"pl-c\">// `Fact` implements `o一oᴵ`, and `MKFact` implements `oo一ooᴵ`.</span>\n<span class=\"pl-c\">// `o一oᴵ` is like a constructor,</span>\n<span class=\"pl-c\">// and `oo一ooᴵ` is like a higher-order function taking a function and returning a function.</span>\n<span class=\"pl-c\">// Similarly, `oo一oo一ooᴵ` is like a function taking a higher-order function that takes a function and returning a function.</span>\n<span class=\"pl-c\">// Also `Tᴵ` is like a higher-order function returning a function.</span>\n<span class=\"pl-c\">//</span>\n<span class=\"pl-c\">// Now is the `Y`, `H`, `G` classes.</span>\n<span class=\"pl-c\">// Our `Dummy` class works, but it makes `MKFact` redundant.</span>\n<span class=\"pl-c\">// We need to find a way to produce `Fact` from `MKFact` without defining extra classes.</span>\n<span class=\"pl-c\">// Let's look at the types.</span>\n<span class=\"pl-c\">// `Fact` implements `o一oᴵ`, and `MKFact` implements `oo一ooᴵ`.</span>\n<span class=\"pl-c\">// So we need something that takes `oo一ooᴵ` and returns `o一oᴵ`, a.k.a `oo一ooᴵ -> o一oᴵ`.</span>\n<span class=\"pl-c\">// `Y.apply` happens to have such a signature.</span>\n<span class=\"pl-c\">// Thus probably we can get a `Fact` through `new Y().apply(new MKFact())`?</span>\n<span class=\"pl-c\">// And it works.</span>\n<span class=\"pl-c\">// Why?</span>\n<span class=\"pl-c\">// Revisit our `Dummy` class.</span>\n<span class=\"pl-c\">// In `New Fact(new Dummy())`, `(new Dummy).apply` calls back `New Fact(this)`.</span>\n<span class=\"pl-c\">// Next we demonstrate `new Y().apply(new MKFact())` is an equivalent form without `this`.</span>\n<span class=\"pl-c\">// And by the definition of `Y`, `new Y().apply(new MKFact())` is `new MKFact().apply(new G(new H(new MKFact())))`.</span>\n<span class=\"pl-c\">// Let `x = new G(new H(new MKFact()))`, we have `new MKFact().apply(x)`.</span>\n<span class=\"pl-c\">// By the definition of `MKFact`, it is `new Fact(x)`.</span>\n<span class=\"pl-c\">// Then we check what is `new Fact(x).apply(n)`.</span>\n<span class=\"pl-c\">// Fill in the value of `x`, it is `new Fact(new G(new H(new MKFact())).apply(n)`.</span>\n<span class=\"pl-c\">// By the definition of `Fact`, it is `new G(new H(new MKFact())).apply(n)`.</span>\n<span class=\"pl-c\">// By the definition of `G`, it is `new H(new MKFact()).apply(new H(new MKFact())).apply(n)`.</span>\n<span class=\"pl-c\">// By the definition of `H`, it is `new MKFact().apply(new G(new H(new MKFact()))).apply(n)`.</span>\n<span class=\"pl-c\">// By the definition of `MKFact`, it is `new Fact(x).apply(n)`.</span>\n<span class=\"pl-c\">// That is it. Self-referring to `Fact` itself without using `this`!</span>\n<span class=\"pl-c\">//</span>\n<span class=\"pl-c\">// This is the mighty Y combinator.</span>\n<span class=\"pl-c\">// The scheme version is in The Little Schemer, chapter 9.</span>\n<span class=\"pl-c\">//</span>\n<span class=\"pl-c\">// Let's walk through the reinvention of it in Java.</span>\n<span class=\"pl-c\">//</span>\n<span class=\"pl-c\">// First let's write a straightforward recursion version of `fact`.</span>\n<span class=\"pl-k\">class</span> <span class=\"pl-en\">StaticFact</span>\n{\n    <span class=\"pl-k\">static</span> <span class=\"pl-k\">int</span> <span class=\"pl-en\">fact</span>(<span class=\"pl-k\">int</span> <span class=\"pl-v\">n</span>)\n    {\n        <span class=\"pl-k\">if</span> (n <span class=\"pl-k\">==</span> <span class=\"pl-c1\">0</span>)\n        {\n            <span class=\"pl-k\">return</span> <span class=\"pl-c1\">1</span>;\n        }\n        <span class=\"pl-k\">else</span>\n        {\n            <span class=\"pl-k\">return</span> n <span class=\"pl-k\">*</span> fact(n <span class=\"pl-k\">-</span> <span class=\"pl-c1\">1</span>);\n        }\n    }\n}\n\n<span class=\"pl-c\">// Hmm, we haven't introduced static method in this book.</span>\n<span class=\"pl-c\">// We did mention using static method like `Math.max` in footnotes,</span>\n<span class=\"pl-c\">// but we never explain how to *declare* a static method.</span>\n<span class=\"pl-c\">// Thus we changed it to a non static version.</span>\n<span class=\"pl-c\">// The definition is almost the same.</span>\n<span class=\"pl-k\">class</span> <span class=\"pl-en\">NormalFact</span>\n{\n    <span class=\"pl-k\">int</span> <span class=\"pl-en\">fact</span>(<span class=\"pl-k\">int</span> <span class=\"pl-v\">n</span>)\n    {\n        <span class=\"pl-k\">if</span> (n <span class=\"pl-k\">==</span> <span class=\"pl-c1\">0</span>)\n        {\n            <span class=\"pl-k\">return</span> <span class=\"pl-c1\">1</span>;\n        }\n        <span class=\"pl-k\">else</span>\n        {\n            <span class=\"pl-k\">return</span> n <span class=\"pl-k\">*</span> fact(n <span class=\"pl-k\">-</span> <span class=\"pl-c1\">1</span>);\n        }\n    }\n}\n\n<span class=\"pl-c\">// We refer `fact` itself in function body, which is not possible in lambda calculus.</span>\n<span class=\"pl-c\">// So we pass a function as parameter instead.</span>\n<span class=\"pl-c\">// Oh, no! Java dose not support first class function.</span>\n<span class=\"pl-c\">// Hmm, in fact we could pass a function via the reflection API, or as a lambda in Java 8.</span>\n<span class=\"pl-c\">// But none of them is available when this book is written.</span>\n<span class=\"pl-c\">// Thus we wrap the function in a class.</span>\n<span class=\"pl-c\">// Note that we do not need a separate class.</span>\n<span class=\"pl-k\">class</span> <span class=\"pl-en\">Fact1</span>\n{\n    <span class=\"pl-k\">int</span> <span class=\"pl-en\">apply</span>(<span class=\"pl-smi\">Fact1</span> <span class=\"pl-v\">f</span>, <span class=\"pl-k\">int</span> <span class=\"pl-v\">n</span>)\n    {\n        <span class=\"pl-k\">if</span> (n <span class=\"pl-k\">==</span> <span class=\"pl-c1\">0</span>)\n        {\n            <span class=\"pl-k\">return</span> <span class=\"pl-c1\">1</span>;\n        }\n        <span class=\"pl-k\">else</span>\n        {\n            <span class=\"pl-k\">return</span> n <span class=\"pl-k\">*</span> f<span class=\"pl-k\">.</span>apply(f, n <span class=\"pl-k\">-</span> <span class=\"pl-c1\">1</span>);\n        }\n    }\n}\n<span class=\"pl-c\">// Nice!</span>\n<span class=\"pl-c\">// But lambda can only accept one parameter.</span>\n<span class=\"pl-c\">// We need to change `Fact1.apply` to return a function.</span>\n<span class=\"pl-c\">// Again in Java we return a wrapped class instead.</span>\n<span class=\"pl-c\">// To make future changes easier,</span>\n<span class=\"pl-c\">// we declare an additional interface instead of using hard-coded class.</span>\n<span class=\"pl-k\">interface</span> <span class=\"pl-en\">Fact2ᴵ</span>\n{\n    <span class=\"pl-k\">int</span> <span class=\"pl-en\">apply</span>(<span class=\"pl-k\">int</span> <span class=\"pl-v\">n</span>);\n}\n<span class=\"pl-k\">class</span> <span class=\"pl-en\">NClosure</span> <span class=\"pl-k\">implements</span> <span class=\"pl-e\">Fact2ᴵ</span>\n{\n    <span class=\"pl-smi\">Fact2</span> f;\n    <span class=\"pl-en\">NClosure</span>(<span class=\"pl-smi\">Fact2</span> <span class=\"pl-v\">_f</span>)\n    {\n        f <span class=\"pl-k\">=</span> _f;\n    }\n\n    <span class=\"pl-k\">public</span> <span class=\"pl-k\">int</span> <span class=\"pl-en\">apply</span>(<span class=\"pl-k\">int</span> <span class=\"pl-v\">n</span>)\n    {\n        <span class=\"pl-k\">if</span> (n <span class=\"pl-k\">==</span> <span class=\"pl-c1\">0</span>)\n        {\n            <span class=\"pl-k\">return</span> <span class=\"pl-c1\">1</span>;\n        }\n        <span class=\"pl-k\">else</span>\n        {\n            <span class=\"pl-k\">return</span> n <span class=\"pl-k\">*</span> (f<span class=\"pl-k\">.</span>apply(f))<span class=\"pl-k\">.</span>apply(n <span class=\"pl-k\">-</span> <span class=\"pl-c1\">1</span>);\n        }\n    }\n}\n<span class=\"pl-k\">class</span> <span class=\"pl-en\">Fact2</span>\n{\n    <span class=\"pl-smi\">Fact2ᴵ</span> <span class=\"pl-en\">apply</span>(<span class=\"pl-smi\">Fact2</span> <span class=\"pl-v\">f</span>)\n    {\n        <span class=\"pl-k\">return</span> <span class=\"pl-k\">new</span> <span class=\"pl-smi\">NClosure</span>(f);\n    }\n}\n<span class=\"pl-c\">// This is the poor man's Y combinator.</span>\n\n<span class=\"pl-c\">// Look at this line `return n * (f.apply(f)).apply(n - 1);`,</span>\n<span class=\"pl-c\">// if it is `g.apply(n - 1)` then it would be similar to the original recursion version.</span>\n<span class=\"pl-c\">// Let's `g = f.apply(f)`:</span>\n<span class=\"pl-k\">class</span> <span class=\"pl-en\">GG</span> <span class=\"pl-k\">implements</span> <span class=\"pl-e\">Fact2ᴵ</span>\n{\n    <span class=\"pl-smi\">Fact3</span> f;\n    <span class=\"pl-c1\">GG</span>(<span class=\"pl-smi\">Fact3</span> _f)\n    {\n        f <span class=\"pl-k\">=</span> _f;\n    }\n\n    public int apply(<span class=\"pl-k\">int</span> n)\n    {\n        <span class=\"pl-en\">return</span> (<span class=\"pl-v\">f</span>.<span class=\"pl-v\">apply</span>(<span class=\"pl-v\">f</span>)).<span class=\"pl-en\">apply</span>(<span class=\"pl-v\">n</span>);\n    }\n}\n<span class=\"pl-k\">class</span> <span class=\"pl-en\">Fact3</span>\n{\n    <span class=\"pl-smi\">Fact2ᴵ</span> <span class=\"pl-en\">apply</span>(<span class=\"pl-smi\">Fact3</span> <span class=\"pl-v\">f</span>)\n    {\n        <span class=\"pl-k\">return</span> <span class=\"pl-k\">new</span> <span class=\"pl-smi\">GClosure</span>(f);\n    }\n}\n\n<span class=\"pl-k\">class</span> <span class=\"pl-en\">GClosure</span> <span class=\"pl-k\">implements</span> <span class=\"pl-e\">Fact2ᴵ</span>\n{\n    <span class=\"pl-smi\">Fact3</span> f;\n    <span class=\"pl-c1\">GG</span> g;\n    <span class=\"pl-en\">GClosure</span>(<span class=\"pl-smi\">Fact3</span> <span class=\"pl-v\">_f</span>)\n    {\n        f <span class=\"pl-k\">=</span> _f;\n        g <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> <span class=\"pl-smi\">GG</span>(f);\n    }\n\n    <span class=\"pl-k\">public</span> <span class=\"pl-k\">int</span> <span class=\"pl-en\">apply</span>(<span class=\"pl-k\">int</span> <span class=\"pl-v\">n</span>)\n    {\n        <span class=\"pl-k\">if</span> (n <span class=\"pl-k\">==</span> <span class=\"pl-c1\">0</span>)\n        {\n            <span class=\"pl-k\">return</span> <span class=\"pl-c1\">1</span>;\n        }\n        <span class=\"pl-k\">else</span>\n        {\n            <span class=\"pl-k\">return</span> n <span class=\"pl-k\">*</span> g<span class=\"pl-k\">.</span>apply(n <span class=\"pl-k\">-</span> <span class=\"pl-c1\">1</span>);\n        }\n    }\n}\n\n<span class=\"pl-c\">// We are almost done.</span>\n<span class=\"pl-c\">// `GClosure.apply()` is the recursion definition we want.</span>\n<span class=\"pl-c\">// Let's create something that takes a `GClosure`.</span>\n<span class=\"pl-k\">class</span> <span class=\"pl-en\">YY</span>\n{\n    <span class=\"pl-smi\">Fact2ᴵ</span> f;\n    <span class=\"pl-c1\">YY</span>(<span class=\"pl-smi\">Fact2ᴵ</span> _f)\n    {\n        f <span class=\"pl-k\">=</span> _f;\n    }\n\n    int apply(<span class=\"pl-k\">int</span> n)\n    {\n        return f.<span class=\"pl-en\">apply</span>(<span class=\"pl-v\">n</span>);\n    }\n}\n<span class=\"pl-c\">// Hmm, the problem is we still need `Fact3`, whose definition hard coded reference to `GClosure`.</span>\n<span class=\"pl-c\">// We could made the constructor of `Fact3` taking `GClosure` as a parameter.</span>\n<span class=\"pl-c\">// That is, to construct a `Fact3`, we need a `GClosure`,</span>\n<span class=\"pl-c\">// and to construct a `GClosure`, we need a `Fact3`.</span>\n<span class=\"pl-c\">// Now if we make `Fact3` and `GClosure` one thing, it will be self-referral.</span>\n<span class=\"pl-k\">class</span> <span class=\"pl-en\">Fact0</span> <span class=\"pl-k\">implements</span> <span class=\"pl-e\">Fact2ᴵ</span>\n{\n    <span class=\"pl-smi\">Fact2ᴵ</span> g;\n    <span class=\"pl-en\">Fact0</span>(<span class=\"pl-smi\">Fact2ᴵ</span> <span class=\"pl-v\">_g</span>)\n    {\n        g <span class=\"pl-k\">=</span> _g;\n    }\n\n    <span class=\"pl-k\">public</span> <span class=\"pl-k\">int</span> <span class=\"pl-en\">apply</span>(<span class=\"pl-k\">int</span> <span class=\"pl-v\">n</span>)\n    {\n        <span class=\"pl-k\">if</span> (n <span class=\"pl-k\">==</span> <span class=\"pl-c1\">0</span>)\n        {\n            <span class=\"pl-k\">return</span> <span class=\"pl-c1\">1</span>;\n        }\n        <span class=\"pl-k\">else</span>\n        {\n            <span class=\"pl-k\">return</span> n <span class=\"pl-k\">*</span> g<span class=\"pl-k\">.</span>apply(n <span class=\"pl-k\">-</span> <span class=\"pl-c1\">1</span>);\n        }\n    }\n}\n<span class=\"pl-c\">// Now the tricky part is constructing `Fact0(_f)`.</span>\n<span class=\"pl-c\">// Again this smells like self-reference.</span>\n<span class=\"pl-c\">// Just as we introduced an additional function as parameter before,</span>\n<span class=\"pl-c\">// to construct `Fact0(_f)` we probably need an additional function.</span>\n<span class=\"pl-k\">class</span> <span class=\"pl-en\">MKFact0</span>\n{\n    <span class=\"pl-smi\">Fact2ᴵ</span> <span class=\"pl-en\">apply</span>(<span class=\"pl-smi\">Fact2ᴵ</span> <span class=\"pl-v\">fact2ᴵ</span>)\n    {\n        <span class=\"pl-k\">return</span> <span class=\"pl-k\">new</span> <span class=\"pl-smi\">Fact0</span>(fact2ᴵ);\n    }\n}\n<span class=\"pl-c\">// Now we need to define `Y0` such that `new Y0().apply(new MKFact0())` will construct a `Fact0`.</span>\n<span class=\"pl-c\">// It is hard to write the `apply` method of `Y0`.</span>\n<span class=\"pl-c\">// Let's go back to last iteration.</span>\n<span class=\"pl-c\">// `GG` is not abstract. It has `Fact3` hard coded in its definition.</span>\n<span class=\"pl-c\">// Let's refactor it.</span>\n<span class=\"pl-k\">class</span> <span class=\"pl-en\">G0</span> <span class=\"pl-k\">implements</span> <span class=\"pl-e\">Fact2ᴵ</span>\n{\n    <span class=\"pl-smi\">Fact2ᴵ</span> g;\n    <span class=\"pl-c1\">G0</span>(<span class=\"pl-smi\">Fact2ᴵ</span> _g)\n    {\n        g <span class=\"pl-k\">=</span> _g;\n    }\n\n    public int apply(<span class=\"pl-k\">int</span> n)\n    {\n        <span class=\"pl-en\">return</span> (<span class=\"pl-v\">g</span>.<span class=\"pl-v\">apply</span>(<span class=\"pl-v\">g</span>)).<span class=\"pl-en\">apply</span>(<span class=\"pl-v\">n</span>);\n    }\n}\n<span class=\"pl-c\">// Oops! `g.apply(g)` is invalid.</span>\n<span class=\"pl-c\">// From here we may try to rewrite `G0`.</span>\n<span class=\"pl-c\">// Or we may try to rewrite `Fact2ᴵ`, `int -> int` is too restrictive,</span>\n<span class=\"pl-c\">// i.e. if we cannot solve a specific problem,</span>\n<span class=\"pl-c\">// try to solve its more general form.</span>\n\n<span class=\"pl-c\">// Rewrite `Fact2ᴵ`, substitute `int` with `Object`, we get `o一oᴵ`.</span>\n<span class=\"pl-c\">// Change `Fact0` and `MKFact0` accordingly, we get `Fact` and `MKFact`.</span>\n<span class=\"pl-c\">// `Fact` implements `o一oᴵ`, we need to define an interface for `MKFact` as well. That is `oo一ooᴵ`.</span>\n<span class=\"pl-c\">// Now we try to rewrite `G0`.</span>\n<span class=\"pl-c\">// We find that `g.apply(g)` still cause type mismatch.</span>\n<span class=\"pl-c\">// `g` cannot be an ordinary `Object`, which may no have an `apply` method defined.</span>\n<span class=\"pl-c\">// Also `g` cannot be an `o一oᴵ`, which cannot take itself (`o一oᴵ`) as a parameter.</span>\n<span class=\"pl-c\">// Thus we need a new type (interface).</span>\n<span class=\"pl-c\">// An interface whose `apply` method takes anything (an `Object`) and returns an `o一oᴵ`.</span>\n<span class=\"pl-c\">// Thus we have `Tᴵ`.</span>\n<span class=\"pl-c\">// Then we look at `Y`.</span>\n<span class=\"pl-c\">// We still dose not know how to write its `apply` method, but we know the signature of it.</span>\n<span class=\"pl-c\">// It takes `MKFact`, a.k.a. `oo一ooᴵ`, and returns `Fact`, a.k.a. `o一oᴵ`.</span>\n<span class=\"pl-c\">// Thus we have `oo一oo一ooᴵ`.</span>\n<span class=\"pl-c\">//</span>\n<span class=\"pl-c\">// We try to pass `MKFact` to `G`, `new G(new MKFact())`.</span>\n<span class=\"pl-c\">// Not possible. We need a bridge to connect `oo一ooᴵ` and `Tᴵ`,</span>\n<span class=\"pl-c\">// i.e. something takes a `MKFact` a.k.a. `oo一ooᴵ` and produces a `Tᴵ` for `G`.</span>\n<span class=\"pl-k\">class</span> <span class=\"pl-en\">H</span> <span class=\"pl-k\">implements</span> <span class=\"pl-e\">Tᴵ</span>\n{\n    oo一ooᴵ f;\n    <span class=\"pl-c1\">H</span>(oo一ooᴵ _f)\n    {\n        f <span class=\"pl-k\">=</span> _f;\n    }\n\n    public o一oᴵ apply(<span class=\"pl-smi\">Tᴵ</span> x)\n    {\n        <span class=\"pl-k\">return</span> <span class=\"pl-c1\">...</span>;\n    }\n}\n<span class=\"pl-c\">// Now we need to fill in the missing `apply` definition for `H`.</span>\n<span class=\"pl-c\">// It returns `o一oᴵ`. Do we have something returns `o一oᴵ`?</span>\n<span class=\"pl-c\">// `f.apply` happens to produce `o一oᴵ`.</span>\n<span class=\"pl-k\">class</span> <span class=\"pl-en\">H</span> <span class=\"pl-k\">implements</span> <span class=\"pl-e\">Tᴵ</span>\n{\n    oo一ooᴵ f;\n    <span class=\"pl-c1\">H</span>(oo一ooᴵ _f)\n    {\n        f <span class=\"pl-k\">=</span> _f;\n    }\n\n    public o一oᴵ apply(<span class=\"pl-smi\">Tᴵ</span> x)\n    {\n        return f.<span class=\"pl-en\">apply</span>(...);\n    }\n}\n<span class=\"pl-c\">// `f.apply()` takes an `o一oᴵ`. Do we have something to transform `Tᴵ` to `o一oᴵ`?</span>\n<span class=\"pl-c\">// The `apply` method of `Tᴵ`.</span>\n<span class=\"pl-c\">// Do we have some class implements `Tᴵ`, except `H` itself?</span>\n<span class=\"pl-c\">// No.</span>\n<span class=\"pl-c\">// So we need to implement one?</span>\n<span class=\"pl-c\">// Wait. `G` implements `o一oᴵ` and its construction method takes `Tᴵ` as parameter.</span>\n<span class=\"pl-c\">// So `new G(x)` fills in the gap.</span>\n<span class=\"pl-k\">class</span> <span class=\"pl-en\">H</span> <span class=\"pl-k\">implements</span> <span class=\"pl-e\">Tᴵ</span>\n{\n    oo一ooᴵ f;\n    <span class=\"pl-c1\">H</span>(oo一ooᴵ _f)\n    {\n        f <span class=\"pl-k\">=</span> _f;\n    }\n\n    public o一oᴵ apply(<span class=\"pl-smi\">Tᴵ</span> x)\n    {\n        return f.<span class=\"pl-en\">apply</span>(<span class=\"pl-v\">new</span> <span class=\"pl-smi\">G</span>(<span class=\"pl-v\">x</span>));\n    }\n}\n<span class=\"pl-c\">// In fact, this is the very definition given in the book.</span>\n<span class=\"pl-c\">//</span>\n<span class=\"pl-c\">// At last, let's complete `Y`.</span>\n<span class=\"pl-k\">class</span> <span class=\"pl-en\">Y</span> <span class=\"pl-k\">implements</span> oo一oo一ooᴵ\n{\n    <span class=\"pl-k\">public</span> o一oᴵ <span class=\"pl-en\">apply</span>(<span class=\"pl-v\">oo一ooᴵ</span> <span class=\"pl-v\">f</span>)\n    {\n        <span class=\"pl-k\">return</span> <span class=\"pl-c1\">...</span>;\n    }\n}\n<span class=\"pl-c\">// We need something takes `oo一ooᴵ` and produces `o一oᴵ`.</span>\n<span class=\"pl-c\">// `H` takes `oo一ooᴵ` in its construction method, and produces `o一oᴵ` by its `apply` method.</span>\n<span class=\"pl-k\">class</span> <span class=\"pl-en\">Y</span> <span class=\"pl-k\">implements</span> oo一oo一ooᴵ\n{\n    <span class=\"pl-k\">public</span> o一oᴵ <span class=\"pl-en\">apply</span>(<span class=\"pl-v\">oo一ooᴵ</span> <span class=\"pl-v\">f</span>)\n    {\n        <span class=\"pl-k\">return</span> <span class=\"pl-k\">new</span> <span class=\"pl-smi\">H</span>(f)<span class=\"pl-k\">.</span>apply(<span class=\"pl-c1\">...</span>);\n    }\n}\n<span class=\"pl-c\">// The parameter of `H(f).apply()` need to be a `Tᴵ`.</span>\n<span class=\"pl-c\">// Do we have something implements `Tᴵ`?</span>\n<span class=\"pl-c\">// `H` itself.</span>\n<span class=\"pl-c\">// So</span>\n<span class=\"pl-k\">class</span> <span class=\"pl-en\">Y</span> <span class=\"pl-k\">implements</span> oo一oo一ooᴵ\n{\n    <span class=\"pl-k\">public</span> o一oᴵ <span class=\"pl-en\">apply</span>(<span class=\"pl-v\">oo一ooᴵ</span> <span class=\"pl-v\">f</span>)\n    {\n        <span class=\"pl-k\">return</span> <span class=\"pl-k\">new</span> <span class=\"pl-smi\">H</span>(f)<span class=\"pl-k\">.</span>apply(<span class=\"pl-k\">new</span> <span class=\"pl-smi\">H</span>(f));\n    }\n}\n<span class=\"pl-c\">// The very definition given in the book.</span>\n\n<span class=\"pl-c\">// If you still have difficulties to understand it in Java,</span>\n<span class=\"pl-c\">// try use another language.</span>\n<span class=\"pl-c\">// For example,</span>\n<span class=\"pl-c\">//</span>\n<span class=\"pl-c\">// ```js</span>\n<span class=\"pl-c\">// // Poor man's Y combinator</span>\n<span class=\"pl-c\">// ((f => n => n == 0 ? 1 : n * f(f)(n - 1))</span>\n<span class=\"pl-c\">//   (f => n => n == 0 ? 1 : 0 * f(f)(n - 1))</span>\n<span class=\"pl-c\">//   3)</span>\n<span class=\"pl-c\">// ```</span>\n<span class=\"pl-c\">//</span>\n<span class=\"pl-c\">// It would be perfect if it is `f(n -1)` instead of `f(f(n)(n - 1))`.</span>\n<span class=\"pl-c\">// Let `g = f(f)`:</span>\n<span class=\"pl-c\">//</span>\n<span class=\"pl-c\">// ```js</span>\n<span class=\"pl-c\">// ((f => ((g => n => n == 0 ? 1 : n * g(n - 1)) f(f))</span>\n<span class=\"pl-c\">//   # same as above</span>\n<span class=\"pl-c\">//   3)</span>\n<span class=\"pl-c\">// ```</span>\n<span class=\"pl-c\">//</span>\n<span class=\"pl-c\">// Hmm, `(g => n => n == 0 ? 1 : n * g(n - 1)` is just what we want!</span>\n<span class=\"pl-c\">// Let `h = (g => n => n == 0 ? 1 : n * g(n - 1)`:</span>\n<span class=\"pl-c\">//</span>\n<span class=\"pl-c\">// ```js</span>\n<span class=\"pl-c\">// (((h =></span>\n<span class=\"pl-c\">//    (f => h(f(f)))</span>\n<span class=\"pl-c\">//    (f => h(f(f))))</span>\n<span class=\"pl-c\">//      (g => n => n == 0 ? 1 : n * g(n - 1))</span>\n<span class=\"pl-c\">//      3)</span>\n<span class=\"pl-c\">// ```</span>\n<span class=\"pl-c\">//</span>\n<span class=\"pl-c\">// Look! The factorial logic is factor out: `(g => n => n == 0 ? 1 : n * g(n - 1))`.</span>\n<span class=\"pl-c\">// And this is the Y combinator.</span>\n<span class=\"pl-c\">//</span>\n<span class=\"pl-c\">// ```js</span>\n<span class=\"pl-c\">// Y =</span>\n<span class=\"pl-c\">//   (h =></span>\n<span class=\"pl-c\">//    (f => h(f(f)))</span>\n<span class=\"pl-c\">//    (f => h(f(f))))</span>\n<span class=\"pl-c\">// ```</span>\n<span class=\"pl-c\">//</span>\n<span class=\"pl-c\">// To construct `fact` with Y combinator: `Y(g => n => n == 0 ? 1 : n * g(n - 1))`.</span>\n<span class=\"pl-c\">//</span>\n<span class=\"pl-c\">// Hope this helps to understand those `Y`, `H`, `G` classes in Java.</span>\n\n<span class=\"pl-k\">public</span> <span class=\"pl-k\">class</span> <span class=\"pl-en\">LittleJava</span>\n{\n    <span class=\"pl-k\">public</span> <span class=\"pl-k\">static</span> <span class=\"pl-k\">void</span> <span class=\"pl-en\">main</span>(<span class=\"pl-k\">String</span>[] <span class=\"pl-v\">args</span>)\n    {\n        <span class=\"pl-smi\">Fact</span> fact <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> <span class=\"pl-smi\">Fact</span>(<span class=\"pl-k\">new</span> <span class=\"pl-smi\">Dummy</span>());\n        <span class=\"pl-smi\">System</span><span class=\"pl-k\">.</span>out<span class=\"pl-k\">.</span>println(fact<span class=\"pl-k\">.</span>apply(<span class=\"pl-k\">new</span> <span class=\"pl-smi\">Integer</span>(<span class=\"pl-c1\">5</span>)));\n        <span class=\"pl-smi\">MKFact</span> mKFact <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> <span class=\"pl-smi\">MKFact</span>();\n\n        <span class=\"pl-smi\">Fact</span> newFact <span class=\"pl-k\">=</span> (<span class=\"pl-smi\">Fact</span>) mKFact<span class=\"pl-k\">.</span>apply(<span class=\"pl-k\">new</span> <span class=\"pl-smi\">Dummy</span>());\n        <span class=\"pl-smi\">System</span><span class=\"pl-k\">.</span>out<span class=\"pl-k\">.</span>println(newFact<span class=\"pl-k\">.</span>apply(<span class=\"pl-k\">new</span> <span class=\"pl-smi\">Integer</span>(<span class=\"pl-c1\">5</span>)));\n\n        <span class=\"pl-smi\">Fact</span> yFact <span class=\"pl-k\">=</span> (<span class=\"pl-smi\">Fact</span>) <span class=\"pl-k\">new</span> <span class=\"pl-smi\">Y</span>()<span class=\"pl-k\">.</span>apply(<span class=\"pl-k\">new</span> <span class=\"pl-smi\">MKFact</span>());\n        <span class=\"pl-smi\">System</span><span class=\"pl-k\">.</span>out<span class=\"pl-k\">.</span>println(yFact<span class=\"pl-k\">.</span>apply(<span class=\"pl-k\">new</span> <span class=\"pl-smi\">Integer</span>(<span class=\"pl-c1\">5</span>)));\n\n        <span class=\"pl-smi\">System</span><span class=\"pl-k\">.</span>out<span class=\"pl-k\">.</span>println(<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>static recursion version<span class=\"pl-pds\">\"</span></span>);\n        <span class=\"pl-smi\">System</span><span class=\"pl-k\">.</span>out<span class=\"pl-k\">.</span>println(<span class=\"pl-smi\">StaticFact</span><span class=\"pl-k\">.</span>fact(<span class=\"pl-c1\">5</span>));\n\n        <span class=\"pl-smi\">System</span><span class=\"pl-k\">.</span>out<span class=\"pl-k\">.</span>println(<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>normal version<span class=\"pl-pds\">\"</span></span>);\n        <span class=\"pl-smi\">NormalFact</span> normalFact <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> <span class=\"pl-smi\">NormalFact</span>();\n        <span class=\"pl-smi\">System</span><span class=\"pl-k\">.</span>out<span class=\"pl-k\">.</span>println(normalFact<span class=\"pl-k\">.</span>fact(<span class=\"pl-c1\">5</span>));\n\n        <span class=\"pl-smi\">System</span><span class=\"pl-k\">.</span>out<span class=\"pl-k\">.</span>println(<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>Fact1<span class=\"pl-pds\">\"</span></span>);\n        <span class=\"pl-smi\">Fact1</span> fact1 <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> <span class=\"pl-smi\">Fact1</span>();\n        <span class=\"pl-smi\">System</span><span class=\"pl-k\">.</span>out<span class=\"pl-k\">.</span>println(fact1<span class=\"pl-k\">.</span>apply(fact1, <span class=\"pl-c1\">5</span>));\n\n        <span class=\"pl-smi\">System</span><span class=\"pl-k\">.</span>out<span class=\"pl-k\">.</span>println(<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>Fact2: poor man's Y combinator<span class=\"pl-pds\">\"</span></span>);\n        <span class=\"pl-smi\">Fact2</span> fact2 <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> <span class=\"pl-smi\">Fact2</span>();\n        <span class=\"pl-smi\">System</span><span class=\"pl-k\">.</span>out<span class=\"pl-k\">.</span>println((fact2<span class=\"pl-k\">.</span>apply(fact2))<span class=\"pl-k\">.</span>apply(<span class=\"pl-c1\">5</span>));\n\n        <span class=\"pl-smi\">System</span><span class=\"pl-k\">.</span>out<span class=\"pl-k\">.</span>println(<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>Fact3: g = f(f)<span class=\"pl-pds\">\"</span></span>);\n        <span class=\"pl-smi\">Fact3</span> fact3 <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> <span class=\"pl-smi\">Fact3</span>();\n        <span class=\"pl-smi\">System</span><span class=\"pl-k\">.</span>out<span class=\"pl-k\">.</span>println((fact3<span class=\"pl-k\">.</span>apply(fact3))<span class=\"pl-k\">.</span>apply(<span class=\"pl-c1\">5</span>));\n\n        <span class=\"pl-smi\">System</span><span class=\"pl-k\">.</span>out<span class=\"pl-k\">.</span>println(<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>YY<span class=\"pl-pds\">\"</span></span>);\n        <span class=\"pl-smi\">YY</span> yy <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> <span class=\"pl-smi\">YY</span>(<span class=\"pl-k\">new</span> <span class=\"pl-smi\">GClosure</span>(<span class=\"pl-k\">new</span> <span class=\"pl-smi\">Fact3</span>()));\n        <span class=\"pl-smi\">System</span><span class=\"pl-k\">.</span>out<span class=\"pl-k\">.</span>println(yy<span class=\"pl-k\">.</span>apply(<span class=\"pl-c1\">5</span>));\n    }\n}\n</code></pre>","date_published":"Sat, 25 Aug 2018 09:07:39 GMT","date_modified":"Sun, 05 Jul 2020 05:52:55 GMT"},{"id":"https://mmap.page/dive-into/go/","url":"https://mmap.page/dive-into/go/","title":"Quick Introduction to Go","content_html":"<h1>Quick Introduction to Go</h1>\n<p>We're going to try to quickly show you enough of Go 1.17 to actually try it out.</p>\n<h2>A Syntax Derived from C</h2>\n<p>The main difference to C is type annotation after identifier.</p>\n<pre><code class=\"language-go\"><span class=\"pl-k\">package</span> main\n<span class=\"pl-k\">import</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>fmt<span class=\"pl-pds\">\"</span></span>\n\n<span class=\"pl-k\">type</span> <span class=\"pl-v\">Point</span> <span class=\"pl-k\">struct</span> {\n\tx <span class=\"pl-k\">float64</span>\n\ty <span class=\"pl-k\">float64</span>\n}\n<span class=\"pl-k\">func</span> <span class=\"pl-en\">distance</span>(<span class=\"pl-v\">from</span> <span class=\"pl-v\">Point</span>, <span class=\"pl-v\">to</span> <span class=\"pl-v\">Point</span>) <span class=\"pl-v\">float64</span> {\n\t<span class=\"pl-k\">return</span> math.<span class=\"pl-c1\">Pow</span>(math.<span class=\"pl-c1\">Pow</span>(from.<span class=\"pl-smi\">x</span>-to.<span class=\"pl-smi\">x</span>, <span class=\"pl-c1\">2</span>)+math.<span class=\"pl-c1\">Pow</span>(from.<span class=\"pl-smi\">y</span>-to.<span class=\"pl-smi\">y</span>, <span class=\"pl-c1\">2</span>), <span class=\"pl-c1\">0.5</span>)\n}\n<span class=\"pl-c\">// You can only declare a method with a receiver defined in the same package.</span>\n<span class=\"pl-k\">func</span> <span class=\"pl-en\">(</span><span class=\"pl-v\">point</span> <span class=\"pl-v\">Point</span><span class=\"pl-en\">) Dist</span>(<span class=\"pl-v\">other</span> <span class=\"pl-v\">Point</span>) <span class=\"pl-v\">float64</span> {\n    <span class=\"pl-k\">return</span> math.<span class=\"pl-c1\">Pow</span>(math.<span class=\"pl-c1\">Pow</span>(point.<span class=\"pl-smi\">x</span>-other.<span class=\"pl-smi\">x</span>, <span class=\"pl-c1\">2</span>)+math.<span class=\"pl-c1\">Pow</span>(point.<span class=\"pl-smi\">y</span>-other.<span class=\"pl-smi\">y</span>, <span class=\"pl-c1\">2</span>), <span class=\"pl-c1\">0.5</span>)\n}\n\n<span class=\"pl-k\">func</span> <span class=\"pl-en\">main</span>() {\n    <span class=\"pl-k\">var</span> <span class=\"pl-smi\">point</span> Point = Point{<span class=\"pl-c1\">0.0</span>, <span class=\"pl-c1\">0.0</span>}\n    <span class=\"pl-k\">var</span> <span class=\"pl-smi\">zero</span> <span class=\"pl-k\">float64</span> = <span class=\"pl-c1\">distance</span>(Point{<span class=\"pl-c1\">0.0</span>, <span class=\"pl-c1\">0.0</span>}, Point{<span class=\"pl-c1\">2.0</span>, <span class=\"pl-c1\">3.0</span>}) - point.<span class=\"pl-c1\">Dist</span>(Point{<span class=\"pl-c1\">2.0</span>, <span class=\"pl-c1\">3.0</span>})\n    fmt.<span class=\"pl-c1\">Println</span>(<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>The entry point of an executable must be a function named `main` in a package named `main`.<span class=\"pl-pds\">\"</span></span>)\n</code></pre>\n<h2>Slice</h2>\n<pre><code class=\"language-go\"><span class=\"pl-smi\">names</span> <span class=\"pl-k\">:=</span> []<span class=\"pl-k\">string</span>{<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>Tom<span class=\"pl-pds\">\"</span></span>, <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>Dick<span class=\"pl-pds\">\"</span></span>, <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>Harry<span class=\"pl-pds\">\"</span></span>} <span class=\"pl-c\">// inferred type `[]T`</span>\n\n<span class=\"pl-c\">// Go reuses `:=` instead of a dedicated keyword `in`.</span>\n<span class=\"pl-c\">// `_` is called blank identifier,meaning we are not interested in indices of the slice.</span>\n<span class=\"pl-c\">// BTW, if we are not interested in the loop values, we can just write `for range names`.</span>\n<span class=\"pl-k\">for</span> <span class=\"pl-smi\">_</span>, <span class=\"pl-smi\">name</span> <span class=\"pl-k\">:=</span> <span class=\"pl-k\">range</span> names {\n    <span class=\"pl-c\">// Go does not have access modifiers.</span>\n    <span class=\"pl-c\">// Exported (public) names begin with a capital letter.</span>\n\tfmt.<span class=\"pl-c1\">Println</span>(<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>Hello, <span class=\"pl-pds\">\"</span></span> + name + <span class=\"pl-s\"><span class=\"pl-pds\">\"</span> !<span class=\"pl-pds\">\"</span></span>)\n}\n</code></pre>\n<p>The slice uses an underlying array to store data.\nThe length of an array <code>[n]T</code> is part of its type, so arrays cannot be resized.\nThus, slices are much more common than arrays.</p>\n<pre><code class=\"language-go\"><span class=\"pl-k\">type</span> slice <span class=\"pl-k\">struct</span> {\n    array unsafe.<span class=\"pl-smi\">Pointer</span>\n    <span class=\"pl-c1\">len</span>   <span class=\"pl-k\">int</span> <span class=\"pl-c\">// current length</span>\n    <span class=\"pl-c1\">cap</span>   <span class=\"pl-k\">int</span> <span class=\"pl-c\">// capacity, the length of the underlying array</span>\n}\n</code></pre>\n<p>Go has a built-in <code>append</code> function to add elements to a slice, modifying the underlying array directly, or replacing the underlying array with a new one with a larger capacity.</p>\n<pre><code class=\"language-go\"><span class=\"pl-c\">// pesudo code (pretend Go supports generics)</span>\n<span class=\"pl-k\">func</span> <span class=\"pl-en\">append</span>(<span class=\"pl-v\">slice</span> []<span class=\"pl-v\">T</span>, <span class=\"pl-v\">elements</span> ...<span class=\"pl-v\">T</span>) []<span class=\"pl-v\">T</span> {\n    <span class=\"pl-k\">for</span> <span class=\"pl-smi\">element</span> <span class=\"pl-k\">:=</span> <span class=\"pl-k\">range</span> elements {\n        slice.<span class=\"pl-smi\">len</span> += <span class=\"pl-c1\">1</span>\n        <span class=\"pl-k\">if</span> slice.<span class=\"pl-smi\">len</span> &#x3C;= slice.<span class=\"pl-smi\">cap</span> {\n            slice[<span class=\"pl-c1\">len</span>-<span class=\"pl-c1\">1</span>] = element\n        } <span class=\"pl-k\">else</span> {\n            <span class=\"pl-smi\">new_slice</span> <span class=\"pl-k\">:=</span> <span class=\"pl-c1\">make</span>([]T, (slice.<span class=\"pl-smi\">len</span>+<span class=\"pl-c1\">1</span>)*<span class=\"pl-c1\">2</span>)\n            <span class=\"pl-c1\">copy</span>(new_slice, slice)\n            slice = new_slice\n            slice[<span class=\"pl-c1\">len</span>-<span class=\"pl-c1\">1</span>] = element\n        }\n    }\n    <span class=\"pl-k\">return</span> slice\n}\n</code></pre>\n<p>To create a new slice:</p>\n<ol>\n<li>Use the slice expressions on an existing array: <code>a[n:m]</code>, <code>a[:m]</code>, <code>a[n:]</code>, and <code>a[:]</code>.</li>\n<li>Slice expressions can also specify capacity, <code>a[n:m:k]</code> or <code>a[:m:k]</code>. <code>k</code> must be less than or equal to the capacity of the source slice or array.</li>\n<li>The <code>make</code> allocates a zeroed array and returns a slice that refers to that array, e.g. <code>s := make([]int, 2, 5)</code>.</li>\n<li><code>var s []T</code> returns <code>nil</code>, the zero value of a slice. It has a length and capacity of 0 and has no underlying array.</li>\n</ol>\n<p>Similarly, the zero value of a map is also <code>nil</code> (<code>var m map[K]T</code>).\nAnd <code>make(map[K]T)</code> returns a map initialized and ready for use.</p>\n<p>Since re-slicing a slice doesn't make a copy of the underlying array, the full underlying array will be kept in memory until it is no longer referenced.\nOccasionally this can cause the program to hold all the data in memory when only a small piece of it is needed.\nIn that case, copy the data over to another new slice via <code>copy</code> or <code>append</code>.</p>\n<h3><code>make</code> and <code>new</code></h3>\n<p>Normally Go has two ways to create a non-primitive:</p>\n<ol>\n<li>Composite literals, e.g. <code>[]int{1, 2, 3}</code>, which creates an instance, are mostly used.</li>\n<li><code>new(T)</code> creates a zero value of <code>T</code> and returns a pointer <code>*T</code>, equivalent to <code>&#x26;T{}</code>.</li>\n</ol>\n<p>However, slices are special.\nAs shown above, composite literals like <code>[]int{1, 2, 3}</code> work well with slices.\nBut <code>new([]int)</code> is rarely useful, since it only returns a pointer with zero value of a slice <code>nil</code>.\nHowever, unlike other structures, a slice is not ready to use with its zero value.\nTo prepare a slice, we need to first create its underlying array.\nAlso, since slices are cheap and expensive as explained in next section, and modifying a slice automatically modifies its underlying array,\na pointer to a slice is rarely used.\nThus Go introduces a new built-in function <code>make</code> for this purpose.\n<code>make([]int, 10, 100)</code> creates a slice ready to use, with underlying array allocated with zero values, and returns a slice, not a pointer to a slice.</p>\n<p>Same applies to <code>maps</code> and <code>channels</code>.\nAnd <code>make</code> applies only to slices, maps, and channels.</p>\n<h3>Unsafe Pointer</h3>\n<p>The <code>array</code> field of the slice does not point to the underlying array.\nInstead, it points to the first element of the underlying array.\nThis makes slicing as cheap and efficient as passing around explicit indexes.</p>\n<p>However, this also means slice cannot utilize array's compile time bound checks.\nIndex out of range error with slices can only be checked at runtime.</p>\n<p>Strings have the same issue since strings in Go are effectively slices of bytes.</p>\n<p>Note that <a href=\"https://blog.golang.org/go-slices-usage-and-internals\">Go Slices: usage and internals</a> on <a href=\"https://blog.golang.org/\">The Go Blog</a> mentioned slice consists of a pointer to the <strong>array</strong>, the length of the segment, and its capacity.\nInstead, slice contains a pointer to the <strong>first element of the array</strong>.\nThe illusion below is correct (<code>ptr *Elem</code>).\nIn C, a pointer to an array is actually a pointer to the first element of an array.\nSo a pointer to an array and a pointer to the first element of an array are equivalent in C.\nBut this does not apply to Go.</p>\n<h3>Variadic Functions</h3>\n<p>Go supports variadic functions (splats arguments): <code>(ns ...int)</code>.</p>\n<h2>Flow Control</h2>\n<h3><code>for</code></h3>\n<p><code>for</code> is the only looping construct in Go.</p>\n<pre><code class=\"language-go\"><span class=\"pl-smi\">sum</span> <span class=\"pl-k\">:=</span> <span class=\"pl-c1\">0</span>\n<span class=\"pl-k\">for</span> <span class=\"pl-smi\">i</span> <span class=\"pl-k\">:=</span> <span class=\"pl-c1\">0</span>; i &#x3C; <span class=\"pl-c1\">10</span>; i++ { <span class=\"pl-c\">// `i++` is a statement, not an expression.</span>\n\tsum += i\n}\n<span class=\"pl-k\">for</span> sum &#x3C; <span class=\"pl-c1\">1000</span> {\n\tsum += sum\n}\n<span class=\"pl-k\">for</span> {\n    sum += sum\n    <span class=\"pl-k\">if</span> sum >= <span class=\"pl-c1\">1000</span> {\n        <span class=\"pl-k\">break</span>\n    }\n}\n</code></pre>\n<h3><code>if</code> and <code>switch</code></h3>\n<p>Like <code>for</code>, <code>if</code> and <code>switch</code> statements can start with a short statement to execute before the condition.\nThis is mainly used to declare variables to limit their scope until the end of the <code>if</code> (including <code>else</code> blocks).</p>\n<pre><code class=\"language-go\"><span class=\"pl-k\">if</span> <span class=\"pl-smi\">v</span> <span class=\"pl-k\">:=</span> math.<span class=\"pl-c1\">Pow</span>(x, n); v &#x3C; lim {\n\t<span class=\"pl-k\">return</span> v\n}\n<span class=\"pl-k\">switch</span> <span class=\"pl-smi\">os</span> <span class=\"pl-k\">:=</span> runtime.<span class=\"pl-smi\">GOOS</span>; os {\n    <span class=\"pl-k\">case</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>darwin<span class=\"pl-pds\">\"</span></span>:\n        fmt.<span class=\"pl-c1\">Println</span>(<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>macOS.<span class=\"pl-pds\">\"</span></span>)\n    <span class=\"pl-k\">case</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>linux<span class=\"pl-pds\">\"</span></span>:\n        fmt.<span class=\"pl-c1\">Println</span>(<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>Linux.<span class=\"pl-pds\">\"</span></span>)\n    <span class=\"pl-k\">default</span>:\n        fmt.<span class=\"pl-c1\">Printf</span>(<span class=\"pl-s\"><span class=\"pl-pds\">\"</span><span class=\"pl-c1\">%s</span>.<span class=\"pl-pds\">\"</span></span>, os)\n}\n</code></pre>\n<h3><code>defer</code></h3>\n<p>A <code>defer</code> statement defers the execution of a function until the surrounding function returns.</p>\n<pre><code class=\"language-go\"><span class=\"pl-smi\">file</span>, <span class=\"pl-smi\">_</span> <span class=\"pl-k\">:=</span> os.<span class=\"pl-c1\">Open</span>(path)\n<span class=\"pl-k\">defer</span> file.<span class=\"pl-c1\">Close</span>()\n</code></pre>\n<p>The deferred call's arguments are evaluated immediately, though.</p>\n<p>Multiple deferred function calls are pushed onto a stack.\nWhen a function returns, its deferred calls are executed in last-in-first-out order.</p>\n<p><code>defer</code> breaks the rule of natural order of execution.\nThus it should be restricted for cleanup operations.\nAbusing <code>defer</code> disturbs the execution flow thus harming readability.</p>\n<h2>Basic Types</h2>\n<ul>\n<li><code>bool</code></li>\n<li><code>string</code></li>\n<li><code>int8</code>, <code>int16</code>, <code>int32</code>, <code>int64</code></li>\n<li><code>uint8</code>, <code>uint16</code>, <code>uint32</code>, <code>uint64</code></li>\n<li><code>int</code>, <code>uint</code>, <code>uintptr</code>: 32/64 bits wide on 32/64-bit systems</li>\n<li><code>byte</code>: alias for uint8</li>\n<li><code>rune</code>: alias for int32, represents a Unicode code point</li>\n<li><code>float32</code>, <code>float64</code></li>\n<li><code>complex64</code>, <code>complex128</code></li>\n</ul>\n<p>The expression <code>T(v)</code> converts the value <code>v</code> to the type <code>T</code>.</p>\n<p>Constants are declared with the <code>const</code> keyword, they can be character, string, boolean, or numeric values.\nNumeric constants are high-precision values.\nAn untyped constant takes the type needed by its context.</p>\n<pre><code class=\"language-go\"><span class=\"pl-k\">const</span> <span class=\"pl-v\">Pi</span> = <span class=\"pl-c1\">3.14</span>\n</code></pre>\n<h2>Type Aliases and Defined Type</h2>\n<pre><code class=\"language-go\"><span class=\"pl-k\">type</span> <span class=\"pl-v\">Boolean</span> = <span class=\"pl-k\">bool</span>\n</code></pre>\n<p>Now <code>Boolean</code> is an alternative spelling of <code>bool</code>.\nThey both denote the same type.</p>\n<p>Be aware the difference between type aliasing and type declaration.\nFor example, these are type declarations:</p>\n<pre><code class=\"language-go\"><span class=\"pl-k\">type</span> <span class=\"pl-v\">IsPositive</span> <span class=\"pl-k\">bool</span>\n<span class=\"pl-k\">type</span> <span class=\"pl-v\">IsNegative</span> <span class=\"pl-k\">bool</span>\n</code></pre>\n<p><code>IsPositive</code> and <code>IsNegative</code> are <em>named types</em> or <em>defined types</em>, with <code>bool</code> as their <em>underlying type</em>.\n<code>IsPositive</code> and <code>IsNegative</code> are new types, different from any other type, including their underlying type <code>bool</code>.\nAlso, <code>IsPositive</code> and <code>IsNegative</code> are not assignable to each other,\nbecause both of them are defined types.</p>\n<blockquote>\n<p>A value x is assignable to a variable of type T (\"x is assignable to T\") if one of the following conditions applies:\n...\nx's type V and T have identical underlying types and at least one of V or T is not a defined type.</p>\n</blockquote>\n<p>This is a great feature.\nIn many programming languages, it is best practice to name a boolean type with its \"direction\":</p>\n<pre><code class=\"language-go\"><span class=\"pl-k\">var</span> <span class=\"pl-smi\">sex</span> <span class=\"pl-k\">bool</span> <span class=\"pl-c\">// bad</span>\n<span class=\"pl-k\">var</span> <span class=\"pl-smi\">isMale</span> <span class=\"pl-k\">bool</span> <span class=\"pl-c\">// good</span>\n</code></pre>\n<p>In Go, I can go further:</p>\n<pre><code class=\"language-go\"><span class=\"pl-k\">type</span> <span class=\"pl-v\">IsMale</span> <span class=\"pl-k\">bool</span>\n<span class=\"pl-k\">var</span> <span class=\"pl-smi\">isMale</span> <span class=\"pl-v\">IsMale</span>\n</code></pre>\n<p>And if I accidentally assign an unrelated boolean value or opposite directed boolean value to IsMale, the compiler will refuse to compile it.</p>\n<h2>Multiple Return Values</h2>\n<p>A function can return any number of results, which is mostly used in error handling:</p>\n<pre><code class=\"language-go\"><span class=\"pl-smi\">val</span>, <span class=\"pl-smi\">err</span> <span class=\"pl-k\">:=</span> <span class=\"pl-c1\">someFunction</span>()\n<span class=\"pl-k\">if</span> err != <span class=\"pl-c1\">nil</span> {\n    <span class=\"pl-k\">return</span> err\n}\n<span class=\"pl-c1\">codeUsing</span>(val)\n</code></pre>\n<p>To handle errors with multiple return values conveniently,\nGo introduces two hacky features:</p>\n<p>First, when <code>err</code> is not <code>nil</code>, <code>val</code> is assigned to the zero value of its type.\nFor problems on zero values, see next section.</p>\n<p>Second, instead of writing</p>\n<pre><code class=\"language-go\"><span class=\"pl-smi\">val</span>, <span class=\"pl-smi\">err</span> <span class=\"pl-k\">:=</span> <span class=\"pl-c1\">f</span>()\n<span class=\"pl-k\">var</span> <span class=\"pl-smi\">newVal</span> <span class=\"pl-v\">T</span>\nnewVal, err = <span class=\"pl-c1\">g</span>()\n</code></pre>\n<p>Go allows us to 'reuse' the <code>err</code> variable:</p>\n<pre><code class=\"language-go\"><span class=\"pl-smi\">val</span>, <span class=\"pl-smi\">err</span> <span class=\"pl-k\">:=</span> <span class=\"pl-c1\">f</span>()\n<span class=\"pl-smi\">newVal</span>, <span class=\"pl-smi\">err</span> <span class=\"pl-k\">:=</span> <span class=\"pl-c1\">g</span>() <span class=\"pl-c\">// `err` is **re-assigned** here</span>\n</code></pre>\n<p>Because in a <code>:=</code> declaration a variable <code>v</code> may appear even if it has already been declared, provided:</p>\n<ul>\n<li>this declaration is in the same scope as the existing declaration of <code>v</code>,</li>\n<li>the corresponding value in the initialization is assignable to <code>v</code>, and</li>\n<li>there is at least one other variable in the declaration that is being declared anew.</li>\n</ul>\n<p>Introducing an unusual, inconsistent rule to support one use case is doubtful.\nTogether with other problems of using multiple return values to model exceptions, this implies a poor design of error handling.</p>\n<p>Note some built-in structures can produce one or multiple value.\nWe have seen <code>range slice</code> returns two values (index and element) before.\nIf you only want the index, just write <code>for i := range names</code>.</p>\n<p>Similarly, we have <code>element := m[key]</code> and <code>element, present := m[key]</code>.\nIn both cases, <code>element</code> is the zero value for the map's element type if <code>key</code> is not present in the map (<code>present</code> is false in the later case).</p>\n<p>Similar to the issue with errors, the zero value <code>element</code> may be a valid value, making missing a key undistinguishable.</p>\n<p>Also note that the evaluation order of multiple return values is uncertain.\nNever assume the evaluation order of multiple return values is from left to right.</p>\n<p>Another issue is Go functions can only consume multiple values returned by another function in a whole.\nFor example, given three functions <code>f() (int, int)</code>, <code>g(int, int)</code>, <code>h(int, int, int)</code>,\n<code>g(f())</code> compiles while <code>h(f(), 1)</code> and <code>h(1, f())</code> do not.</p>\n<h2>Zero Values</h2>\n<p>Variables declared without an explicit initial value are given their zero value:</p>\n<ul>\n<li><code>0</code> for numeric types</li>\n<li><code>false</code> for the boolean type</li>\n<li><code>\"\"</code> (empty string) for strings</li>\n<li><code>nil</code> for pointers, functions, interfaces, slices, channels, and maps.</li>\n<li>The above zero values are applied recursively for arrays and structs.</li>\n</ul>\n<p>Using <code>0</code>, <code>fales</code>, and <code>\"\"</code> for numbers, bools, and strings is confusing.\nAnd the compiler cannot check declaration without assignment errors.</p>\n<p>Using <code>nil</code> as zero values has the same problem with nullability in other languages.</p>\n<p>To make things worse:</p>\n<ul>\n<li><code>nil</code> for functions and interfaces requires any function taking a function or an interface check whether the argument is null or not.</li>\n<li><code>nil</code> for pointers requires any function taking a pointer, and any method, a.k.a. functions with a receiver argument, check whether the argument is null or not.</li>\n<li><code>nil</code> for slices, maps, and channels requires introducing a special <code>make</code> function to create their instances.</li>\n</ul>\n<h2>Functions as Values</h2>\n<p>Functions are values too.\nThey can be passed around just like other values.</p>\n<pre><code class=\"language-go\"><span class=\"pl-k\">func</span> <span class=\"pl-en\">sortStringsByLength</span>(<span class=\"pl-v\">s</span> []<span class=\"pl-v\">string</span>) {\n    sort.<span class=\"pl-c1\">Slice</span>(\n            s,\n            <span class=\"pl-c\">// Anonymous functions are closures.</span>\n            <span class=\"pl-c1\">func</span>(i <span class=\"pl-k\">int</span>, j <span class=\"pl-k\">int</span>) <span class=\"pl-k\">bool</span> { <span class=\"pl-k\">return</span> <span class=\"pl-c1\">len</span>(s[i]) &#x3C; <span class=\"pl-c1\">len</span>(s[j]) })\n}\n</code></pre>\n<p>However, it only matches exact function signature.\nIt does not support subtyping of functions, since Go does not support covariance and contravariance.\nEven covariant return type is not supported, which is supported by Java.</p>\n<h2>Pointers</h2>\n<p>Unlike C, Go has no pointer arithmetic.\nAnd accessing the field via a struct pointer will derefer the pointer implicitly.\nAlso, methods with a pointer/value receiver also accept its value/pointer as the receiver when they are called.</p>\n<pre><code class=\"language-go\"><span class=\"pl-k\">func</span> <span class=\"pl-en\">(</span><span class=\"pl-v\">point</span> *<span class=\"pl-v\">Point</span><span class=\"pl-en\">) Scale</span>(<span class=\"pl-v\">f</span> <span class=\"pl-v\">float64</span>) { <span class=\"pl-c\">/* ... */</span> }\n<span class=\"pl-smi\">point</span> <span class=\"pl-k\">:=</span> <span class=\"pl-v\">Point</span>{x: <span class=\"pl-c1\">1.0</span>, y: <span class=\"pl-c1\">2.0</span>}\n<span class=\"pl-smi\">pointer</span> <span class=\"pl-k\">:=</span> &#x26;point <span class=\"pl-c\">// the `&#x26;` operator generates a pointer</span>\nfmt.<span class=\"pl-c1\">Println</span>(pointer.<span class=\"pl-smi\">x</span>) <span class=\"pl-c\">// same as (*pointer).x, where the `*` operator denotes the underlying value</span>\npoint.<span class=\"pl-c1\">Scale</span>(<span class=\"pl-c1\">10</span>) <span class=\"pl-c\">// same as pointer.Scale(10)</span>\n</code></pre>\n<p>We are cheating in the definition of <code>Scale</code>.\nThe definition of <code>Scale</code> does not check nil value of <code>*Point</code>.\nAs mentioned before, <code>nil</code> is zero value of a pointer, in other words, all pointers are nullable in Go.\nThe compiler accepts <code>nil</code> as a valid receiver of <code>Scale</code>, which is in fact invalid.</p>\n<pre><code class=\"language-go\"><span class=\"pl-k\">var</span> <span class=\"pl-smi\">n</span> *Point <span class=\"pl-c\">// nil</span>\nn.<span class=\"pl-c1\">Scale</span>(<span class=\"pl-c1\">10</span>) <span class=\"pl-c\">// The compiler does not check nullability.</span>\n</code></pre>\n<p><code>n.Scale(10)</code> compiles, but triggers a <strong>runtime</strong> error: <code>invalid memory address or nil pointer dereference</code>.\nDue to the auto indirection of a value receiver, even a method accepting a value of a type not accepting <code>nil</code> may take a <code>nil</code> receiver argument.</p>\n<p>Thus I prefer to declare a function instead.\nMethods are only used to implement interfaces.</p>\n<h2>Interfaces</h2>\n<h3>Implicitness</h3>\n<p>Interfaces are implemented implicitly.</p>\n<pre><code class=\"language-go\"><span class=\"pl-k\">type</span> <span class=\"pl-v\">I</span> <span class=\"pl-k\">interface</span> {\n\t<span class=\"pl-c1\">M</span>()\n}\n<span class=\"pl-c\">// Type T implements the interface I, without explicit declaration.</span>\n<span class=\"pl-k\">func</span> <span class=\"pl-en\">(</span><span class=\"pl-v\">t</span> <span class=\"pl-v\">T</span><span class=\"pl-en\">) M</span>() {\n\tfmt.<span class=\"pl-c1\">Println</span>(t.<span class=\"pl-smi\">S</span>)\n}\n</code></pre>\n<h3>Empty Interface</h3>\n<p>Because Go does not have generics,\nyou are forced to use empty interface <code>interface{}</code> for generic code.\n<code>interface{}</code> is similar to <code>void*</code> in C, breaking type safety.</p>\n<p><code>t := i.(T)</code> asserts <code>i</code> holding <code>T</code> and assigns the underlying <code>T</code> value, triggering a panic if <code>i</code> does not hold <code>T</code>.\n<code>t, ok := i.(T)</code> avoids triggering a panic if <code>i</code> does not hold <code>T</code>.\n<code>switch t := i.(type)</code> permits several type assertions in series.</p>\n<p>An interface can be considered as a pair of <code>(ConcreteType, Value)</code>.\nThus while an interface can be nil (for example, zero value), an interface holding a nil concrete value is itself non-nil.</p>\n<pre><code class=\"language-go\"><span class=\"pl-k\">var</span> <span class=\"pl-smi\">i</span> <span class=\"pl-k\">interface</span>{} = <span class=\"pl-c1\">nil</span> <span class=\"pl-c\">// i == nil</span>\n<span class=\"pl-k\">var</span> <span class=\"pl-smi\">j</span> []<span class=\"pl-k\">string</span> = <span class=\"pl-c1\">nil</span>\ni = j <span class=\"pl-c\">// i != nil</span>\n</code></pre>\n<h3>Check Implementation</h3>\n<p>To check if a value satisfies an interface at <strong>run time</strong>, use type assertion:</p>\n<pre><code class=\"language-go\"><span class=\"pl-smi\">m</span>, <span class=\"pl-smi\">ok</span> <span class=\"pl-k\">:=</span> val.(json.<span class=\"pl-smi\">Marshaler</span>)\n</code></pre>\n<p>To get the type and underlying value of an interface value at rut time, use <code>reflect.TypeOf(x)</code> and <code>reflect.ValueOf(x)</code>.\nBoth <code>reflect.Type</code> and <code>reflect.Value</code> have a <code>Kind</code> method that returns a constant indicating what sort of item is stored:\n<code>reflect.Uint</code>, <code>reflect.Float64</code>, <code>reflect.Slice</code>, and so on.\n<code>reflect.Value</code> also has an <code>Interface</code> method, which packs the type and value information back into an interface representation and returns the result.</p>\n<p>To change the underlying value of <code>reflect.Value</code>, we can use <code>reflect.SetT</code>.</p>\n<pre><code class=\"language-go\"><span class=\"pl-k\">var</span> <span class=\"pl-smi\">x</span> <span class=\"pl-k\">float64</span> = <span class=\"pl-c1\">3.4</span>\n<span class=\"pl-smi\">v</span> <span class=\"pl-k\">:=</span> reflect.<span class=\"pl-c1\">ValueOf</span>(&#x26;x)\nv.<span class=\"pl-c1\">SetFloat</span>(<span class=\"pl-c1\">7.1</span>)\n</code></pre>\n<p>Note that we pass <code>&#x26;x</code> instead of <code>x</code> to <code>reflect.ValueOf</code>.\nOtherwise <code>v</code> would store a copy of <code>x</code>, and <code>v.SetFloat</code> would be illegal.\nThe <code>CanSet</code> method of <code>reflect.Value</code> reports the settability of it.</p>\n<p>Be careful with reflections.\nReflections involves type assertion and value copying.\nThus it may cause performance issues.</p>\n<p>To make sure that a type implementing the required interface at <strong>compile time</strong>:</p>\n<pre><code class=\"language-go\"><span class=\"pl-k\">var</span> <span class=\"pl-smi\">_</span> json.<span class=\"pl-smi\">Marshaler</span> = (*RawMessage)(<span class=\"pl-c1\">nil</span>)\n</code></pre>\n<p>Here we use a pointer instead of <code>new(RawMessage)</code> because if RawMessage is a big array or struct, calling <code>new</code> may allocate unnecessary memory.</p>\n<h3>Embedded Interfaces</h3>\n<p>Interface type name can be used in place of a method specification.</p>\n<pre><code class=\"language-go\"><span class=\"pl-k\">type</span> <span class=\"pl-v\">ComplexInterface</span> <span class=\"pl-k\">interface</span> {\n    <span class=\"pl-v\">EmbeddedInterface</span>\n    <span class=\"pl-v\">AnotherEmbeddedInterface</span>\n    <span class=\"pl-c1\">AMethod</span>() <span class=\"pl-k\">int</span>\n}\n</code></pre>\n<p>The method set of <code>ComplexInterface</code> is the union of its embedded interfaces and its explicitly declared methods.\nIf there are interface methods have identical names, they must have identical signatures.</p>\n<h3>Struct</h3>\n<p>Structs can embed interfaces.</p>\n<pre><code class=\"language-go\"><span class=\"pl-c\">// Job has all the methods of `*log.Logger`.</span>\n<span class=\"pl-k\">type</span> <span class=\"pl-v\">Job</span> <span class=\"pl-k\">struct</span> {\n    <span class=\"pl-v\">Command</span> <span class=\"pl-k\">string</span>\n    *log.<span class=\"pl-smi\">Logger</span> <span class=\"pl-c\">// same as Logger *log.Logger</span>\n}\n</code></pre>\n<h3>Stringer</h3>\n<p>One of the most ubiquitous interfaces is <code>Stringer</code>\ndefined by the <code>fmt</code> package.</p>\n<pre><code class=\"language-go\"><span class=\"pl-k\">type</span> <span class=\"pl-v\">Stringer</span> <span class=\"pl-k\">interface</span> {\n    <span class=\"pl-c1\">String</span>() <span class=\"pl-k\">string</span>\n}\n</code></pre>\n<p>The print functions from <code>fmt</code> utilizes the <code>Stringer</code> interface.</p>\n<h3>error</h3>\n<p>The other ubiquitous interface is the built-in <code>error</code> interface:</p>\n<pre><code class=\"language-go\"><span class=\"pl-k\">type</span> <span class=\"pl-v\">NullPointerException</span> <span class=\"pl-k\">struct</span> {\n    <span class=\"pl-v\">Message</span> <span class=\"pl-k\">string</span>\n}\n\n<span class=\"pl-c\">// satisfies `error` interface</span>\n<span class=\"pl-k\">func</span> <span class=\"pl-en\">(</span><span class=\"pl-v\">e</span> *<span class=\"pl-v\">NullPointerException</span><span class=\"pl-en\">) Error</span>() <span class=\"pl-v\">string</span> {\n    <span class=\"pl-k\">return</span> e.<span class=\"pl-smi\">Message</span>\n}\n</code></pre>\n<p>If we do not want to declare our own error type, we just use a general error with a string via <code>errors.New</code> or <code>fmt.Errorf</code>.</p>\n<h4>error.Is and error.As</h4>\n<p>Besides <code>New</code>, <code>errors</code> also provides two functions: <code>Is</code> and <code>As</code>.</p>\n<p><code>errors.Is</code> compares an error to a value.\nThere are two differences between using <code>errors.Is(err, value)</code> and comparing via <code>err == value</code> directly:</p>\n<ol>\n<li><code>errors.Is</code> will invoke the <code>Is</code> method of the error if available.</li>\n<li><code>errors.Is</code> will examine all the wrapped errors on the chain.</li>\n</ol>\n<p>For example:</p>\n<pre><code class=\"language-go\"><span class=\"pl-k\">type</span> <span class=\"pl-v\">NonExistError</span> <span class=\"pl-k\">struct</span> {\n    <span class=\"pl-v\">Code</span> <span class=\"pl-k\">int</span>\n    <span class=\"pl-v\">Err</span> <span class=\"pl-k\">error</span>\n}\n<span class=\"pl-k\">func</span> <span class=\"pl-en\">(</span><span class=\"pl-v\">e</span> *<span class=\"pl-v\">NonExistError</span><span class=\"pl-en\">) Error</span>() <span class=\"pl-v\">string</span> { <span class=\"pl-k\">return</span> strconv.<span class=\"pl-c1\">Itoa</span>(e.<span class=\"pl-smi\">Code</span>) }\n<span class=\"pl-c\">// If e1.Unwrap() returns e2, then e1 wraps e2, and we can unwrap e1 to get e2.</span>\n<span class=\"pl-c\">// e2 itself may implement an Unwrap method returning its underlying error (error chain).</span>\n<span class=\"pl-k\">func</span> <span class=\"pl-en\">(</span><span class=\"pl-v\">e</span> *<span class=\"pl-v\">NonExistError</span><span class=\"pl-en\">) Unwrap</span>() <span class=\"pl-v\">error</span> { <span class=\"pl-k\">return</span> e.<span class=\"pl-smi\">Err</span> }\n<span class=\"pl-k\">func</span> <span class=\"pl-en\">(</span><span class=\"pl-v\">e</span> *<span class=\"pl-v\">NonExistError</span><span class=\"pl-en\">) Is</span>(<span class=\"pl-v\">target</span> <span class=\"pl-v\">error</span>) <span class=\"pl-v\">bool</span> {\n    <span class=\"pl-smi\">t</span>, <span class=\"pl-smi\">ok</span> <span class=\"pl-k\">:=</span> target.(*NonExistError)\n    <span class=\"pl-k\">if</span> ok {\n        <span class=\"pl-k\">return</span> e.<span class=\"pl-smi\">Code</span> == t.<span class=\"pl-smi\">Code</span>\n    } <span class=\"pl-k\">else</span> {\n        <span class=\"pl-k\">return</span> <span class=\"pl-c1\">false</span>\n    }\n}\n</code></pre>\n<p>Similarly, there is an <code>errors.As</code> method, examining all the wrapped errors on the chain, using <code>As</code> method defined on errors when available.</p>\n<pre><code class=\"language-go\"><span class=\"pl-k\">var</span> <span class=\"pl-smi\">err</span> *NonExistError\n<span class=\"pl-k\">var</span> <span class=\"pl-smi\">ok</span> <span class=\"pl-k\">bool</span> = errors.<span class=\"pl-c1\">As</span>(e, &#x26;err)\n</code></pre>\n<h4>%w</h4>\n<p>Besides defining the <code>Unwrap</code> method explicitly, <code>fmt.Errorf</code> with <code>%w</code> verb present returns an error with an <code>Unwrap</code> method returning the argument of <code>%w</code>.\nThus the argument of <code>%w</code> must be an error.\nIn other aspects, <code>%w</code> is identical to <code>%v</code>.</p>\n<pre><code class=\"language-go\"><span class=\"pl-smi\">e2</span> <span class=\"pl-k\">:=</span> errors.<span class=\"pl-c1\">New</span>(<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>wrap me<span class=\"pl-pds\">\"</span></span>)\n<span class=\"pl-smi\">e1</span> <span class=\"pl-k\">:=</span> fmt.<span class=\"pl-c1\">Errorf</span>(<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>wraps <span class=\"pl-ii\">%</span>w<span class=\"pl-pds\">\"</span></span>, e2)\n</code></pre>\n<p>Wrapping an error will expose the underlying error, thus making the wrapped error part of the API.\nTherefore abusing wrapping will break abstraction and expose implementation details unnecessarily.</p>\n<h4>panic and recover</h4>\n<p>As an alternative to return an error, we can <code>panic</code> instead.</p>\n<p>To regain control of a panicking execution, we can use the built-in <code>recover</code> function.</p>\n<pre><code class=\"language-go\"><span class=\"pl-k\">func</span> <span class=\"pl-en\">f</span>(<span class=\"pl-v\">v</span> <span class=\"pl-v\">interface</span>{}) {\n    <span class=\"pl-c\">// anonymous function</span>\n    <span class=\"pl-k\">defer</span> <span class=\"pl-k\">func</span>() {\n        <span class=\"pl-k\">if</span> r: = <span class=\"pl-c1\">recover</span>(); r != <span class=\"pl-c1\">nil</span> {\n            log.<span class=\"pl-c1\">Fatal</span>(<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>Recovered in f<span class=\"pl-pds\">\"</span></span>, r)\n        }\n    }()\n    <span class=\"pl-c1\">func</span>() {\n        <span class=\"pl-c1\">panic</span>(<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>panic<span class=\"pl-pds\">\"</span></span>)\n    }()\n    fmt.<span class=\"pl-c1\">Println</span>(v)\n}\n</code></pre>\n<h2>Goroutines</h2>\n<p>Goroutines are user level continuation, more lightweight than system level continuation (threads).</p>\n<pre><code class=\"language-go\"><span class=\"pl-k\">func</span> <span class=\"pl-en\">sum</span>(<span class=\"pl-v\">s</span> []<span class=\"pl-v\">int</span>, <span class=\"pl-v\">c</span> <span class=\"pl-v\">chan</span>&#x3C;- <span class=\"pl-v\">int</span>) { <span class=\"pl-c\">// `chan&#x3C;-` only receive values; `&#x3C;-chan` only send values</span>\n\t<span class=\"pl-smi\">sum</span> <span class=\"pl-k\">:=</span> <span class=\"pl-c1\">0</span>\n\t<span class=\"pl-k\">for</span> <span class=\"pl-smi\">_</span>, <span class=\"pl-smi\">v</span> <span class=\"pl-k\">:=</span> <span class=\"pl-k\">range</span> s {\n\t\tsum += v\n\t}\n\tc <span class=\"pl-k\">&#x3C;-</span> sum <span class=\"pl-c\">// send sum to c</span>\n}\n<span class=\"pl-k\">func</span> <span class=\"pl-en\">calc</span>(<span class=\"pl-v\">s</span> []<span class=\"pl-v\">int</span>, <span class=\"pl-v\">c</span> <span class=\"pl-v\">chan</span> <span class=\"pl-v\">int</span>) <span class=\"pl-v\">int</span> { <span class=\"pl-c\">// `chan` has no direction (can receive and send values)</span>\n\t<span class=\"pl-k\">go</span> <span class=\"pl-c1\">sum</span>(s[:<span class=\"pl-c1\">len</span>(s)/<span class=\"pl-c1\">2</span>], c)\n    <span class=\"pl-k\">go</span> <span class=\"pl-c1\">sum</span>(s[<span class=\"pl-c1\">len</span>(s)/<span class=\"pl-c1\">2</span>:], c)\n    <span class=\"pl-k\">return</span> <span class=\"pl-k\">&#x3C;-</span>c + <span class=\"pl-k\">&#x3C;-</span>c\n}\n<span class=\"pl-k\">func</span> <span class=\"pl-en\">main</span>() {\n\t<span class=\"pl-smi\">s</span> <span class=\"pl-k\">:=</span> []<span class=\"pl-k\">int</span>{<span class=\"pl-c1\">7</span>, <span class=\"pl-c1\">2</span>, <span class=\"pl-c1\">8</span>, -<span class=\"pl-c1\">9</span>, <span class=\"pl-c1\">4</span>, <span class=\"pl-c1\">0</span>}\n\t<span class=\"pl-smi\">c</span> <span class=\"pl-k\">:=</span> <span class=\"pl-c1\">make</span>(<span class=\"pl-k\">chan</span> <span class=\"pl-k\">int</span>, <span class=\"pl-c1\">2</span>) <span class=\"pl-c\">// no race conditions, thus we create a buffered channel</span>\n    fmt.<span class=\"pl-c1\">Println</span>(<span class=\"pl-c1\">calc</span>(s, c))\n}\n</code></pre>\n<h3>Closing a Channel</h3>\n<p>A sender can close a channel to indicate that no more values will be sent: <code>close(c)</code>.\nSending on a closed channel will cause a panic.\nThus only the sender should close a channel, never the receiver.</p>\n<p>Channels aren't like files; you don't usually need to close them.\nClosing is only necessary when the receiver must be told there are no more values coming, such as to terminate a range loop.</p>\n<pre><code class=\"language-go\"><span class=\"pl-k\">func</span> <span class=\"pl-en\">fibonacci</span>(<span class=\"pl-v\">n</span> <span class=\"pl-v\">int</span>, <span class=\"pl-v\">c</span> <span class=\"pl-v\">chan</span>&#x3C;- <span class=\"pl-v\">int</span>) {\n\t<span class=\"pl-smi\">x</span>, <span class=\"pl-smi\">y</span> <span class=\"pl-k\">:=</span> <span class=\"pl-c1\">0</span>, <span class=\"pl-c1\">1</span>\n\t<span class=\"pl-k\">for</span> <span class=\"pl-smi\">i</span> <span class=\"pl-k\">:=</span> <span class=\"pl-c1\">0</span>; i &#x3C;= n; i++ {\n\t\tc <span class=\"pl-k\">&#x3C;-</span> x\n\t\tx, y = y, x+y\n\t}\n\t<span class=\"pl-c1\">close</span>(c)\n}\n\n<span class=\"pl-k\">func</span> <span class=\"pl-en\">main</span>() {\n\t<span class=\"pl-smi\">c</span> <span class=\"pl-k\">:=</span> <span class=\"pl-c1\">make</span>(<span class=\"pl-k\">chan</span> <span class=\"pl-k\">int</span>) <span class=\"pl-c\">// unbuffered channel</span>\n\t<span class=\"pl-k\">go</span> <span class=\"pl-c1\">fibonacci</span>(<span class=\"pl-c1\">10</span>, c)\n\t<span class=\"pl-k\">for</span> <span class=\"pl-smi\">i</span> <span class=\"pl-k\">:=</span> <span class=\"pl-k\">range</span> c {\n\t\tfmt.<span class=\"pl-c1\">Println</span>(i)\n\t}\n}\n</code></pre>\n<p>Receivers can test whether a channel has been closed by assigning a second parameter to the receive expression <code>v, ok := &#x3C;-c</code>.</p>\n<h3>Select</h3>\n<p>The <code>select</code> statement lets a goroutine wait on multiple communication operations.</p>\n<p>A select blocks until one of its cases can run, then it executes that case.\nIt chooses one <strong>at random</strong> if multiple are ready。</p>\n<pre><code class=\"language-go\"><span class=\"pl-k\">func</span> <span class=\"pl-en\">fibonacci</span>(<span class=\"pl-v\">c</span> <span class=\"pl-v\">chan</span>&#x3C;- <span class=\"pl-v\">int</span>, <span class=\"pl-v\">end</span> &#x3C;-<span class=\"pl-v\">chan</span> <span class=\"pl-v\">bool</span>) {\n\t<span class=\"pl-smi\">x</span>, <span class=\"pl-smi\">y</span> <span class=\"pl-k\">:=</span> <span class=\"pl-c1\">0</span>, <span class=\"pl-c1\">1</span>\n\t<span class=\"pl-k\">for</span> {\n\t\t<span class=\"pl-k\">select</span> {\n\t\t<span class=\"pl-k\">case</span> c <span class=\"pl-k\">&#x3C;-</span> x:\n\t\t\tx, y = y, x+y\n\t\t<span class=\"pl-k\">case</span> <span class=\"pl-k\">&#x3C;-</span>end:\n\t\t\t<span class=\"pl-k\">return</span>\n\t\t}\n\t}\n}\n\n<span class=\"pl-k\">func</span> <span class=\"pl-en\">main</span>() {\n\t<span class=\"pl-smi\">c</span> <span class=\"pl-k\">:=</span> <span class=\"pl-c1\">make</span>(<span class=\"pl-k\">chan</span> <span class=\"pl-k\">int</span>)\n\t<span class=\"pl-smi\">end</span> <span class=\"pl-k\">:=</span> <span class=\"pl-c1\">make</span>(<span class=\"pl-k\">chan</span> <span class=\"pl-k\">bool</span>)\n\t<span class=\"pl-k\">go</span> <span class=\"pl-k\">func</span>() {\n\t\t<span class=\"pl-k\">for</span> <span class=\"pl-smi\">i</span> <span class=\"pl-k\">:=</span> <span class=\"pl-c1\">0</span>; i &#x3C; <span class=\"pl-c1\">10</span>; i++ {\n\t\t\tfmt.<span class=\"pl-c1\">Println</span>(<span class=\"pl-k\">&#x3C;-</span>c)\n\t\t}\n\t\tend <span class=\"pl-k\">&#x3C;-</span> <span class=\"pl-c1\">true</span>\n\t}()\n\t<span class=\"pl-c1\">fibonacci</span>(c, end)\n}\n</code></pre>\n<p>The <code>default</code> case in a select is run if no other case is ready.</p>\n<h2>Name Conventions</h2>\n<h3>Package</h3>\n<p>By convention, packages are given lower case, single-word names; there should be no need for underscores or mixedCaps.\nAnother convention is that the package name is the base name of its source directory, for example <code>encoding/base64</code>.</p>\n<p>By the way, to import a package only for its side effect (<code>init()</code>), use a blank identifier <code>import _ packageName</code>.</p>\n<h3>Getter</h3>\n<p>It's neither idiomatic nor necessary to put <code>Get</code> into the getter's name.\nIf you have a field called <code>owner</code> (lower case, unexported), the getter method should be called <code>Owner</code> (upper case, exported), not <code>GetOwner</code>.\nThe use of upper-case names for export provides the hook to discriminate the field from the method.\nA setter function, if needed, will likely be called <code>SetOwner</code>.</p>\n<h3>Interface</h3>\n<p>By convention, one-method interfaces are named by the method name plus an -er suffix or similar modification to construct an agent noun: <code>Reader</code>, <code>Writer</code>, <code>Formatter</code>, <code>CloseNotifier</code> etc.</p>\n<h3>MixedCaps</h3>\n<p>The convention in Go is to use <code>MixedCaps</code> or <code>mixedCaps</code> rather than underscores to write multiword names.</p>\n<p>Why?</p>\n<p>First, <code>set_owner</code> (unexported names in Go) is easier to read because we are already familiar with <code>set owner</code> in natural languages.\nWe Are not Familiar with Compound words and Similar structures Like this.\nThus <code>Set_owner</code> (exported names in Go) does not feel nature.</p>\n<p>Second, Go prefers brevity <del>over</del> for clarity.\n<em>Effective Go</em> suggested that:</p>\n<blockquote>\n<p>Long names don't automatically make things more readable.\nA helpful doc comment can often be more valuable than an extra long name.</p>\n</blockquote>\n<p>Thus mixedCaps will probably not get long enough to reduce readability, e.g. <a href=\"https://signalvnoise.com/posts/3250-clarity-over-brevity-in-variable-and-method-names\"><code>isSomeoneElseJustFinishedWriting</code></a>.</p>\n<h2>Testing</h2>\n<p>To test Go code, write testing functions as <code>TestXxx(*testing.T)</code>.</p>\n<pre><code class=\"language-go\"><span class=\"pl-k\">package</span> main\n\n<span class=\"pl-k\">import</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>testing<span class=\"pl-pds\">\"</span></span>\n\n<span class=\"pl-k\">func</span> <span class=\"pl-en\">TestSum</span>(<span class=\"pl-v\">t</span> *<span class=\"pl-v\">testing</span>.<span class=\"pl-v\">T</span>) {\n    <span class=\"pl-smi\">total</span> <span class=\"pl-k\">:=</span> <span class=\"pl-c1\">Sum</span>(<span class=\"pl-c1\">1</span>, <span class=\"pl-c1\">1</span>)\n    <span class=\"pl-k\">if</span> total != <span class=\"pl-c1\">2</span> {\n       t.<span class=\"pl-c1\">Errorf</span>(<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>Sum(1, 1) got: <span class=\"pl-c1\">%d</span>, expected: <span class=\"pl-c1\">%d</span>.<span class=\"pl-pds\">\"</span></span>, total, <span class=\"pl-c1\">2</span>)\n    }\n}\n</code></pre>\n<p>Put those testing functions in a file whose name ends with <code>_test.go</code> within the package.\nThe file will be excluded from regular package builds but will be included when the <code>go test</code> command is run.</p>\n<h3>Benchmark</h3>\n<p>Functions of the form <code>BenchmarkXxx(*testing.B)</code> are benchmarks, which will be executed by <code>go test -bench</code>.</p>\n<pre><code class=\"language-go\"><span class=\"pl-k\">func</span> <span class=\"pl-en\">BenchmarkHello</span>(<span class=\"pl-v\">b</span> *<span class=\"pl-v\">testing</span>.<span class=\"pl-v\">B</span>) {\n    <span class=\"pl-c1\">doSomeExpensiveSetup</span>()\n    b.<span class=\"pl-c1\">ResetTimer</span>()\n    <span class=\"pl-k\">for</span> <span class=\"pl-smi\">i</span> <span class=\"pl-k\">:=</span> <span class=\"pl-c1\">0</span>; i &#x3C; b.<span class=\"pl-smi\">N</span>; i++ {\n        fmt.<span class=\"pl-c1\">Sprintf</span>(<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>hello<span class=\"pl-pds\">\"</span></span>)\n    }\n}\n</code></pre>\n<p>The output</p>\n<pre><code>BenchmarkHello    10000000    282 ns/op\n</code></pre>\n<p>means that the loop ran 10000000 times at a speed of 282 ns per loop.</p>\n<p>The times are adjusted until the benchmark function lasts long enough to be timed reliably.</p>\n<p>If a benchmark needs to test performance in a parallel setting, it may use the <code>RunParallel</code> helper function; such benchmarks are intended to be used with the go test <code>-cpu</code> flag:</p>\n<pre><code class=\"language-go\"><span class=\"pl-k\">func</span> <span class=\"pl-en\">BenchmarkTemplateParallel</span>(<span class=\"pl-v\">b</span> *<span class=\"pl-v\">testing</span>.<span class=\"pl-v\">B</span>) {\n    <span class=\"pl-smi\">templ</span> <span class=\"pl-k\">:=</span> template.<span class=\"pl-c1\">Must</span>(template.<span class=\"pl-c1\">New</span>(<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>test<span class=\"pl-pds\">\"</span></span>).<span class=\"pl-c1\">Parse</span>(<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>Hello, {.}!<span class=\"pl-pds\">\"</span></span>))\n    b.<span class=\"pl-c1\">RunParallel</span>(<span class=\"pl-k\">func</span>(pb *testing.<span class=\"pl-smi\">PB</span>) {\n        <span class=\"pl-k\">var</span> <span class=\"pl-smi\">buf</span> bytes.<span class=\"pl-smi\">Buffer</span>\n        <span class=\"pl-k\">for</span> pb.<span class=\"pl-c1\">Next</span>() {\n            buf.<span class=\"pl-c1\">Reset</span>()\n            templ.<span class=\"pl-c1\">Execute</span>(&#x26;buf, <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>World<span class=\"pl-pds\">\"</span></span>)\n        }\n    })\n}\n</code></pre>\n<h3>Examples</h3>\n<p>Example functions may include a concluding line comment that begins with <code>Output:</code> and is compared with the standard output of the function when the tests are run.\nThe comparison ignores leading and trailing space.</p>\n<pre><code class=\"language-go\"><span class=\"pl-k\">func</span> <span class=\"pl-en\">ExampleHello</span>() {\n        fmt.<span class=\"pl-c1\">Println</span>(<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>hello<span class=\"pl-pds\">\"</span></span>)\n        <span class=\"pl-c\">// Output: hello</span>\n}\n\n<span class=\"pl-k\">func</span> <span class=\"pl-en\">ExampleSalutations</span>() {\n        fmt.<span class=\"pl-c1\">Println</span>(<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>hello, and<span class=\"pl-pds\">\"</span></span>)\n        fmt.<span class=\"pl-c1\">Println</span>(<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>goodbye<span class=\"pl-pds\">\"</span></span>)\n        <span class=\"pl-c\">// Output:</span>\n        <span class=\"pl-c\">// hello, and</span>\n        <span class=\"pl-c\">// goodbye</span>\n}\n</code></pre>\n<p>Example functions without output comments are compiled but not executed.</p>\n<h3>Fuzzing</h3>\n<p>TODO introduced in Go 1.18</p>\n<h3>Subtests and Sub-benchmarks</h3>\n<p>The <code>Run</code> method allows defining subtests and sub-benchmarks,\nwithout having to define separate functions for each.\nThis enables uses like table-driven benchmarks and creating hierarchical tests.\nIt also provides a way to share common setup and tear-down code:</p>\n<pre><code class=\"language-go\"><span class=\"pl-k\">func</span> <span class=\"pl-en\">TestFoo</span>(<span class=\"pl-v\">t</span> *<span class=\"pl-v\">testing</span>.<span class=\"pl-v\">T</span>) {\n    <span class=\"pl-c\">// &#x3C;setup code></span>\n    t.<span class=\"pl-c1\">Run</span>(<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>one<span class=\"pl-pds\">\"</span></span>, <span class=\"pl-c1\">func</span>(t *testing.<span class=\"pl-smi\">T</span>) { ... })\n    t.<span class=\"pl-c1\">Run</span>(<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>two<span class=\"pl-pds\">\"</span></span>, <span class=\"pl-c1\">func</span>(t *testing.<span class=\"pl-smi\">T</span>) { ... })\n    t.<span class=\"pl-c1\">Run</span>(<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>B=1<span class=\"pl-pds\">\"</span></span>, <span class=\"pl-c1\">func</span>(t *testing.<span class=\"pl-smi\">T</span>) { ... })\n    <span class=\"pl-c\">// &#x3C;tear-down code></span>\n}\n</code></pre>\n<p>The argument to the <code>-run</code> and <code>-bench</code> command-line flags\nis an unanchored regular expression that matches the test's name.</p>\n<pre><code class=\"language-sh\">go <span class=\"pl-c1\">test</span> -run Foo     <span class=\"pl-c\"># Run top-level tests matching \"Foo\", such as \"TestFooBar\".</span>\ngo <span class=\"pl-c1\">test</span> -run Foo/B=  <span class=\"pl-c\"># For top-level tests matching \"Foo\", run subtests matching \"B=\".</span>\ngo <span class=\"pl-c1\">test</span> -run /B=1    <span class=\"pl-c\"># For all top-level tests, run subtests matching \"B=1\".</span>\n</code></pre>\n<p>Subtests can also be used to control parallelism.\nA parent test will only complete once all of its subtests complete.</p>\n<pre><code class=\"language-go\"><span class=\"pl-k\">func</span> <span class=\"pl-en\">TestGroupedParallel</span>(<span class=\"pl-v\">t</span> *<span class=\"pl-v\">testing</span>.<span class=\"pl-v\">T</span>) {\n    <span class=\"pl-k\">for</span> <span class=\"pl-smi\">_</span>, <span class=\"pl-smi\">tc</span> <span class=\"pl-k\">:=</span> <span class=\"pl-k\">range</span> tests {\n        <span class=\"pl-smi\">tc</span> <span class=\"pl-k\">:=</span> tc <span class=\"pl-c\">// capture range variable</span>\n        t.<span class=\"pl-c1\">Run</span>(tc.<span class=\"pl-smi\">Name</span>, <span class=\"pl-c1\">func</span>(t *testing.<span class=\"pl-smi\">T</span>) {\n            t.<span class=\"pl-c1\">Parallel</span>()\n        })\n    }\n}\n</code></pre>\n<h3>Main</h3>\n<p>It is sometimes necessary for a test program to do extra setup or teardown before or after testing.\nIt is also sometimes necessary for a test to control which code runs on the main thread.\nTo support these and other cases, if a test file contains a function:</p>\n<pre><code class=\"language-go\"><span class=\"pl-k\">func</span> <span class=\"pl-en\">TestMain</span>(<span class=\"pl-v\">m</span> *<span class=\"pl-v\">testing</span>.<span class=\"pl-v\">M</span>)\n</code></pre>\n<p>then the generated test will call <code>TestMain(m)</code> instead of running the tests directly.\n<code>TestMain</code> runs in the main goroutine and can do whatever setup and teardown is necessary around a call to <code>m.Run</code>.\nIt should then call <code>os.Exit</code> with the result of <code>m.Run</code>.\nWhen <code>TestMain</code> is called, <code>flag.Parse</code> has not been run.\nIf <code>TestMain</code> depends on command-line flags, it should call <code>flag.Parse</code> explicitly.</p>\n<p>A simple implementation of <code>TestMain</code> is:</p>\n<pre><code class=\"language-go\"><span class=\"pl-k\">func</span> <span class=\"pl-en\">TestMain</span>(<span class=\"pl-v\">m</span> *<span class=\"pl-v\">testing</span>.<span class=\"pl-v\">M</span>) {\n\t<span class=\"pl-c\">// flag.Parse()</span>\n\tos.<span class=\"pl-c1\">Exit</span>(m.<span class=\"pl-c1\">Run</span>())\n}\n</code></pre>\n<h3>Helper functions</h3>\n<p>When testing, to print location of a call to the helper function,\ninstead of a line in the definition of the helper function, invoke <code>Helper</code> method in the definition of the helper function.</p>\n<p>For example:</p>\n<pre><code class=\"language-go\"><span class=\"pl-k\">func</span> <span class=\"pl-en\">assertTrue</span>(<span class=\"pl-v\">t</span> *<span class=\"pl-v\">testing</span>.<span class=\"pl-v\">T</span> <span class=\"pl-v\">condition</span> <span class=\"pl-v\">bool</span>) {\n    <span class=\"pl-c\">// This marks assertTrue a helper function.</span>\n    <span class=\"pl-c\">// Without it, if something is wrong,</span>\n    <span class=\"pl-c\">// `go test` will always print the line number of `t.Fail()` below.</span>\n    t.<span class=\"pl-c1\">Helper</span>()\n    <span class=\"pl-k\">if</span> !condition {\n        t.<span class=\"pl-c1\">Fail</span>()\n    }\n}\n\n<span class=\"pl-k\">func</span> <span class=\"pl-en\">TestFoo</span>(<span class=\"pl-v\">t</span> *<span class=\"pl-v\">testing</span>.<span class=\"pl-v\">T</span>) {\n    <span class=\"pl-c\">// Since assertTrue is marked as a helper function,</span>\n    <span class=\"pl-c\">// `go test` will print the line number of the following line.</span>\n    <span class=\"pl-c1\">assertTrue</span>(t, <span class=\"pl-c1\">1</span> + <span class=\"pl-c1\">1</span> == <span class=\"pl-c1\">1</span>)\n}\n</code></pre>\n<p><code>testing/iotest</code> implements Readers and Writers useful mainly for testing.</p>\n<h2>Tooling</h2>\n<h3>Module</h3>\n<p>Initialize a module:</p>\n<pre><code class=\"language-sh\">go mod init yourname.github.com/hello<span class=\"pl-s\"><span class=\"pl-pds\">`</span></span>\n</code></pre>\n<p>This will create a <code>go.mod</code> file,\nwhere dependencies will be listed.</p>\n<p>Update <code>go.mod</code> based on Go source files,\nand install missing dependencies automatically:</p>\n<pre><code class=\"language-sh\">go mod tidy\n</code></pre>\n<p>The specific dependency versions installed will be recorded in <code>go.sum</code>.</p>\n<h3>Formatting</h3>\n<p><code>go fmt</code> formats your code.\nIt has no line length limit.</p>\n<h3>Documentation</h3>\n<p>TODO Go 1.19 changes doc comments syntax.</p>\n<p><code>go doc</code> processes Go source files to extract documentation.\nComments that appear before top-level declarations, with no intervening newlines, are extracted along with the declaration.</p>\n<p>Every package should have a <em>package comment</em>, a block comment preceding the package clause.\nFor multi-file packages, the package comment only needs to be present in one file, and any one will do.</p>\n<p>Comments do not need extra formatting such as banners of stars.\nThe comments are uninterpreted plain text, except that indented text will be display in a fixed-width font, suitable for program snippets.</p>\n<p><code>godoc</code> does not support cross reference.</p>\n<p>Inside a package, every exported (capitalized) name in a program should have a <em>doc comment</em>.</p>\n<p>The first sentence of a doc comment should be a one-sentence summary that starts with the name being declared.\nThis is because <code>godoc</code> is stupid.\nIt does not offer a <code>search</code> function.\nTo search for a function, we have to use <code>grep</code>:</p>\n<pre><code>go doc regexp | grep parse\n</code></pre>\n<p><em>Effective Go</em> pointed out:</p>\n<blockquote>\n<p>If all the doc comments in the package began, \"This function...\",\n<code>grep</code> wouldn't help you remember the name.</p>\n</blockquote>\n<p>This approach has three issues:</p>\n<p>First, beginning a comment with <code>\"This function...</code> may be redundant, but just omitting the function name like <code>Returns the source text used to compile the regular expression.</code> is more succinct.</p>\n<p>Second, although this approach does support a hacky way to search for function names, it does not provide an important information, the function signature, which is crucial for a static typed language.</p>\n<p>Third, in fact neither <code>godoc</code> nor <code>grep</code> has a concept of sentence.\nThus the \"first sentence\" is actually the \"first line\".\nThe <code>go doc regexp | grep parse</code> example given in the <em>Effective Go</em> demonstrates how ineffective this approach.\n<code>go doc regexp | grep parse</code> finds <code>Compile</code>, but fails to find <code>MustCompile</code> and <code>MustCompilePOSIX</code>:</p>\n<pre><code>MustCompile is like Compile but panics if the expression cannot be\nparsed.\n\nMustCompilePOSIX is like CompilePOSIX but panics if the expression\ncannot be parsed.\n</code></pre>\n<p>Because \"parsed\" does not fit into the first line,\n<code>go doc regexp | grep parse</code> fails to find these two related functions.</p>\n<p>This is a typical example of a poor design that roots in the unix philosophy \"pass everything as text\".</p>\n<p><code>godoc</code> should have parsed the comments into structures consist of signature, summary, description, etc., and either provided a built-in search command, or produced an AST for other tools to consume.</p>\n<h2>Unsupported</h2>\n<p>Go does not have generics.</p>\n<p>TODO Go 1.18 introduces generics.</p>\n<p>Go does not distinguish reassignable and irreassignable variables, even function parameters and method receiver are reassignable (just like a local variable).</p>\n<p>Go does not have immutable collection types in its standard library.</p>\n<p>Go does not support optional parameters or overloading, except for some built-in functions like <code>append</code> and <code>make</code>.</p>\n<h2>Style and Conventions</h2>\n<ol>\n<li>Error strings should not be capitalized (unless beginning with proper nouns or acronyms) or end with punctuation, since they are usually printed following other context.</li>\n<li>Avoid renaming imports except to avoid a name collision; good package names should not require renaming. In the event of collision, prefer to rename the most local or project-specific import.</li>\n<li>Words in names that are initialisms or acronyms have a consistent case. For example, <code>xmlHTTPRequest</code> or <code>XMLHTTPRequest</code>. Code generated by the protocol buffer compiler is exempt from this rule.</li>\n<li>Go interfaces generally belong in the package that uses values of the interface type, not the package that implements those values. The implementing package should return concrete (usually pointer or struct) types: that way, new methods can be added to implementations without requiring extensive refactoring.</li>\n<li>Prefer synchronous functions over asynchronous ones. If callers need more concurrency, they can add it easily by calling the function from a separate goroutine. But it is quite difficult - sometimes impossible - to remove unnecessary concurrency at the caller side.</li>\n<li>In tests, the order is <code>actual != expected</code>, and the message uses that order too. For example, <code>if got != tt.want {t.Errorf(\"Foo(%q) = %d; want %d\", tt.in, got, tt.want)}</code> Some test frameworks encourage writing these backwards: <code>0 != x, \"expected 0, got x\"</code>, and so on. Go does not.</li>\n</ol>\n<p>See <a href=\"https://github.com/golang/go/wiki/CodeReviewComments\">https://github.com/golang/go/wiki/CodeReviewComments</a> for more information.</p>\n<h2>References</h2>\n<p>This introduction is based on the following materials:</p>\n<ol>\n<li><a href=\"https://tour.golang.org/\">A Tour of Go</a></li>\n<li><a href=\"https://golang.org/doc/effective_go.html\">Effective Go</a></li>\n<li><a href=\"https://gobyexample.com/timeouts\">Go by Example</a></li>\n<li><a href=\"https://blog.golang.org/go-slices-usage-and-internals\">Go Slices: usage and internals</a></li>\n<li><a href=\"https://blog.golang.org/defer-panic-and-recover\">Defer, Panic, and Recover</a></li>\n</ol>","date_published":"Sat, 25 Aug 2018 02:30:57 GMT","date_modified":"Mon, 05 Sep 2022 15:35:49 GMT"},{"id":"https://mmap.page/dive-into/ocaml/","url":"https://mmap.page/dive-into/ocaml/","title":"OCaml Basic","content_html":"<h1>OCaml Basic</h1>\n<h2>Types</h2>\n<ul>\n<li><strong>unit</strong> <code>()</code></li>\n<li><strong>bool</strong> <code>true</code>, <code>false</code></li>\n<li><strong>int</strong> <code>min_int ... -1 0 1 2 ... max_int</code> (63-bit signed integers on a 64-bit machine)</li>\n<li><strong>char</strong> <code>'c' ...</code> (8-bit byte)</li>\n<li><strong>string</strong> <code>\"a sequence of char\"</code></li>\n<li><strong>float</strong> <code>min_float ... 0.0 ... max_float</code> (<code>double</code> in C)</li>\n<li><strong>option</strong> <code>type 'a option = None | Some of 'a</code></li>\n<li><strong>io</strong> <code>in_channel</code>, <code>out_channel</code></li>\n</ul>\n<h2>Operators</h2>\n<ul>\n<li>arithmetic operators for integers: <code>+ - * / mod</code></li>\n<li>arithmetic operators for floats: <code>+. -. *. /. **</code></li>\n<li>comparison: <code>= &#x3C; &#x3C;= > >= &#x3C;></code> and <code>== !=</code></li>\n<li>logical operators: <code>&#x26;&#x26;</code>, <code>||</code>, <code>not</code>, <code>if ... then ... else ...</code>, <code>if ... then ...</code></li>\n<li>tuples: <code>(a, b)</code></li>\n<li>cons: <code>a :: (b :: [])</code> (<code>[a; b; c]</code>)</li>\n<li>concat: <code>string1 ^ string2</code>, <code>[a; b] @ [c; d]</code></li>\n</ul>\n<p>Wrapping an operator in parentheses to form a function:</p>\n<pre><code class=\"language-ocaml\">(<span class=\"pl-k\">+</span>) <span class=\"pl-c1\">1</span> <span class=\"pl-c1\">2</span>;;\n</code></pre>\n<h2>Names</h2>\n<ul>\n<li><code>let name = expression</code></li>\n<li><code>let name1 = expression1 in let name2 = expression2 in ...</code></li>\n</ul>\n<h2>Pattern Matching</h2>\n<pre><code class=\"language-ocaml\"><span class=\"pl-k\">match</span> x <span class=\"pl-k\">with</span>\n  <span class=\"pl-k\">|</span> <span class=\"pl-c1\">0</span> <span class=\"pl-k\">|</span> <span class=\"pl-c1\">1</span> -> <span class=\"pl-c1\">1</span>\n  <span class=\"pl-k\">|</span> <span class=\"pl-c1\">_</span> -> x\n</code></pre>\n<p>Pattern matching multiple values:</p>\n<pre><code class=\"language-ocaml\"><span class=\"pl-k\">match</span> x, y <span class=\"pl-k\">with</span>\n  <span class=\"pl-k\">|</span> <span class=\"pl-c1\">0</span>, <span class=\"pl-c1\">0</span> -> <span class=\"pl-c1\">true</span>\n  <span class=\"pl-k\">|</span> <span class=\"pl-c1\">_</span>, <span class=\"pl-c1\">_</span> -> <span class=\"pl-c1\">false</span>\n</code></pre>\n<p>Nested pattern matching:</p>\n<pre><code class=\"language-ocaml\"><span class=\"pl-k\">match</span> x <span class=\"pl-k\">with</span>\n  <span class=\"pl-k\">|</span> <span class=\"pl-c1\">0</span> ->\n    <span class=\"pl-k\">begin</span> <span class=\"pl-k\">match</span> y <span class=\"pl-k\">with</span>\n      <span class=\"pl-k\">|</span> <span class=\"pl-c1\">0</span> -> <span class=\"pl-c1\">0</span>\n      <span class=\"pl-k\">|</span> <span class=\"pl-c1\">_</span> -> x\n    <span class=\"pl-k\">end</span>\n  <span class=\"pl-k\">|</span> <span class=\"pl-c1\">1</span> -> <span class=\"pl-c1\">1</span>\n</code></pre>\n<p><code>begin ... end</code> is a syntax sugar for <code>( ... )</code>.</p>\n<p>Guarded patterns:</p>\n<pre><code class=\"language-ocaml\"><span class=\"pl-k\">match</span> x <span class=\"pl-k\">with</span>\n  <span class=\"pl-k\">|</span> <span class=\"pl-v\">x</span> <span class=\"pl-k\">when</span> x <span class=\"pl-kos\">&#x3C;</span><span class=\"pl-k\">=</span> <span class=\"pl-c1\">0</span> -> <span class=\"pl-c1\">1</span>\n  <span class=\"pl-k\">|</span> <span class=\"pl-c1\">_</span> -> x <span class=\"pl-k\">*</span> f (x <span class=\"pl-k\">-</span> <span class=\"pl-c1\">1</span>);;\n</code></pre>\n<p>Alias patterns (<code>as</code>):</p>\n<pre><code class=\"language-ocaml\"><span class=\"pl-k\">let</span> <span class=\"pl-k\">rec </span><span class=\"pl-en\">fib</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">function</span>\n  <span class=\"pl-k\">|</span> (<span class=\"pl-c1\">0</span> | <span class=\"pl-c1\">1</span>) <span class=\"pl-v\">as</span> <span class=\"pl-v\">i</span> -> i\n  <span class=\"pl-k\">|</span> <span class=\"pl-v\">i</span> -> fib(i<span class=\"pl-c1\">-2</span>) <span class=\"pl-k\">+</span> fib(i<span class=\"pl-c1\">-1</span>);;\n</code></pre>\n<p>Matching character intervals:</p>\n<pre><code class=\"language-ocaml\"><span class=\"pl-k\">let</span> <span class=\"pl-en\">alphanum</span> <span class=\"pl-v\">c</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">match</span> c <span class=\"pl-k\">with</span>\n  <span class=\"pl-k\">|</span> <span class=\"pl-c1\">'a'</span>..<span class=\"pl-c1\">'z'</span> <span class=\"pl-k\">|</span> <span class=\"pl-c1\">'A'</span>..<span class=\"pl-c1\">'Z'</span> -> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>letter<span class=\"pl-pds\">\"</span></span>\n  <span class=\"pl-k\">|</span> <span class=\"pl-c1\">'0'</span>..<span class=\"pl-c1\">'9'</span> -> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>number<span class=\"pl-pds\">\"</span></span>\n  <span class=\"pl-k\">|</span> <span class=\"pl-c1\">_</span> -> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>other<span class=\"pl-pds\">\"</span></span>;;\n</code></pre>\n<p>Matches should be exhaustive and reachable,\notherwise the compiler will emit a warning.</p>\n<p>Matching against floating-point values is rarely used\nbecause of numerical issues.</p>\n<p>Also, name binding (<code>let</code>) uses pattern matching under the hood.</p>\n<pre><code class=\"language-ocaml\"><span class=\"pl-k\">let</span> (a,b,c) <span class=\"pl-k\">=</span> (<span class=\"pl-c1\">1</span>, <span class=\"pl-c1\">true</span>, <span class=\"pl-c1\">'A'</span>);;\n</code></pre>\n<h2>Functions</h2>\n<ul>\n<li>Anonymous function: <code>fun parameter -> body</code></li>\n<li>Shortcut for pattern matching: <code>function [] -> 0 | _::rest -> 1 + length t</code></li>\n<li>Named function: <code>let name parametr1 paremeter2 -> body</code></li>\n<li>Recursive function: <code>let rec name parameter -> body</code></li>\n<li>Recursive value: <code>let rec infinite_list = 1 :: 1</code></li>\n<li>Mutually recursive function: <code>let rec f x = ... and g y = ...</code></li>\n<li>Type constraining: <code>let id (x: int): int = x</code></li>\n<li>Define void functions: <code>let void_function () = body</code></li>\n<li>Call void functions: <code>print_newline ()</code></li>\n<li>No main function, <code>let () = body</code> ensures body is side-effect only</li>\n<li>Labelled parameters: <code>let f ~x ~y = x - y;; f ~y:2 ~x:1;;</code></li>\n<li>Optional parameters: <code>let f ?(x=1) y = x - y;; f ~x:3 2;;</code></li>\n</ul>\n<p>Optional parameters use pattern match under the hood:</p>\n<pre><code class=\"language-ocaml\"><span class=\"pl-k\">let</span> <span class=\"pl-en\">f</span> <span class=\"pl-v\">?</span><span class=\"pl-ent\">x</span> <span class=\"pl-v\">y</span> <span class=\"pl-k\">=</span>\n  <span class=\"pl-k\">let</span> x <span class=\"pl-k\">=</span> <span class=\"pl-k\">match</span> x <span class=\"pl-k\">with None -> 1 | Some n -></span> n <span class=\"pl-k\">in</span>\n    x <span class=\"pl-k\">-</span> y;;\n\nf ?x:(<span class=\"pl-en\">Some</span> <span class=\"pl-c1\">3</span>) <span class=\"pl-c1\">2</span>;;\n</code></pre>\n<p>This 'raw' syntax can be used to delegate default behavior\nfrom a wrapper function to the wrapped function:</p>\n<pre><code class=\"language-ocaml\"><span class=\"pl-k\">let</span> <span class=\"pl-en\">f'</span> <span class=\"pl-v\">?</span><span class=\"pl-ent\">x</span> <span class=\"pl-v\">y</span> <span class=\"pl-k\">=</span> f ?x y\n</code></pre>\n<p>Optional parameters are always called as named parameters.\nTo support partial application (currying),\noptional parameters should always be followed by not-optional parameters in declaration.</p>\n<p>Because optional parameters applications reuse\nthe syntax of named parameters,\nthe type of a higher-order function may be ambiguous.\nThe compiler will always prefer to infer that a parameter is labeled, not optional.\nIf optional parameter is wanted, type need to be specified explicitly.</p>\n<h2>Types</h2>\n<ul>\n<li>type definition: <code>type name = type expression</code></li>\n<li>with parameters: <code>type 'a name = type expression</code></li>\n<li>records: <code>type name = { field: type }</code></li>\n<li>sum type: <code>type name = | S | T of ...</code></li>\n</ul>\n<p>Unlike functions, type declaration is recursive by default.</p>\n<h2>Exception</h2>\n<ul>\n<li><code>exception ExceptionName</code></li>\n<li><code>exception ExceptionWithExtraInfo of type</code></li>\n<li><code>raise ExceptionName</code>: type of <code>raise</code> is <code>exn -> 'a</code> which seems impossible because it never returns at all. Returning <code>'a</code> allows throwing an exception anywhere in a program.</li>\n<li><code>try ... with ...</code></li>\n<li><code>failwith \"string\"</code>: <code>raise (Failure \"string\")</code> (predefined)</li>\n<li><code>Invalid_argument</code> is like <code>Failure</code> but mainly used for programming bugs</li>\n<li><code>assert (boolean)</code>:  <code>boolean || raise (Assert_failure ...)</code></li>\n<li><code>assert false</code> is similar to <code>raise Invalid_argument</code></li>\n</ul>\n<h2>Mutability</h2>\n<h3>Reference</h3>\n<ul>\n<li><code>'a ref</code>: <code>type 'a ref = { mutable contents: 'a }</code></li>\n<li><code>let p = ref 0</code></li>\n<li><code>p := 1</code>: <code>p.contents &#x3C;- 1</code></li>\n<li><code>!p</code>: <code>p.contents</code></li>\n<li><code>let np = ref 1</code>: <code>let np = {p with contents=1}</code></li>\n</ul>\n<h3>Array</h3>\n<ul>\n<li><code>[|1; 2; 3|]</code></li>\n<li><code>Array.make length init</code>, <code>Array.length</code></li>\n<li><code>arr.(i)</code>, <code>arr.(i) &#x3C;- e</code></li>\n</ul>\n<h3>Loop</h3>\n<ul>\n<li><code>while condition do expression done</code></li>\n<li><code>for name = start to/downto end do expression done</code></li>\n</ul>\n<h2>Lazy</h2>\n<ul>\n<li>Construct a lazy value: <code>let name = lazy expression</code></li>\n<li>Returns the value (calculated on demand): <code>Lazy.force name</code></li>\n</ul>\n<h2>Module</h2>\n<ul>\n<li><code>Module.function</code> or <code>open Module</code> to use unqualified names</li>\n<li>access record field wrapped in module: <code>t.Module.field</code></li>\n<li>module file: normal OCaml files <code>.ml</code></li>\n<li>interface: <code>val f : int -> int</code> in <code>.mli</code> files</li>\n</ul>\n<p>Example: <code>set.mli</code></p>\n<pre><code class=\"language-ocaml\"><span class=\"pl-c\">(* Abstract type *)</span>\n<span class=\"pl-k\">type</span> <span class=\"pl-k\">'a set</span>\n<span class=\"pl-c\">(* Concrete type to make it explicit what is a choice,</span>\n<span class=\"pl-c\">since simply writing</span>\n<span class=\"pl-c\"></span>\n<span class=\"pl-c\">    type 'a choice</span>\n<span class=\"pl-c\"></span>\n<span class=\"pl-c\">is not informative.</span>\n<span class=\"pl-c\">Also, exposing concrete implementation allows client code</span>\n<span class=\"pl-c\">to pattern match against choice.</span>\n<span class=\"pl-c\"></span>\n<span class=\"pl-c\">`set.ml` must repeat this definition.</span>\n<span class=\"pl-c\">*)</span>\n<span class=\"pl-k\">type</span> <span class=\"pl-k\">'a choice </span>=\n  | <span class=\"pl-en\">Element</span> <span class=\"pl-k\">of</span> <span class=\"pl-k\">'a</span>\n  | <span class=\"pl-en\">Empty</span>\n<span class=\"pl-c\">(* declare types for public values *)</span>\n<span class=\"pl-k\">val</span> <span class=\"pl-en\">empty</span> : <span class=\"pl-k\">'a</span> <span class=\"pl-k\">set</span>\n<span class=\"pl-k\">val</span> <span class=\"pl-en\">contains</span> : <span class=\"pl-k\">'a</span> <span class=\"pl-k\">set</span> -> <span class=\"pl-k\">'a</span> -> <span class=\"pl-k\">bool</span>\n<span class=\"pl-c\">(* optional and labeled parameters *)</span>\n<span class=\"pl-k\">val</span> <span class=\"pl-en\">add</span> : <span class=\"pl-v\">?</span><span class=\"pl-ent\">elem</span><span class=\"pl-v\">:</span>'a -> <span class=\"pl-ent\">a_set</span><span class=\"pl-v\">:'</span><span class=\"pl-k\">a</span><span class=\"pl-v\"> </span><span class=\"pl-k\">set</span> -> <span class=\"pl-k\">'a</span> <span class=\"pl-k\">set</span>\n<span class=\"pl-k\">val</span> <span class=\"pl-en\">choose</span> : <span class=\"pl-k\">'a</span> <span class=\"pl-k\">set</span> -> <span class=\"pl-k\">'a</span> <span class=\"pl-k\">choice</span>\n</code></pre>\n<p>Or embed modules in a file:</p>\n<pre><code class=\"language-ocaml\"><span class=\"pl-k\">module</span> <span class=\"pl-en\">Set</span> : <span class=\"pl-k\">sig</span>\n  <span class=\"pl-k\">type</span> <span class=\"pl-k\">t</span>\n  val ...\n<span class=\"pl-k\">end</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">struct</span>\n  <span class=\"pl-k\">type</span> <span class=\"pl-k\">t </span>= ...\n  <span class=\"pl-k\">let</span> ...\n<span class=\"pl-k\">end</span>\n</code></pre>\n<p>Or separate signature and implementation (allow different implementations):</p>\n<pre><code class=\"language-ocaml\"><span class=\"pl-k\">module type </span><span class=\"pl-en\">Set</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">sig</span>\n  <span class=\"pl-k\">include</span> (<span class=\"pl-k\">module</span> <span class=\"pl-k\">type</span> of <span class=\"pl-en\">OtherModule</span>)\n  <span class=\"pl-k\">type</span> <span class=\"pl-k\">...</span>\n  val ...\n<span class=\"pl-k\">end</span>\n\n<span class=\"pl-k\">module type </span><span class=\"pl-en\">ListBackend</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">struct</span>\n  <span class=\"pl-k\">include</span> <span class=\"pl-en\">OtherModule</span>\n  <span class=\"pl-k\">type</span> <span class=\"pl-k\">...</span>\n  <span class=\"pl-k\">let</span> ...\n<span class=\"pl-k\">end</span>\n\n<span class=\"pl-k\">module</span> <span class=\"pl-en\">SetOnList</span> : <span class=\"pl-en\">Set</span> <span class=\"pl-k\">=</span> <span class=\"pl-en\">ListBackend</span>\n</code></pre>\n<p>By convention, the primary type of a given module <code>M</code> is called <code>t</code>.\nAnd functions in <code>M</code> that take a value of <code>M.t</code> takes it as their first argument.</p>\n<h2>Get Started</h2>\n<h3>Install</h3>\n<pre><code>sudo apt-get install ocaml-nox opam curl build-essential m4\n</code></pre>\n<h3>Compile</h3>\n<p>For a single file:</p>\n<pre><code>ocamlopt -strict-sequence -o x x.ml\n</code></pre>\n<p><code>-strict-sequence</code> forces the left-hand part of each sequence to have type unit,\nthus <code>a; b; c</code> is equivalent to:</p>\n<pre><code class=\"language-ocaml\"><span class=\"pl-k\">let</span> <span class=\"pl-c1\">()</span> <span class=\"pl-k\">=</span> a <span class=\"pl-k\">in</span>\n<span class=\"pl-k\">let</span> <span class=\"pl-c1\">()</span> <span class=\"pl-k\">=</span> b <span class=\"pl-k\">in</span>\nc\n</code></pre>\n<p>For debugging, compile to byte-code,\nwhich is also faster to compile,\nalso turning on all warnings\nand adding debug information\n(required to run <code>ocamldebug</code> and to print stack backtraces)</p>\n<pre><code>ocamlc -wA -g -o x x.ml\nocamldebug ./x\n</code></pre>\n<p>For a project (automatically finding modules, etc.):</p>\n<pre><code>ocamlbuild -strict-sequence x.native\n</code></pre>\n<h3>OPAM</h3>\n<p>Initialize (run once):</p>\n<pre><code>opam init\n</code></pre>\n<h3>Standard Library</h3>\n<p>OCaml's Standard Library is developed for use in bootstrapping the compiler,\nand is purposefully kept small and simple.</p>\n<p>The general-purpose 'standard' library is\nthe Core distribution provided by Jane Street.</p>\n<pre><code>opam install core\n</code></pre>\n<h3>REPL</h3>\n<p>The built-in repl <code>opam</code> lacks features such as history and completion.\nUse <code>utop</code> instead (shipped with <code>core</code>):</p>\n<pre><code>utop\n</code></pre>\n<h3>Editors</h3>\n<p>Merlin is an editor service that provides modern IDE features:</p>\n<ul>\n<li>context-sensitive auto-completion</li>\n<li>interactive type-querying</li>\n<li>highlight parts of code that don't compile on the go</li>\n<li>goto definition</li>\n</ul>\n<p>Install it via opam:</p>\n<pre><code>opam install merlin\n# Auto configure Emacs and Vim\nopam user-setup install\n</code></pre>\n<p>Supported editors:</p>\n<ul>\n<li>Emacs</li>\n<li>Vim</li>\n<li>Acme</li>\n<li>Atom</li>\n<li>VS Code</li>\n<li>Sublime Text 3</li>\n</ul>\n<p><code>ocp-indent</code> can indent opam code automatically\n(available via <code>opam</code>).</p>\n<h2>Code Example</h2>\n<pre><code class=\"language-ocaml\"><span class=\"pl-c\">(* FUNCTIONS *)</span>\n\n<span class=\"pl-c\">(* Floats use different operators. *)</span>\n<span class=\"pl-k\">let</span> pi <span class=\"pl-k\">=</span> <span class=\"pl-c1\">4.0</span> <span class=\"pl-k\">*.</span> atan <span class=\"pl-c1\">1.0</span>\n\n<span class=\"pl-c\">(* Global type inference. *)</span>\n<span class=\"pl-k\">let</span> square <span class=\"pl-k\">=</span> <span class=\"pl-k\">fun</span> <span class=\"pl-v\">x</span> -> x <span class=\"pl-k\">*.</span> x\n\n<span class=\"pl-c\">(* Functions are by default non-recursive.</span>\n<span class=\"pl-c\">Recursion need to be explicit (with `rec`).</span>\n<span class=\"pl-c\">*)</span>\n<span class=\"pl-k\">let</span> <span class=\"pl-k\">rec </span><span class=\"pl-en\">fact</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">fun</span> <span class=\"pl-v\">n</span> ->\n  <span class=\"pl-k\">match</span> n <span class=\"pl-k\">with</span> <span class=\"pl-c\">(* pattern matching *)</span>\n  <span class=\"pl-k\">|</span> <span class=\"pl-c1\">0</span> <span class=\"pl-k\">|</span> <span class=\"pl-c1\">1</span> -> <span class=\"pl-c1\">1</span>\n  <span class=\"pl-k\">|</span> <span class=\"pl-c1\">_</span> -> n <span class=\"pl-k\">*</span> fact (n <span class=\"pl-k\">-</span> <span class=\"pl-c1\">1</span>)\n<span class=\"pl-c\">(* The compiler will emit a warning if</span>\n<span class=\"pl-c\">pattern matching is not exhaustive,</span>\n<span class=\"pl-c\">or contains unreachable matches.</span>\n<span class=\"pl-c\">*)</span>\n\n<span class=\"pl-c\">(* Mutually recursion with function declaration shortcuts. *)</span>\n<span class=\"pl-k\">let</span> <span class=\"pl-k\">rec </span><span class=\"pl-en\">sort</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">function</span>\n  <span class=\"pl-k\">|</span> <span class=\"pl-c1\">[]</span> -> <span class=\"pl-c1\">[]</span>\n  <span class=\"pl-k\">|</span> <span class=\"pl-v\">first</span> :: <span class=\"pl-v\">rest</span> -> insert first (sort rest)\n<span class=\"pl-k\">and</span> <span class=\"pl-en\">insert</span> <span class=\"pl-v\">element</span> <span class=\"pl-v\">a_list</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">match</span> a_list <span class=\"pl-k\">with</span>\n  <span class=\"pl-k\">|</span> <span class=\"pl-c1\">[]</span> -> [element]\n  <span class=\"pl-k\">|</span> <span class=\"pl-v\">first</span> :: <span class=\"pl-v\">rest</span> ->\n    <span class=\"pl-k\">if</span> element <span class=\"pl-kos\">&#x3C;</span><span class=\"pl-k\">=</span> first <span class=\"pl-k\">then</span>\n      element :: a_list\n    <span class=\"pl-k\">else</span> <span class=\"pl-c\">(* the else clause has the same type as the then clause *)</span>\n      first :: insert element rest\n<span class=\"pl-c\">(* `sort` and `insert` is polymorphic.</span>\n<span class=\"pl-c\">They can be applied to lists of any type,</span>\n<span class=\"pl-c\">and returns a list with the same type.</span>\n<span class=\"pl-c\"></span>\n<span class=\"pl-c\">`sort` and `insert` does not modify their input list.</span>\n<span class=\"pl-c\">Lists are immutable, like most data structures in OCaml.</span>\n<span class=\"pl-c\">*)</span>\n\n<span class=\"pl-c\">(* OCaml provides the `|>` operator to flip function and its parameter.*)</span>\n<span class=\"pl-k\">let</span> <span class=\"pl-k\">rec </span><span class=\"pl-en\">fact</span>' <span class=\"pl-k\">=</span> <span class=\"pl-k\">function</span>\n  <span class=\"pl-k\">|</span> <span class=\"pl-c1\">0</span> <span class=\"pl-k\">|</span> <span class=\"pl-c1\">1</span> -> <span class=\"pl-c1\">1</span>\n  <span class=\"pl-k\">|</span> <span class=\"pl-v\">n</span> ->\n    n\n    <span class=\"pl-k\">|></span> (<span class=\"pl-k\">-</span>) <span class=\"pl-c1\">1</span> <span class=\"pl-c\">(* Convert infix operator to prefix function call. *)</span>\n    <span class=\"pl-k\">|></span> fact\n    <span class=\"pl-k\">|></span> ( <span class=\"pl-k\">*</span> ) n <span class=\"pl-c\">(* Spaces to avoided be recognized as comments. *)</span>\n<span class=\"pl-c\">(* It can easily be defined as a higher-order function. *)</span>\n<span class=\"pl-k\">let</span> <span class=\"pl-en\">(|>)</span> <span class=\"pl-v\">f</span> <span class=\"pl-v\">x</span> <span class=\"pl-k\">=</span> x f\n\n<span class=\"pl-c\">(* `|>` operator makes refactoring (changing numbers and order of argument) harder,</span>\n<span class=\"pl-c\">thus intemediate variables are often preferred. *)</span>\n\n<span class=\"pl-c\">(* TYPES *)</span>\n\n<span class=\"pl-c\">(* Type Aliases *)</span>\n<span class=\"pl-k\">type</span> <span class=\"pl-k\">boolean </span>= <span class=\"pl-k\">bool</span>\n<span class=\"pl-k\">type</span> <span class=\"pl-k\">integer </span>= <span class=\"pl-k\">int</span>\n<span class=\"pl-k\">type</span> <span class=\"pl-k\">double </span>= <span class=\"pl-k\">float</span>\n<span class=\"pl-k\">type</span> <span class=\"pl-k\">character </span>= <span class=\"pl-k\">char</span>\n<span class=\"pl-k\">type</span> <span class=\"pl-k\">sequence_of_bytes </span>= <span class=\"pl-k\">string</span>\n\n<span class=\"pl-c\">(* Records *)</span>\n<span class=\"pl-k\">type</span> <span class=\"pl-k\">point </span>= {x: <span class=\"pl-k\">float;</span> y: <span class=\"pl-k\">float</span>}\n<span class=\"pl-k\">let</span> <span class=\"pl-en\">new_point</span> <span class=\"pl-v\">x</span> <span class=\"pl-v\">y</span> <span class=\"pl-k\">=</span> {x; y}\n\n<span class=\"pl-c\">(* Here type annotations can be omitted.</span>\n<span class=\"pl-c\">However, it is a good practice to annotate types for records in real projects,</span>\n<span class=\"pl-c\">because OCaml infer record types from field names.</span>\n<span class=\"pl-c\"></span>\n<span class=\"pl-c\">In real projects, declaration of the distance function may be far from</span>\n<span class=\"pl-c\">the declaration of the point type.</span>\n<span class=\"pl-c\">And later declaration of a new record with the same field names may be added</span>\n<span class=\"pl-c\">between the declaration of type point and function distance,</span>\n<span class=\"pl-c\">which will cause type error of the distance function</span>\n<span class=\"pl-c\">if the fields of the new record have different types,</span>\n<span class=\"pl-c\">or change the semantics of function distance silently</span>\n<span class=\"pl-c\">if the fields of the new record have same types as type point.</span>\n<span class=\"pl-c\">*)</span>\n<span class=\"pl-k\">let</span> <span class=\"pl-en\">distance</span> (<span class=\"pl-v\">from</span><span class=\"pl-k\">: point</span>) (<span class=\"pl-v\">target</span><span class=\"pl-k\">: point</span>) <span class=\"pl-k\">=</span>\n  ((from.x <span class=\"pl-k\">-.</span> target.x) <span class=\"pl-k\">**</span> <span class=\"pl-c1\">2.0</span> <span class=\"pl-k\">+.</span> (from.y <span class=\"pl-k\">-.</span> target.y) <span class=\"pl-k\">**</span> <span class=\"pl-c1\">2.0</span>) <span class=\"pl-k\">**</span> <span class=\"pl-c1\">0.5</span>\n\n<span class=\"pl-c\">(* We cannot make function new_point also accepts integer values (will be converted to floats.</span>\n<span class=\"pl-c\">OCaml's type system does not allow this.</span>\n<span class=\"pl-c\">However, types can be wrapped/tagged with a type constructor,</span>\n<span class=\"pl-c\">and the wrapped/tagged types can be combined to disjoint unions.</span>\n<span class=\"pl-c\">This is called polymorphic variants.</span>\n<span class=\"pl-c\">*)</span>\n<span class=\"pl-k\">type</span> <span class=\"pl-k\">number </span>= [<span class=\"pl-en\">`Integer</span> <span class=\"pl-k\">of</span> <span class=\"pl-k\">int</span> | <span class=\"pl-en\">`Float</span> <span class=\"pl-k\">of</span> <span class=\"pl-k\">float</span>]\n<span class=\"pl-k\">let</span> <span class=\"pl-en\">new_point_polymorphic</span> (<span class=\"pl-v\">x</span><span class=\"pl-k\">: [&#x3C; number]</span>) (<span class=\"pl-v\">y</span><span class=\"pl-k\">: [&#x3C; number]</span>): <span class=\"pl-k\">point =</span>\n  <span class=\"pl-k\">match</span> x, y <span class=\"pl-k\">with</span>\n    <span class=\"pl-k\">|</span> <span class=\"pl-en\">`Integer</span> <span class=\"pl-v\">m</span>, <span class=\"pl-en\">`Integer</span> <span class=\"pl-v\">n</span> -> {x <span class=\"pl-k\">=</span> float_of_int m; y <span class=\"pl-k\">=</span> float_of_int n}\n    <span class=\"pl-k\">|</span> <span class=\"pl-en\">`Integer</span> <span class=\"pl-v\">m</span>, <span class=\"pl-en\">`Float</span> <span class=\"pl-v\">n</span> -> {x <span class=\"pl-k\">=</span> float_of_int m; y <span class=\"pl-k\">=</span> n}\n    <span class=\"pl-k\">|</span> <span class=\"pl-en\">`Float</span> <span class=\"pl-v\">m</span>, <span class=\"pl-en\">`Integer</span> <span class=\"pl-v\">n</span> -> {x <span class=\"pl-k\">=</span> m; y <span class=\"pl-k\">=</span> float_of_int n}\n    <span class=\"pl-k\">|</span> <span class=\"pl-en\">`Float</span> <span class=\"pl-v\">m</span>, <span class=\"pl-en\">`Float</span> <span class=\"pl-v\">n</span> -> {x <span class=\"pl-k\">=</span> m; y <span class=\"pl-k\">=</span> n}\n\n<span class=\"pl-c\">(* Unlike the closed [&#x3C; `A | `B], [> `A | `B] is structural typing,</span>\n<span class=\"pl-c\">opening to any type that can at least match `A and `B.</span>\n<span class=\"pl-c\">Both of them can only be denoted directly, not be given a name via `type`.</span>\n<span class=\"pl-c\">And [`A | `B] is fixed type.</span>\n<span class=\"pl-c\"></span>\n<span class=\"pl-c\">- [&#x3C; `A | `B | `C]: [&#x3C; `B | `A | `C], [&#x3C; `C | `A], [`A | `B | `C], [`B]</span>\n<span class=\"pl-c\">- [> `A | `B ]: [> `A | `C | `B], [`A | `B | `C], [> `A | `B], [`B | `A]</span>\n<span class=\"pl-c\">- [`A | `B]: [`B | `A]</span>\n<span class=\"pl-c\"></span>\n<span class=\"pl-c\">A | B is normal variant type:</span>\n<span class=\"pl-c\"></span>\n<span class=\"pl-c\">- It cannot be denoted directly. To use it, it has to been given a name.</span>\n<span class=\"pl-c\">- Once the name is given, A and B is assigned to a unique type. In other words,</span>\n<span class=\"pl-c\">  `type one_name = A | B` and `type another_name = A | B` are not compatible.</span>\n<span class=\"pl-c\"></span>\n<span class=\"pl-c\">Normal variants are slightly lighter than polymorphic variants,</span>\n<span class=\"pl-c\">since static information allows for more optimizations.</span>\n<span class=\"pl-c\">However noticeable differences would only appear on huge data structures.</span>\n<span class=\"pl-c\">*)</span>\n\n<span class=\"pl-c\">(* Recursive Types *)</span>\n<span class=\"pl-k\">type</span> <span class=\"pl-k\">'a binary_tree </span>= <span class=\"pl-c\">(* 'a is a type variable, and stands for any given type. *)</span>\n  | <span class=\"pl-en\">Leaf</span>\n  | <span class=\"pl-en\">Node</span> <span class=\"pl-k\">of</span> <span class=\"pl-k\">'a</span> <span class=\"pl-k\">*</span> <span class=\"pl-k\">'a</span> <span class=\"pl-k\">binary_tree</span> <span class=\"pl-k\">*</span> <span class=\"pl-k\">'a</span> <span class=\"pl-k\">binary_tree</span>\n  <span class=\"pl-c\">(* The `*` character is used</span>\n<span class=\"pl-c\">  because the set of all pairs of type `t * s`</span>\n<span class=\"pl-c\">  corresponds to the Cartesian product of</span>\n<span class=\"pl-c\">  the set of elements of type `t` and the set of elements of type `s`.</span>\n<span class=\"pl-c\">  *)</span>\n\n<span class=\"pl-c\">(* IMPERATIVE FEATURES *)</span>\n\n<span class=\"pl-k\">let</span> <span class=\"pl-en\">increse_array</span> <span class=\"pl-v\">arr</span> <span class=\"pl-k\">=</span>\n  <span class=\"pl-k\">let</span> length <span class=\"pl-k\">=</span> min (<span class=\"pl-c1\">Array.</span>length arr) <span class=\"pl-c1\">3</span> <span class=\"pl-k\">in</span>\n  <span class=\"pl-k\">let</span> incresements <span class=\"pl-k\">=</span> [|<span class=\"pl-c1\">1</span>; <span class=\"pl-c1\">2</span>; <span class=\"pl-c1\">3</span>|] <span class=\"pl-k\">in</span>\n  <span class=\"pl-k\">let</span> result <span class=\"pl-k\">=</span> <span class=\"pl-c1\">Array.</span>make length <span class=\"pl-c1\">0</span> <span class=\"pl-k\">in</span> <span class=\"pl-c\">(* 0.0 is initial value *)</span>\n  <span class=\"pl-k\">for</span> i <span class=\"pl-k\">=</span> <span class=\"pl-c1\">0</span> <span class=\"pl-k\">to</span> length <span class=\"pl-k\">-</span> <span class=\"pl-c1\">1</span> <span class=\"pl-k\">do</span>\n    result.(i) <span class=\"pl-kos\">&#x3C;</span><span class=\"pl-k\">-</span> arr.(i) <span class=\"pl-k\">+</span> incresements.(i)\n  <span class=\"pl-k\">done</span>; <span class=\"pl-c\">(* `a ; b` returns `b` *)</span>\n  result\n\n<span class=\"pl-k\">type</span> <span class=\"pl-k\">mutable_point </span>= { <span class=\"pl-k\">mutable </span>x: <span class=\"pl-k\">float;</span> <span class=\"pl-k\">mutable </span>y: <span class=\"pl-k\">float</span> }\n<span class=\"pl-k\">let</span> <span class=\"pl-en\">translate</span> <span class=\"pl-v\">p</span> <span class=\"pl-v\">dx</span> <span class=\"pl-v\">dy</span> <span class=\"pl-k\">=</span>\n  p.x <span class=\"pl-kos\">&#x3C;</span><span class=\"pl-k\">-</span> p.x <span class=\"pl-k\">+.</span> dx; p.y <span class=\"pl-kos\">&#x3C;</span><span class=\"pl-k\">-</span> p.y <span class=\"pl-k\">+.</span> dy;;\n\n<span class=\"pl-c\">(* OCaml standard library provides references, which mimics mutable variables. *)</span>\n<span class=\"pl-k\">type</span> <span class=\"pl-k\">'a reference </span>= { <span class=\"pl-k\">mutable </span>contents: <span class=\"pl-k\">'a</span> }\n<span class=\"pl-k\">let</span> <span class=\"pl-en\">ref</span> <span class=\"pl-v\">initial_value</span> <span class=\"pl-k\">=</span> { contents <span class=\"pl-k\">=</span> initial_value }\n<span class=\"pl-k\">let</span> <span class=\"pl-en\">(:=)</span> <span class=\"pl-v\">r</span> <span class=\"pl-v\">new_value</span> <span class=\"pl-k\">=</span> r.contents <span class=\"pl-kos\">&#x3C;</span><span class=\"pl-k\">-</span> new_value\n<span class=\"pl-k\">let</span> <span class=\"pl-en\">(!)</span> <span class=\"pl-v\">r</span> <span class=\"pl-k\">=</span> r.contents\n\n<span class=\"pl-c\">(* Store a polymorphic function as a mutable field in a record. *)</span>\n<span class=\"pl-k\">type</span> <span class=\"pl-k\">idref </span>= { <span class=\"pl-k\">mutable </span>id: <span class=\"pl-k\">'a</span>. <span class=\"pl-k\">'a</span> -> <span class=\"pl-k\">'a</span> }\n\n\n<span class=\"pl-c\">(* MODULE *)</span>\n\n<span class=\"pl-c\">(* OBJECT *)</span>\n<span class=\"pl-k\">class</span> <span class=\"pl-en\">point_1d</span> <span class=\"pl-v\">init</span> <span class=\"pl-k\">=</span>\n  <span class=\"pl-k\">object</span> (<span class=\"pl-en\">self</span>)\n    val <span class=\"pl-k\">mutable</span> x <span class=\"pl-k\">=</span> init\n    <span class=\"pl-k\">method</span> <span class=\"pl-en\">get_x</span> <span class=\"pl-k\">=</span> x\n    <span class=\"pl-k\">method</span> <span class=\"pl-en\">move</span> <span class=\"pl-v\">d</span> <span class=\"pl-k\">=</span> x <span class=\"pl-kos\">&#x3C;</span><span class=\"pl-k\">-</span> x <span class=\"pl-k\">+</span> d\n    <span class=\"pl-c\">(* Private methods can only be invoked from other methods of the same object. *)</span>\n    <span class=\"pl-k\">method</span> <span class=\"pl-k\">private </span><span class=\"pl-en\">move_one</span> <span class=\"pl-k\">=</span> self#move <span class=\"pl-c1\">1</span>\n    <span class=\"pl-c\">(* Initializer is an anonymous hidden method</span>\n<span class=\"pl-c\">    Initializers cannot be overridden.</span>\n<span class=\"pl-c\">    On the contrary, all initializers are evaluated sequentially.</span>\n<span class=\"pl-c\">    *)</span>\n    <span class=\"pl-k\">initializer</span> print_string <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>new 1d point at <span class=\"pl-pds\">\"</span></span>; print_int x; print_newline <span class=\"pl-c1\">()</span>\n  <span class=\"pl-k\">end</span>\n\n<span class=\"pl-k\">class</span> <span class=\"pl-en\">positive_1d_point</span> <span class=\"pl-v\">init</span> <span class=\"pl-k\">=</span>\n  <span class=\"pl-k\">object</span> (<span class=\"pl-en\">self</span>)\n    <span class=\"pl-k\">inherit</span> point_1d init\n    <span class=\"pl-c\">(* Private methods are inherited (they are by default visible in subclasses),</span>\n<span class=\"pl-c\">    unless they are hidden by signature matching.</span>\n<span class=\"pl-c\">    *)</span>\n    <span class=\"pl-k\">method</span> <span class=\"pl-k\">virtual </span><span class=\"pl-en\">move_one</span> <span class=\"pl-k\">:</span> _\n    <span class=\"pl-c\">(* Private methods can be made public in a subclass. *)</span>\n    <span class=\"pl-k\">method</span> <span class=\"pl-en\">is_positive</span> <span class=\"pl-k\">=</span> self#get_x <span class=\"pl-kos\">></span> <span class=\"pl-c1\">0</span>\n  <span class=\"pl-k\">end</span>\n\n<span class=\"pl-k\">let</span> strings <span class=\"pl-k\">=</span> <span class=\"pl-k\">ref</span> <span class=\"pl-c1\">[]</span>\n\n<span class=\"pl-c\">(* Immediate objects are like anonymous classes in Java. *)</span>\n<span class=\"pl-k\">let</span> immediate_object <span class=\"pl-k\">=</span>\n  <span class=\"pl-k\">object</span> (self) <span class=\"pl-c\">(* `self` could be any identifier. It is a convention to use `self`. *)</span>\n    val <span class=\"pl-k\">mutable</span> x <span class=\"pl-k\">=</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>Immediate objects are like anonymous classes in Java.<span class=\"pl-pds\">\"</span></span>\n    method get_x <span class=\"pl-k\">=</span> x\n    method set_x new_value <span class=\"pl-k\">=</span> x <span class=\"pl-kos\">&#x3C;</span><span class=\"pl-k\">-</span> new_value\n    method print <span class=\"pl-k\">=</span> print_string self#get_x\n    method register <span class=\"pl-k\">=</span> strings <span class=\"pl-kos\">:=</span> self :: <span class=\"pl-k\">!</span>strings\n    <span class=\"pl-c\">(* Putting self into an external reference is not allowed,</span>\n<span class=\"pl-c\">    as it would forbid extending the class through inheritance.</span>\n<span class=\"pl-c\">    However, since immediate objects are not extensible,</span>\n<span class=\"pl-c\">    there is no such restriction for immediate objects.</span>\n<span class=\"pl-c\">    *)</span>\n  end\n\n<span class=\"pl-c\">(* Virtual classes are like abstract classes in Java.</span>\n<span class=\"pl-c\">Virtual classes cannot be instantiated.</span>\n<span class=\"pl-c\">*)</span>\n<span class=\"pl-k\">class virtual </span><span class=\"pl-en\">abstract_number</span> <span class=\"pl-v\">init</span> <span class=\"pl-k\">=</span>\n  <span class=\"pl-k\">object</span> (<span class=\"pl-en\">self</span>)\n    val <span class=\"pl-k\">mutable</span> <span class=\"pl-k\">virtual</span> x : <span class=\"pl-k\">int</span>\n    <span class=\"pl-k\">method</span> <span class=\"pl-k\">virtual </span><span class=\"pl-en\">get_x</span> <span class=\"pl-k\">:</span> <span class=\"pl-k\">int</span>\n    <span class=\"pl-k\">method</span> <span class=\"pl-k\">virtual </span><span class=\"pl-en\">move</span> <span class=\"pl-k\">:</span> <span class=\"pl-k\">int</span> -> <span class=\"pl-k\">unit</span>\n    <span class=\"pl-k\">method</span> <span class=\"pl-en\">print</span> <span class=\"pl-k\">=</span> print_int self#get_x\n  <span class=\"pl-k\">end</span>\n\n<span class=\"pl-c\">(* Multiple Inheritance *)</span>\n<span class=\"pl-k\">class</span> <span class=\"pl-en\">painter</span> (<span class=\"pl-v\">name</span><span class=\"pl-k\">: string</span>) <span class=\"pl-k\">=</span> <span class=\"pl-k\">object</span>\n  val <span class=\"pl-k\">mutable</span> name <span class=\"pl-k\">=</span> name\n  <span class=\"pl-k\">method</span> <span class=\"pl-en\">get_name</span> <span class=\"pl-k\">=</span> name\n  <span class=\"pl-k\">method</span> <span class=\"pl-en\">draw</span> <span class=\"pl-k\">=</span> print_string <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>I am painting.<span class=\"pl-pds\">\"</span></span>\n<span class=\"pl-k\">end</span>\n\n<span class=\"pl-k\">class</span> <span class=\"pl-en\">cowboy</span> (<span class=\"pl-v\">name</span><span class=\"pl-k\">: string</span>) <span class=\"pl-k\">=</span> <span class=\"pl-k\">object</span>\n  val <span class=\"pl-k\">mutable</span> name <span class=\"pl-k\">=</span> name\n  <span class=\"pl-k\">method</span> <span class=\"pl-en\">get_name</span> <span class=\"pl-k\">=</span> name\n  <span class=\"pl-k\">method</span> <span class=\"pl-en\">draw</span> <span class=\"pl-k\">=</span> print_string <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>I am fighting.<span class=\"pl-pds\">\"</span></span>\n<span class=\"pl-k\">end</span>\n\n<span class=\"pl-k\">class</span> <span class=\"pl-en\">painter_and_cowboy</span> (<span class=\"pl-v\">init</span><span class=\"pl-k\">: string</span>) <span class=\"pl-k\">=</span> <span class=\"pl-k\">object</span>\n  <span class=\"pl-k\">inherit</span> painter (init <span class=\"pl-k\">^</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span> as a painter<span class=\"pl-pds\">\"</span></span>) <span class=\"pl-k\">as</span> painter\n  <span class=\"pl-c\">(* cowboy overrides variable name and method draw of painter.</span>\n<span class=\"pl-c\">  Thus `inherit!` is used instead of `inherit`.</span>\n<span class=\"pl-c\">  *)</span>\n  <span class=\"pl-k\">inherit!</span> cowboy (init <span class=\"pl-k\">^</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span> as a cowboy<span class=\"pl-pds\">\"</span></span>) <span class=\"pl-k\">as</span> cowboy\n  <span class=\"pl-k\">method</span> <span class=\"pl-en\">dual_draws</span> <span class=\"pl-k\">=</span>\n    painter#draw;\n    cowboy#draw\n<span class=\"pl-k\">end</span>\n\n<span class=\"pl-c\">(* Parameterized Classes *)</span>\n\n<span class=\"pl-c\">(* Classes stores its value as a reference under the hood,</span>\n<span class=\"pl-c\">thus it should be monomorphic or parametric.</span>\n<span class=\"pl-c\">The painter and cowboy classes above are monomorphic.</span>\n<span class=\"pl-c\">*)</span>\n\n<span class=\"pl-k\">class</span> ['a] <span class=\"pl-c\">(* Class type parameters are listed between [ and ]. *)</span> parametric_class\n  (init:<span class=\"pl-k\"> 'a</span>) <span class=\"pl-k\">=</span> <span class=\"pl-k\">object</span>\n    val <span class=\"pl-k\">mutable</span> x <span class=\"pl-k\">=</span> init\n    <span class=\"pl-k\">method</span> <span class=\"pl-en\">get_x</span> <span class=\"pl-k\">=</span> x\n    <span class=\"pl-k\">method</span> <span class=\"pl-en\">set_x</span> <span class=\"pl-v\">new_value</span> <span class=\"pl-k\">=</span> x <span class=\"pl-kos\">&#x3C;</span><span class=\"pl-k\">-</span> new_value\n  <span class=\"pl-k\">end</span>\n\n<span class=\"pl-c\">(* Constraints *)</span>\n<span class=\"pl-k\">class</span> <span class=\"pl-en\">[</span><span class=\"pl-k\">'a</span><span class=\"pl-en\">] circle</span> (<span class=\"pl-v\">c</span><span class=\"pl-k\">: 'a</span>) (<span class=\"pl-v\">r</span><span class=\"pl-k\">: float</span>) <span class=\"pl-k\">=</span> <span class=\"pl-k\">object</span>\n  <span class=\"pl-k\">constraint</span> <span class=\"pl-k\">'a</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">#point_1d</span>\n  val <span class=\"pl-k\">mutable</span> center <span class=\"pl-k\">=</span> c\n  <span class=\"pl-k\">method</span> <span class=\"pl-en\">move</span> <span class=\"pl-k\">=</span> center#move\n  <span class=\"pl-k\">method</span> <span class=\"pl-en\">perimeter</span> <span class=\"pl-k\">=</span> <span class=\"pl-c1\">2.0</span> <span class=\"pl-k\">*.</span> pi <span class=\"pl-k\">*.</span> r\n<span class=\"pl-k\">end</span>\n\n<span class=\"pl-c\">(* Polymorphic Methods *)</span>\n\n<span class=\"pl-k\">class</span> <span class=\"pl-en\">[</span><span class=\"pl-k\">'a</span><span class=\"pl-en\">] intlist</span> (<span class=\"pl-v\">l</span> <span class=\"pl-k\">: int list</span>) <span class=\"pl-k\">=</span>\n    <span class=\"pl-k\">object</span>\n      <span class=\"pl-k\">method</span> <span class=\"pl-en\">empty</span> <span class=\"pl-k\">=</span> (l <span class=\"pl-k\">=</span> <span class=\"pl-c1\">[]</span>)\n      <span class=\"pl-k\">method</span> <span class=\"pl-en\">fold</span> <span class=\"pl-v\">f</span> (<span class=\"pl-v\">accu</span> <span class=\"pl-k\">: 'a</span>) <span class=\"pl-k\">=</span> <span class=\"pl-c1\">List.</span>fold_left f accu l\n    <span class=\"pl-k\">end</span>\n\n<span class=\"pl-c\">(* Objects themselves are not polymorphic,</span>\n<span class=\"pl-c\">so first use of `fold` fixes its type.</span>\n<span class=\"pl-c\">*)</span>\n\n<span class=\"pl-c\">(* To make `fold` polymorphic, annotate its type explicitly: *)</span>\n<span class=\"pl-k\">class</span> <span class=\"pl-en\">intlist'</span> (<span class=\"pl-v\">l</span> <span class=\"pl-k\">: int list</span>) <span class=\"pl-k\">=</span>\n    <span class=\"pl-k\">object</span>\n      <span class=\"pl-k\">method</span> <span class=\"pl-en\">empty</span> <span class=\"pl-k\">=</span> (l <span class=\"pl-k\">=</span> <span class=\"pl-c1\">[]</span>)\n      <span class=\"pl-k\">method</span> <span class=\"pl-en\">fold</span> <span class=\"pl-k\">:</span> 'a. ('a -> <span class=\"pl-k\">int</span> -> 'a) -> 'a -> 'a <span class=\"pl-k\">=</span>\n        <span class=\"pl-k\">fun</span> <span class=\"pl-v\">f</span> <span class=\"pl-v\">accu</span> -> <span class=\"pl-c1\">List.</span>fold_left f accu l\n    end\n\n<span class=\"pl-c\">(* However, type annotation can be omitted if it is already known,</span>\n<span class=\"pl-c\">for example, through type constraints on self.*)</span>\n<span class=\"pl-k\">class type </span><span class=\"pl-en\">[</span><span class=\"pl-k\">'a</span><span class=\"pl-en\">] iterator</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">object</span>\n  <span class=\"pl-k\">method</span> <span class=\"pl-en\">fold</span> <span class=\"pl-k\">:</span> ('b -> 'a -> 'b) -> 'b -> 'b\n<span class=\"pl-k\">end</span>\n\n<span class=\"pl-k\">class</span> <span class=\"pl-en\">intlist''</span> <span class=\"pl-v\">l</span> <span class=\"pl-k\">=</span>\n    <span class=\"pl-k\">object</span> (self :<span class=\"pl-k\"> int #iterator</span>) <span class=\"pl-c\">(* implements iterator interface *)</span>\n      method empty <span class=\"pl-k\">=</span> (l <span class=\"pl-k\">=</span> <span class=\"pl-c1\">[]</span>)\n      method fold f accu <span class=\"pl-k\">=</span> <span class=\"pl-c1\">List.</span>fold_left f accu l\n    end\n\n<span class=\"pl-c\">(* Another example of interfaces. *)</span>\n\n<span class=\"pl-k\">class type </span><span class=\"pl-en\">point0</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">object</span>\n  <span class=\"pl-k\">method</span> <span class=\"pl-en\">get_x</span> <span class=\"pl-k\">:</span> <span class=\"pl-k\">int</span>\n<span class=\"pl-k\">end</span>\n\n<span class=\"pl-k\">class</span> <span class=\"pl-en\">distance_point</span> <span class=\"pl-v\">x</span> <span class=\"pl-k\">=</span>\n    <span class=\"pl-k\">object</span>\n      <span class=\"pl-k\">inherit</span> point_1d x\n      <span class=\"pl-c\">(* Unlike Java, the type of `other` cannot be `#point0` directly,</span>\n<span class=\"pl-c\">      since the HM type system OCaml uses has difficult to infer subtypes.</span>\n<span class=\"pl-c\">      Just like using parametric types to mark subtyping expilicitly,</span>\n<span class=\"pl-c\">      here `'a. (... as 'a)` is used to mark the extensible part of `#point0`.</span>\n<span class=\"pl-c\">      *)</span>\n      <span class=\"pl-k\">method</span> <span class=\"pl-en\">distance</span> <span class=\"pl-k\">:</span> 'a. (<span class=\"pl-k\">#point0</span> <span class=\"pl-k\">as</span> 'a) -> <span class=\"pl-k\">int</span> <span class=\"pl-k\">=</span>\n        <span class=\"pl-k\">fun</span> <span class=\"pl-v\">other</span> -> abs (other#get_x <span class=\"pl-k\">-</span> x)\n    end\n\n<span class=\"pl-c\">(* Credit: this section uses code examples from OCaml manual. *)</span>\n\n<span class=\"pl-c\">(* In Ocaml, inheritance does not imply subtyping.</span>\n<span class=\"pl-c\">Coercions are required for inherited types,</span>\n<span class=\"pl-c\">as for uninherited types.</span>\n<span class=\"pl-c\">*)</span>\n\n\n<span class=\"pl-c\">(* Labeled Arguments *)</span>\n\n<span class=\"pl-k\">let</span> <span class=\"pl-en\">named_arguments</span> <span class=\"pl-v\">~</span><span class=\"pl-ent\">x</span> <span class=\"pl-v\">~</span><span class=\"pl-ent\">y</span> <span class=\"pl-k\">=</span> x <span class=\"pl-k\">+</span> y\n\n<span class=\"pl-c\">(* Functions with labeled arguments are nominal, not structral.</span>\n<span class=\"pl-c\">Thus `2 |> (fun ~x -> x)` does not work.</span>\n<span class=\"pl-c\">Same applies to functions with optional arugments (see below),</span>\n<span class=\"pl-c\">except that OCaml can auto transform them</span>\n<span class=\"pl-c\">by passing `None` for all optional arguments.</span>\n<span class=\"pl-c\">*)</span>\n\n<span class=\"pl-c\">(* Optional Arguments *)</span>\n\n<span class=\"pl-k\">let</span> <span class=\"pl-en\">inc_multiple_times</span> <span class=\"pl-v\">?(</span><span class=\"pl-ent\">times</span><span class=\"pl-v\">=</span><span class=\"pl-c1\">1</span><span class=\"pl-v\">)</span> <span class=\"pl-v\">x</span> <span class=\"pl-k\">=</span> x <span class=\"pl-k\">+</span> <span class=\"pl-c1\">1</span> <span class=\"pl-k\">*</span> times\n\n<span class=\"pl-c\">(* To avoid ambigulity with partital application,</span>\n<span class=\"pl-c\">optional arguments must be followed by at least one non optional argument.</span>\n<span class=\"pl-c\">*)</span>\n\n<span class=\"pl-k\">let</span> <span class=\"pl-en\">dummy_argument</span> <span class=\"pl-v\">?(</span><span class=\"pl-ent\">x</span><span class=\"pl-v\">=</span><span class=\"pl-c1\">1</span><span class=\"pl-v\">)</span> <span class=\"pl-v\">()</span> <span class=\"pl-k\">=</span> x\n\n\n<span class=\"pl-k\">let</span> <span class=\"pl-c1\">()</span> <span class=\"pl-k\">=</span> <span class=\"pl-c\">(* To ensure the body is side-effect only, i.e. returning unit. *)</span>\n  <span class=\"pl-k\">let</span> a_point <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> point_1d <span class=\"pl-c1\">42</span> <span class=\"pl-k\">in</span>\n  print_int a_point#get_x; print_newline <span class=\"pl-c1\">()</span>;\n  a_point#move <span class=\"pl-c1\">1</span>;\n\n  <span class=\"pl-k\">let</span> john <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> painter_and_cowboy <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>john<span class=\"pl-pds\">\"</span></span> <span class=\"pl-k\">in</span>\n  print_string john#get_name <span class=\"pl-c\">(* cowboy *)</span>; print_newline <span class=\"pl-c1\">()</span>;\n  john#draw <span class=\"pl-c\">(* cowboy *)</span>; print_newline <span class=\"pl-c1\">()</span>;\n  john#dual_draws; print_newline <span class=\"pl-c1\">()</span>;\n\n  <span class=\"pl-c\">(* Labeled arguments must always be applied with its name. *)</span>\n  <span class=\"pl-k\">let</span> four <span class=\"pl-k\">=</span> named_argumests <span class=\"pl-ent\">~y:</span><span class=\"pl-c1\">2</span> <span class=\"pl-ent\">~x:</span><span class=\"pl-c1\">2</span>\n\n  <span class=\"pl-c\">(* Optional arguments must be either omitted or applied with its name. *)</span>\n  <span class=\"pl-k\">let</span> two <span class=\"pl-k\">=</span> inc_multiple_times <span class=\"pl-c1\">1</span>;\n  <span class=\"pl-k\">let</span> five <span class=\"pl-k\">=</span> inc_multiple_times <span class=\"pl-ent\">~times:</span><span class=\"pl-c1\">5</span> <span class=\"pl-c1\">1</span>;\n  <span class=\"pl-k\">let</span> one <span class=\"pl-k\">=</span> dummy_argument <span class=\"pl-c1\">()</span>;\n  <span class=\"pl-k\">let</span> three <span class=\"pl-k\">=</span> dummy_argument <span class=\"pl-ent\">~x:</span><span class=\"pl-c1\">3</span> <span class=\"pl-c1\">()</span>;\n\n  exit <span class=\"pl-c1\">0</span>\n</code></pre>","date_published":"Sat, 18 Aug 2018 13:22:33 GMT","date_modified":"Sun, 24 May 2020 13:58:17 GMT"},{"id":"https://mmap.page/dive-into/haskell/","url":"https://mmap.page/dive-into/haskell/","title":"Haskell: Laziness, Type Class, and Monad","content_html":"<h1>Haskell: Laziness, Type Class, and Monad</h1>\n<h2>Laziness</h2>\n<blockquote>\n<p>A function is <strong>strict</strong> in an argument\nif the result is undefined\nwhenever an undefined value is passed to this argument.\nFor instance, <code>(+)</code> is strict in both arguments,\nwhile (&#x26;&#x26;) is strict in its first only.\nRecall that it is defined by</p>\n<pre><code>True &#x26;&#x26; x = x\nFalse &#x26;&#x26; x = False\n</code></pre>\n<p>...</p>\n<p>If a function is not strict in an argument,\nwe say that it is <strong>non-strict</strong> or <strong>lazy</strong> in that argument.</p>\n</blockquote>\n<p>-- Haskell: The Craft of Function Programming (3e):517</p>\n<h3>Infinite List</h3>\n<pre><code class=\"language-haskell\"><span class=\"pl-en\">fibs</span> <span class=\"pl-k\">::</span>[<span class=\"pl-c1\">Integer</span>]\nfibs <span class=\"pl-k\">=</span> <span class=\"pl-c1\">0</span> <span class=\"pl-k\">:</span> <span class=\"pl-c1\">1</span> <span class=\"pl-k\">:</span> <span class=\"pl-c1\">zipWith</span> <span class=\"pl-en\">(+)</span> fibs (<span class=\"pl-c1\">tail</span> fibs)\n<span class=\"pl-c1\">take</span> <span class=\"pl-c1\">3</span> fibs\n</code></pre>\n<h3>Mutual Recursion</h3>\n<p>Unlike OCaml, mutual recursion in Haskell does not need to use <code>let rec</code> (because of laziness).</p>\n<pre><code class=\"language-haskell\"><span class=\"pl-en\">isEven</span> <span class=\"pl-k\">::</span> <span class=\"pl-c1\">Int</span> <span class=\"pl-k\">-></span> <span class=\"pl-c1\">Bool</span>\nisEven <span class=\"pl-c1\">0</span> <span class=\"pl-k\">=</span> <span class=\"pl-c1\">True</span>\nisEven n <span class=\"pl-k\">=</span> isOdd (n <span class=\"pl-k\">-</span> <span class=\"pl-c1\">1</span>)\n\n<span class=\"pl-en\">isOdd</span> <span class=\"pl-k\">::</span> <span class=\"pl-c1\">Int</span> <span class=\"pl-k\">-></span> <span class=\"pl-c1\">Bool</span>\nisOdd <span class=\"pl-c1\">0</span> <span class=\"pl-k\">=</span> <span class=\"pl-c1\">False</span>\nisOdd n <span class=\"pl-k\">=</span> isEven (n <span class=\"pl-k\">-</span> <span class=\"pl-c1\">1</span>)\n</code></pre>\n<h2>Type Class</h2>\n<pre><code class=\"language-haskell\"><span class=\"pl-en\">quickSort</span> <span class=\"pl-k\">::</span> <span class=\"pl-e\">Ord</span> <span class=\"pl-smi\">a</span> <span class=\"pl-k\">=></span> [<span class=\"pl-smi\">a</span>] <span class=\"pl-k\">-></span> [<span class=\"pl-smi\">a</span>]\n\nquickSort <span class=\"pl-c1\">[]</span>     <span class=\"pl-k\">=</span> <span class=\"pl-c1\">[]</span>\nquickSort (x<span class=\"pl-k\">:</span>xs) <span class=\"pl-k\">=</span> quickSort [<span class=\"pl-ent\">e</span>|e&#x3C;-xs,e&#x3C;=x] ++ [x] ++ quickSort [e|e&#x3C;-xs, e>x]\n</code></pre>\n<p><code>Ord</code> is a type class (interface),\nand <code>[e|e&#x3C;-xs,e&#x3C;=x]</code> is list comprehension.</p>\n<p>Function signatures defined in type class are similar to overloading in other languages.</p>\n<pre><code class=\"language-haskell\"><span class=\"pl-k\">class</span> <span class=\"pl-e\">Eq</span> <span class=\"pl-smi\">a</span> <span class=\"pl-k\">where</span>\n  <span class=\"pl-en\">(==)</span> <span class=\"pl-k\">::</span> <span class=\"pl-smi\">a</span> <span class=\"pl-k\">-></span> <span class=\"pl-smi\">a</span> <span class=\"pl-k\">-></span> <span class=\"pl-c1\">Bool</span>\n</code></pre>\n<p><code>instance</code> of type class is similar to classes implemented interface in other languages.</p>\n<pre><code class=\"language-haskell\"><span class=\"pl-k\">instance</span> <span class=\"pl-e\">Monad</span> <span class=\"pl-c1\">Maybe</span> <span class=\"pl-k\">where</span>\n    <span class=\"pl-c1\">return</span> x <span class=\"pl-k\">=</span> <span class=\"pl-ent\">Just</span> x\n    <span class=\"pl-ent\">Nothing</span> <span class=\"pl-k\">>>=</span> f <span class=\"pl-k\">=</span> <span class=\"pl-ent\">Nothing</span>\n    <span class=\"pl-ent\">Just</span> x <span class=\"pl-k\">>>=</span> f  <span class=\"pl-k\">=</span> f x\n    <span class=\"pl-c1\">fail</span> _ <span class=\"pl-k\">=</span> <span class=\"pl-ent\">Nothing</span>\n</code></pre>\n<p>But what is Monad? Read on.</p>\n<h2>Monad</h2>\n<p>Monad is like a box.\nIt keeps tracking of some extra content and makes code cleaner (but not necessary clearer).</p>\n<h3>Maybe Monad</h3>\n<p>The Maybe monad chains (<code>>>=</code>) sequences of operations and hides failure handling (extra context) in a monad.</p>\n<p>Let's revisit the definition of Maybe from this perspective:\n(<code>--</code> starts a comment in Haskell)</p>\n<pre><code class=\"language-haskell\"><span class=\"pl-k\">instance</span> <span class=\"pl-e\">Monad</span> <span class=\"pl-c1\">Maybe</span> <span class=\"pl-k\">where</span>\n    <span class=\"pl-c\">-- `return` is a function to wrap x as `Just x`.</span>\n    <span class=\"pl-c1\">return</span> x <span class=\"pl-k\">=</span> <span class=\"pl-ent\">Just</span> x\n    <span class=\"pl-c\">-- As soon as one fails, the rest are ignored and the final result is `Nothing`.</span>\n    <span class=\"pl-ent\">Nothing</span> <span class=\"pl-k\">>>=</span> f <span class=\"pl-k\">=</span> <span class=\"pl-ent\">Nothing</span>\n    <span class=\"pl-c\">-- Only apply `f` when x is `Just x`， not `Nothing`.</span>\n    <span class=\"pl-ent\">Just</span> x <span class=\"pl-k\">>>=</span> f  <span class=\"pl-k\">=</span> f x\n    <span class=\"pl-c\">-- Throw a failure.</span>\n    <span class=\"pl-c1\">fail</span> _ <span class=\"pl-k\">=</span> <span class=\"pl-ent\">Nothing</span>\n</code></pre>\n<h3>Monadic Classes</h3>\n<p>The type class of Monad is defined as below:</p>\n<pre><code class=\"language-haskell\"><span class=\"pl-k\">class</span> <span class=\"pl-e\">Monad</span> <span class=\"pl-smi\">m</span> <span class=\"pl-k\">where</span>\n    <span class=\"pl-c\">-- core functions of Monad</span>\n    <span class=\"pl-en\">(>>=)</span>  <span class=\"pl-k\">::</span> <span class=\"pl-smi\">m</span> <span class=\"pl-smi\">a</span> <span class=\"pl-k\">-></span> (<span class=\"pl-smi\">a</span> <span class=\"pl-k\">-></span> <span class=\"pl-smi\">m</span> <span class=\"pl-smi\">b</span>) <span class=\"pl-k\">-></span> <span class=\"pl-smi\">m</span> <span class=\"pl-smi\">b</span>\n    <span class=\"pl-en\">return</span> <span class=\"pl-k\">::</span> <span class=\"pl-smi\">a</span> <span class=\"pl-k\">-></span> <span class=\"pl-smi\">m</span> <span class=\"pl-smi\">a</span>\n\n    <span class=\"pl-c\">-- other functions</span>\n    <span class=\"pl-en\">(>>)</span>   <span class=\"pl-k\">::</span> <span class=\"pl-smi\">m</span> <span class=\"pl-smi\">a</span> <span class=\"pl-k\">-></span> <span class=\"pl-smi\">m</span> <span class=\"pl-smi\">b</span> <span class=\"pl-k\">-></span> <span class=\"pl-smi\">m</span> <span class=\"pl-smi\">b</span>\n    m <span class=\"pl-k\">>></span> k <span class=\"pl-k\">=</span> m <span class=\"pl-k\">>>=</span> <span class=\"pl-k\">\\</span>_ <span class=\"pl-k\">-></span> k <span class=\"pl-c\">-- `\\_ -> k` is a lambda</span>\n\n    <span class=\"pl-en\">fail</span>   <span class=\"pl-k\">::</span> <span class=\"pl-c1\">String</span> <span class=\"pl-k\">-></span> <span class=\"pl-smi\">m</span> <span class=\"pl-smi\">a</span>\n    <span class=\"pl-c1\">fail</span> s <span class=\"pl-k\">=</span> <span class=\"pl-c1\">error</span> s\n</code></pre>\n<p><code>fail</code> is like <code>throw</code> in other languages.\nHaskell uses it to in pattern matching to enable failure.\nWe do not write them explicitly in code.</p>\n<p><code>>></code> is a syntax sugar to throw away the result of <code>m a</code>.\nThus <code>putStr \"foo\" >== \\_ -> putStr \"bar\"</code> can be expressed as\n<code>putStr \"foo\" >> putStr \"bar\"</code>.</p>\n<p><code>>>=</code> chains tow computations,\npassing the result of the first computation to the second computation,\nby wrapping the second computation in a function,\nand passing the first result as its parameter.</p>\n<p>Unlike other languages, in Haskell, <code>return</code> wraps date in a monad.</p>\n<p>Let's revisit the definition of Maybe monad under the perspective of monadic class.</p>\n<pre><code class=\"language-haskell\"><span class=\"pl-k\">instance</span> <span class=\"pl-e\">Monad</span> <span class=\"pl-c1\">Maybe</span> <span class=\"pl-k\">where</span>\n    <span class=\"pl-en\">return</span> <span class=\"pl-k\">::</span> <span class=\"pl-smi\">a</span> <span class=\"pl-k\">-></span> <span class=\"pl-c1\">Maybe</span> <span class=\"pl-smi\">a</span>\n    <span class=\"pl-c1\">return</span> x <span class=\"pl-k\">=</span> <span class=\"pl-ent\">Just</span> x\n    <span class=\"pl-k\">>>=</span> <span class=\"pl-k\">::</span> <span class=\"pl-c1\">Maybe</span> <span class=\"pl-smi\">a</span> <span class=\"pl-k\">-></span> (<span class=\"pl-smi\">a</span> <span class=\"pl-k\">-></span> <span class=\"pl-c1\">Maybe</span> <span class=\"pl-smi\">b</span>) <span class=\"pl-k\">-></span> <span class=\"pl-c1\">Maybe</span> <span class=\"pl-smi\">b</span>\n    <span class=\"pl-ent\">Nothing</span> <span class=\"pl-k\">>>=</span> f <span class=\"pl-k\">=</span> <span class=\"pl-ent\">Nothing</span>\n    <span class=\"pl-ent\">Just</span> x <span class=\"pl-k\">>>=</span> f  <span class=\"pl-k\">=</span> f x\n    <span class=\"pl-en\">fail</span> <span class=\"pl-k\">::</span> <span class=\"pl-c1\">String</span> <span class=\"pl-k\">-></span> <span class=\"pl-c1\">Maybe</span> <span class=\"pl-smi\">a</span>\n    <span class=\"pl-c1\">fail</span> _ <span class=\"pl-k\">=</span> <span class=\"pl-ent\">Nothing</span>\n</code></pre>\n<h3>Do Notation</h3>\n<pre><code class=\"language-haskell\"><span class=\"pl-en\">helloWorld</span> <span class=\"pl-k\">::</span> <span class=\"pl-c1\">IO</span> <span class=\"pl-c1\">()</span>\nhelloWorld <span class=\"pl-k\">=</span>\n    <span class=\"pl-k\">do</span>\n        <span class=\"pl-c1\">putStr</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>Hello<span class=\"pl-pds\">\"</span></span>\n        <span class=\"pl-c1\">putStr</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span> <span class=\"pl-pds\">\"</span></span>\n        <span class=\"pl-c1\">putStrLn</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>world!<span class=\"pl-pds\">\"</span></span>\n</code></pre>\n<p>Haskell syntax is layout sensitive,\nin other words, it conforms to offside rule.\nAlthough Haskell does support braces and semicolons,\nthis alternative style is rare in the Haskell community.</p>\n<pre><code class=\"language-haskell\"><span class=\"pl-k\">do</span> { <span class=\"pl-c1\">putStr</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>Hello<span class=\"pl-pds\">\"</span></span>; <span class=\"pl-c1\">putStr</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span> <span class=\"pl-pds\">\"</span></span>; <span class=\"pl-c1\">putStrLn</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>world!<span class=\"pl-pds\">\"</span></span>; }\n</code></pre>\n<p>Within a do notation, <code>&#x3C;-</code> binds the result to a name.</p>\n<pre><code class=\"language-haskell\"><span class=\"pl-en\">echo</span> <span class=\"pl-k\">::</span> <span class=\"pl-c1\">IO</span> <span class=\"pl-c1\">()</span>\necho <span class=\"pl-k\">=</span>\n    <span class=\"pl-k\">do</span>\n        line <span class=\"pl-k\">&#x3C;-</span> <span class=\"pl-c1\">getLine</span>\n        <span class=\"pl-c1\">putStrLn</span> line\n</code></pre>\n<p>In fact, do notation is an alternative syntax for monad:</p>\n<pre><code class=\"language-haskell\"><span class=\"pl-c1\">putStr</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>Hello<span class=\"pl-pds\">\"</span></span> <span class=\"pl-k\">>></span> <span class=\"pl-c1\">putStr</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span> <span class=\"pl-pds\">\"</span></span> <span class=\"pl-k\">>></span> <span class=\"pl-c1\">putStrLn</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>world!<span class=\"pl-pds\">\"</span></span>\n\n<span class=\"pl-en\">echo</span> <span class=\"pl-k\">::</span> <span class=\"pl-c1\">IO</span> <span class=\"pl-c1\">()</span>\necho <span class=\"pl-k\">=</span> <span class=\"pl-c1\">getLine</span> <span class=\"pl-k\">>>=</span> <span class=\"pl-c1\">putStrLn</span>\n</code></pre>","date_published":"Sat, 18 Aug 2018 12:01:19 GMT","date_modified":"Thu, 26 Dec 2019 15:16:30 GMT"},{"id":"https://mmap.page/dapi/learn-programming/","url":"https://mmap.page/dapi/learn-programming/","title":"编程入门路线","content_html":"<h1>编程入门路线</h1>\n<h2>路线一</h2>\n<p>首先，学好英语。高中毕业程度就可以。\n高中英语，语法什么的基本全了， 3500 的词汇量，打个折扣，3000 也绰绰有余了。\n学到这个程度就可以，以后大量阅读英文资料，计算机方面的词汇会自然而然积累，不用特意提前去背。</p>\n<p>其实初中程度的英语，1500 的词汇量，也勉强够了。\n初中英语的问题是有些语法没接触到，也就是说可能会碰到一些陌生的结构。\n好在很多情况下，即使不理解结构，从上下文也能推断出意思。\n而同类的结构见得多了，可能慢慢就理解了。\n中文的语法，通常是本科阶段才正式介绍，可是在此之前并不影响大家使用中文。\n非母语虽然困难很多，但一样可以。\n初中时候查双解字典，字典的解释大量使用定语从句，当时完全不知道定语从句这回事，\n但是渐渐地也能明白这个结构的作用。</p>\n<p>俗话说，磨刀不误砍柴功。但是也不必太刻意地追求磨刀磨得恰当好处。\n磨过头了，英语学多了，可以去翻译。\n高中程度的英语只是阅读，翻译远远不够，强行翻译容易给别人挖坑，当然自己作为练习是可以的。\n感觉自己学习编程的热情要在磨刀中消磨殆尽了，那也可以先放一放，直接去学。以后有必要再补也是一样的。\n答案不如问题重要，路线不如动力和兴趣重要。</p>\n<p>接着，看一本入门的书。</p>\n<p>选哪一本呢？这个阶段对编程基本是一无所知，所以如何评判书的好坏呢？</p>\n<p>其实还是有办法的。</p>\n<p>就是看书的厚薄。</p>\n<p>这个肤浅的判断方法出奇地好用。\n它背后的依据是，如果一本入门书不够薄：</p>\n<ol>\n<li>要么，这本书介绍了太多细节了，入门书应该介绍这一领域的精华，而不是让初学者迷失在细节；</li>\n<li>要么，这本书将一些过深的内容放到入门书里了；</li>\n<li>要么，这本书把读者当作弱智，不相信读者的能力，很多书每一步都给你截图，书看上去很厚，其实言之无物；</li>\n<li>要么，作者随便东拼西凑搞了一本书出来，自己都不知道自己在干什么。</li>\n</ol>\n<p>我推荐 The Little Schemer.\n如果这本书不好找，或者觉得这书不合口味，那挑一本别的入门书也是一样。记得选薄的就可以。</p>\n<h2>路线二</h2>\n<p>不学英语，直接看 The Little Schemer 的中译本。</p>\n<p>注意，中译本我并没有看过，不知道翻译的质量怎么样。</p>\n<p>或者也可以看裘宗燕翻译的 SICP (《计算机程序的构造和解释》)。\n这书并不薄。不过入门的话，只用看前 3 章就可以，这样算下来还是比较薄的。\n和 The Little Schemer 不同，SICP 的习题很多，\n如果感觉吃力，可以选做或者干脆不做，习题本来就是给学有余力的人准备的，别让习题挫伤自己的信心。</p>\n<h2>路线三</h2>\n<p>自己制定路线。</p>\n<p>自己往往比别人更了解自己，自己制定的路线，对自己而言，说不定比别人推荐的路线更合适。\n不要惧怕探索，只要保持动力和兴趣，总能走通的，大不了走点弯路罢了。\n即使因为走了弯路进展慢一点，但自己能闯出一条独特的路，会给自己信心。\n在黑暗中独立摸索的经验，也会给你一些感觉。</p>\n<p>很少人有这个幸运或者不幸能永远沿着别人的路走。\n总有一天会碰到没人探过路的情况，这时候当初的信心和感觉会成为你的助力。</p>","date_published":"Sat, 11 Aug 2018 07:56:16 GMT","date_modified":"Sat, 23 Nov 2019 19:11:50 GMT"},{"id":"https://mmap.page/dive-into/jupyter-lab/","url":"https://mmap.page/dive-into/jupyter-lab/","title":"JupyterLab Guide","content_html":"<h1>JupyterLab Guide</h1>\n<p><strong>This guide is outdated and unmaintained.</strong></p>\n<p>JupyterLab is the next generation UI of Jupyter Notebook (formly known as IPython Notebook).</p>\n<h2>Installation</h2>\n<p>JupyterLab can be installed via <code>conda</code>, <code>pip</code>, and <code>pipenv</code>.</p>\n<p>For example, to install with <code>conda</code>:</p>\n<pre><code class=\"language-sh\">conda install -c conda-forge jupyterlab\n</code></pre>\n<p>Once installed, you can start it with:</p>\n<pre><code class=\"language-sh\">jupyter lab\n</code></pre>\n<p>To shut down JupyterLab,\nfirst shut down all kernels via <code>Kernel</code> menu,\nthen type <code>ctrl-c</code>.</p>\n<h2>Notebooks</h2>\n<p>Jupyter notebooks combines:</p>\n<ol>\n<li>live runnable code cells</li>\n<li>text cells (Markdown, LaTeX equations, images, interactive visualizations)</li>\n</ol>\n<p>Multiple view(tabs) can be opened for the same notebook,\nwith synced content.</p>\n<p>The blue collapse button on left of each cell can trigger collapsing and expanding cells.</p>\n<p>Right-click on a notebook and select \"New Console for Notebook\" can attach to the notebook kernel.\nThis provides a log of all computations done in the kernel (in the order in the order in which they were done),\nand a place to interactively inspect kernel state without changing the notebook.</p>\n<h3>Raw HTML</h3>\n<p>IPython kernel provides a variety of convenience classes for displaying rich output, including HTML:</p>\n<pre><code class=\"language-python\"><span class=\"pl-k\">from</span> IPython.display <span class=\"pl-k\">import</span> display, <span class=\"pl-c1\">HTML</span>\ndisplay(HTML(<span class=\"pl-s\"><span class=\"pl-pds\">'</span>&#x3C;del>Hello World&#x3C;/del><span class=\"pl-pds\">'</span></span>))\n</code></pre>\n<p>or</p>\n<pre><code class=\"language-python\"><span class=\"pl-k\">from</span> IPython.display <span class=\"pl-k\">import</span> display\ndisplay({<span class=\"pl-s\"><span class=\"pl-pds\">'</span>text/html<span class=\"pl-pds\">'</span></span>: <span class=\"pl-s\"><span class=\"pl-pds\">'</span>&#x3C;del>Hello World&#x3C;/del><span class=\"pl-pds\">'</span></span>}, <span class=\"pl-v\">raw</span><span class=\"pl-k\">=</span><span class=\"pl-c1\">True</span>)\n</code></pre>\n<p>MIME types supported by default:</p>\n<ul>\n<li>document: <code>text/markdown</code>, <code>text/html</code>, <code>text/latex</code>, <code>application/vdom.v1+json</code> (Virtual DOM)</li>\n<li>images: <code>image/bmp</code>, <code>image/gif</code>, <code>image/jpeg</code>, <code>image/png</code>, <code>image/svg+xml</code></li>\n<li>data: <code>application/json</code>, <code>application/vnd.vega.v2+json</code>, <code>application/vnd.vegalite.v1+json</code></li>\n<li>other: CSV (as <code>.csv</code> files, no MIME type), PDF (as <code>.pdf</code> files, with <code>application/pdf</code> MIME type, view only)</li>\n</ul>\n<p>Other Jupyter kernels offer similar APIs.</p>\n<h2>Keymap</h2>\n<p>Keyboard shortcuts can be viewed in menu, context menu, and command palette (Commands tab of sidebar).</p>\n<p>Keyboard shortcut for command palette: <code>Ctrl+Shift+c</code></p>\n<h3>Code Cell/Console</h3>\n<ul>\n<li><code>Tab</code>: complete.</li>\n<li><code>Shift+Tab</code>: tooltip.</li>\n<li><code>Shift+Enter</code>: run code.</li>\n</ul>\n<h3>Image File Viewer</h3>\n<ul>\n<li><code>+</code> and <code>-</code>: zoom</li>\n<li><code>[</code> and <code>]</code>: rotate</li>\n<li><code>H</code> and <code>V</code>: flip horizontally/vertically</li>\n<li><code>I</code>: invert the colors</li>\n<li><code>0</code>: reset</li>\n</ul>\n<h3>Mouse</h3>\n<p>Besides keyboard, mouse is also useful.\nDrag and drop cells within one notebook to rearrange them;\ndrag and drop cells within notebooks to copy content;\ndrag and drop tabs to arrange their layout.</p>\n<h2>Extensions</h2>\n<p>JupyterLab extensions are npm packages.</p>\n<p>To install extensions, first install nodejs.\nFor example, via <code>conda</code>:</p>\n<pre><code class=\"language-sh\">conda install -c conda-forge nodejs\n</code></pre>\n<p>Then use <code>jupyter labextension</code> to manage extensions,\nvia invoking subcommands like <code>list</code>, <code>install</code>/<code>uninstall</code>, <code>enable</code>/<code>unable</code>.</p>\n<h2>Tools and Services</h2>\n<h3>nbdime</h3>\n<p><a href=\"https://github.com/jupyter/nbdime\">nbdime</a> provides tools for diffing and merging of <a href=\"https://jupyter-notebook.readthedocs.io/\">Jupyter Notebooks</a>.</p>\n<ul>\n<li><code>nbdiff</code> compare notebooks in a terminal-friendly way</li>\n<li><code>nbmerge</code> three-way merge of notebooks with automatic conflict resolution</li>\n<li><code>nbdiff-web</code> shows you a rich rendered diff of notebooks</li>\n<li><code>nbmerge-web</code> gives you a web-based three-way merge tool for notebooks</li>\n<li><code>nbshow</code> present a single notebook in a terminal-friendly way</li>\n</ul>\n<h3>nbconvert</h3>\n<p><a href=\"https://nbconvert.readthedocs.io/\">nbconvert</a> allows you to convert a Jupyter .ipynb notebook document file into another static format including HTML, LaTeX, PDF, Markdown, reStructuredText, and more.</p>\n<p><a href=\"https://nbviewer.jupyter.org/\">nbviewer</a> is a free web service based on <code>nbconvert</code> to share static html versions of notebook files.</p>\n<h3>Binder</h3>\n<p><a href=\"https://mybinder.org/\">Binder</a> is a free web service to turn a GitHub repo into a collection of interactive notebooks:</p>\n<ol>\n<li>Enter an URL to a GitHub repo of Jupyter notebooks.</li>\n<li>Binder builds a Docker image for the repository, based on <code>requirements.txt</code> or <code>environment.yml</code> in repository's root directory.</li>\n<li>Binder launches a JupyterHub server. It provides a reusable/shareable link to live repository.</li>\n</ol>","date_published":"Sat, 11 Aug 2018 06:43:25 GMT","date_modified":"Mon, 05 Sep 2022 14:05:34 GMT"},{"id":"https://mmap.page/web/html-history/","url":"https://mmap.page/web/html-history/","title":"History of HTML through Linux/BSD Websites","content_html":"<h1>History of HTML through Linux/BSD Websites</h1>\n<p>This is a breif overview of HTML versions examplified with some Linux/BSD websites.</p>\n<p>All the screen shots are captured on 2018-02-20.</p>\n<h2>Slackware</h2>\n<p><picture><source srcset=\"/web/slackware.avif\" type=\"image/avif\"><img src=\"https://mmap.page/web/slackware.png\" alt=\"slackware\" width=\"656\" height=\"363\"></picture></p>\n<p>Slackware still uses tarballs for packaging,\nand its website is also old-fashioned,\nwith html tags capitalized,\nusing tables for layout.</p>\n<pre><code class=\"language-html\">&#x3C;<span class=\"pl-ent\">HTML</span>>\n&#x3C;<span class=\"pl-ent\">TITLE</span>>\nThe Slackware Linux Project&#x3C;/<span class=\"pl-ent\">TITLE</span>>\n&#x3C;<span class=\"pl-ent\">BODY</span> <span class=\"pl-e\">BACKGROUND</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>/grfx/shared/background.jpg<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">BGCOLOR</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>#fefefe<span class=\"pl-pds\">\"</span></span>\n\t\t         <span class=\"pl-e\">TEXT</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>#000000<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">LINK</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>#000000<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">VLINK</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>#000000<span class=\"pl-pds\">\"</span></span>\n\t\t         <span class=\"pl-e\">ALINK</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>#000000<span class=\"pl-pds\">\"</span></span>>\n&#x3C;<span class=\"pl-ent\">CENTER</span>>\n\n&#x3C;<span class=\"pl-ent\">TABLE</span> <span class=\"pl-e\">BORDER</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>0<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">WIDTH</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>85%<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">CELLSPACING</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>0<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">CELLPADDING</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>0<span class=\"pl-pds\">\"</span></span>>\n&#x3C;<span class=\"pl-ent\">TR</span>>\n\t&#x3C;<span class=\"pl-ent\">TD</span> <span class=\"pl-e\">COLSPAN</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>3<span class=\"pl-pds\">\"</span></span>>\n\t\t&#x3C;<span class=\"pl-ent\">TABLE</span> <span class=\"pl-e\">WIDTH</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>95%<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">CELLSPACING</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>0<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">CELLPADDING</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>0<span class=\"pl-pds\">\"</span></span>>\n\t\t&#x3C;<span class=\"pl-ent\">TR</span>>\n\t\t\t&#x3C;<span class=\"pl-ent\">TD</span> <span class=\"pl-e\">ALIGN</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>center<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">VALIGN</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>bottom<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">WIDTH</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>55%<span class=\"pl-pds\">\"</span></span>>\n\t\t\t\t&#x3C;<span class=\"pl-ent\">TABLE</span> <span class=\"pl-e\">WIDTH</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>80%<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">CELLPADDING</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>0<span class=\"pl-pds\">\"</span></span>>&#x3C;<span class=\"pl-ent\">TR</span>>&#x3C;<span class=\"pl-ent\">TD</span> <span class=\"pl-e\">BGCOLOR</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>#000000<span class=\"pl-pds\">\"</span></span>>\n\n\t      &#x3C;<span class=\"pl-ent\">TABLE</span> <span class=\"pl-e\">WIDTH</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>100%<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">CELLPADDING</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>6<span class=\"pl-pds\">\"</span></span>>\n\t      &#x3C;<span class=\"pl-ent\">TR</span>>&#x3C;<span class=\"pl-ent\">TD</span> <span class=\"pl-e\">BGCOLOR</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>#fefefe<span class=\"pl-pds\">\"</span></span>>\n\t\t\t\t&#x3C;<span class=\"pl-ent\">CENTER</span>>&#x3C;<span class=\"pl-ent\">B</span>>\n\t\t\t\tThe Slackware Linux Project\t\t\t\t&#x3C;/<span class=\"pl-ent\">B</span>>&#x3C;/<span class=\"pl-ent\">CENTER</span>>\n\t\t\t\t&#x3C;/<span class=\"pl-ent\">TD</span>>&#x3C;/<span class=\"pl-ent\">TR</span>>&#x3C;/<span class=\"pl-ent\">TABLE</span>>\n&#x3C;/<span class=\"pl-ent\">TD</span>>&#x3C;/<span class=\"pl-ent\">TR</span>>&#x3C;/<span class=\"pl-ent\">TABLE</span>>\t\t\t&#x3C;/<span class=\"pl-ent\">TD</span>>\n\t\t\t&#x3C;<span class=\"pl-ent\">TD</span> <span class=\"pl-e\">VALIGN</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>bottom<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">ALIGN</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>right<span class=\"pl-pds\">\"</span></span>>\n\t\t\t\t&#x3C;<span class=\"pl-ent\">TABLE</span> <span class=\"pl-e\">CELLPADDING</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>0<span class=\"pl-pds\">\"</span></span>>&#x3C;<span class=\"pl-ent\">TR</span>>&#x3C;<span class=\"pl-ent\">TD</span> <span class=\"pl-e\">BGCOLOR</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>##000000<span class=\"pl-pds\">\"</span></span>>\n\t\t\t\t&#x3C;<span class=\"pl-ent\">TABLE</span> <span class=\"pl-e\">CELLPADDING</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>0<span class=\"pl-pds\">\"</span></span>>&#x3C;<span class=\"pl-ent\">TR</span>>&#x3C;<span class=\"pl-ent\">TD</span> <span class=\"pl-e\">BGCOLOR</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>#ffffff<span class=\"pl-pds\">\"</span></span>>\n\t\t\t\t&#x3C;<span class=\"pl-ent\">A</span> <span class=\"pl-e\">HREF</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>/index.html<span class=\"pl-pds\">\"</span></span>>&#x3C;<span class=\"pl-ent\">IMG</span> <span class=\"pl-e\">SRC</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>/grfx/shared/slackware_traditional_website_logo.png<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">ALT</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>Slackware Logo<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">BORDER</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>0<span class=\"pl-pds\">\"</span></span>>&#x3C;/<span class=\"pl-ent\">A</span>>\t\t\t\t&#x3C;/<span class=\"pl-ent\">TD</span>>&#x3C;/<span class=\"pl-ent\">TR</span>>&#x3C;/<span class=\"pl-ent\">TABLE</span>>\n\t\t\t\t&#x3C;/<span class=\"pl-ent\">TD</span>>&#x3C;/<span class=\"pl-ent\">TR</span>>&#x3C;/<span class=\"pl-ent\">TABLE</span>>\n\t\t\t&#x3C;/<span class=\"pl-ent\">TD</span>>\n\t\t&#x3C;/<span class=\"pl-ent\">TR</span>>\n      &#x3C;<span class=\"pl-ent\">TR</span>>\n         &#x3C;<span class=\"pl-ent\">TD</span> <span class=\"pl-e\">COLSPAN</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>2<span class=\"pl-pds\">\"</span></span>>&#x3C;<span class=\"pl-ent\">BR</span>>&#x3C;/<span class=\"pl-ent\">TD</span>>\n      &#x3C;/<span class=\"pl-ent\">TR</span>>\n\t\t&#x3C;/<span class=\"pl-ent\">TABLE</span>>\n\t&#x3C;/<span class=\"pl-ent\">TD</span>>\n&#x3C;/<span class=\"pl-ent\">TR</span>>\n&#x3C;<span class=\"pl-ent\">TR</span> <span class=\"pl-e\">VALIGN</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>top<span class=\"pl-pds\">\"</span></span>>\n\t&#x3C;<span class=\"pl-ent\">TD</span> <span class=\"pl-e\">WIDTH</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>10%<span class=\"pl-pds\">\"</span></span>>\n\t\t&#x3C;<span class=\"pl-ent\">TABLE</span> <span class=\"pl-e\">WIDTH</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>100%<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">CELLPADDING</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>0<span class=\"pl-pds\">\"</span></span>>&#x3C;<span class=\"pl-ent\">TR</span>>&#x3C;<span class=\"pl-ent\">TD</span> <span class=\"pl-e\">BGCOLOR</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>#000000<span class=\"pl-pds\">\"</span></span>>\n\n\t      &#x3C;<span class=\"pl-ent\">TABLE</span> <span class=\"pl-e\">WIDTH</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>100%<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">CELLPADDING</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>14<span class=\"pl-pds\">\"</span></span>>\n\t      &#x3C;<span class=\"pl-ent\">TR</span>>&#x3C;<span class=\"pl-ent\">TD</span> <span class=\"pl-e\">BGCOLOR</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>#fefefe<span class=\"pl-pds\">\"</span></span>>\n&#x3C;<span class=\"pl-ent\">FONT</span> <span class=\"pl-e\">SIZE</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>-1<span class=\"pl-pds\">\"</span></span>>&#x3C;<span class=\"pl-ent\">B</span>>\n&#x3C;<span class=\"pl-ent\">A</span> <span class=\"pl-e\">HREF</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>/index.html<span class=\"pl-pds\">\"</span></span>>News&#x3C;/<span class=\"pl-ent\">A</span>>&#x3C;<span class=\"pl-ent\">P</span>>\n&#x3C;/<span class=\"pl-ent\">B</span>>&#x3C;/<span class=\"pl-ent\">FONT</span>>\n&#x3C;/<span class=\"pl-ent\">TD</span>>&#x3C;/<span class=\"pl-ent\">TR</span>>&#x3C;/<span class=\"pl-ent\">TABLE</span>>\n&#x3C;/<span class=\"pl-ent\">TD</span>>&#x3C;/<span class=\"pl-ent\">TR</span>>&#x3C;/<span class=\"pl-ent\">TABLE</span>>&#x3C;<span class=\"pl-ent\">TABLE</span> <span class=\"pl-e\">WIDTH</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>100%<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">CELLPADDING</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>0<span class=\"pl-pds\">\"</span></span>>&#x3C;<span class=\"pl-ent\">TR</span>>&#x3C;<span class=\"pl-ent\">TD</span> <span class=\"pl-e\">BGCOLOR</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>#000000<span class=\"pl-pds\">\"</span></span>>\n\n\t      &#x3C;<span class=\"pl-ent\">TABLE</span> <span class=\"pl-e\">WIDTH</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>100%<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">CELLPADDING</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>14<span class=\"pl-pds\">\"</span></span>>\n\t      &#x3C;<span class=\"pl-ent\">TR</span>>&#x3C;<span class=\"pl-ent\">TD</span> <span class=\"pl-e\">BGCOLOR</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>#fefefe<span class=\"pl-pds\">\"</span></span>>\n&#x3C;<span class=\"pl-ent\">FONT</span> <span class=\"pl-e\">SIZE</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>-1<span class=\"pl-pds\">\"</span></span>>&#x3C;<span class=\"pl-ent\">B</span>>\n&#x3C;<span class=\"pl-ent\">A</span> <span class=\"pl-e\">HREF</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>/security/<span class=\"pl-pds\">\"</span></span>>Security Advisories&#x3C;/<span class=\"pl-ent\">A</span>>&#x3C;<span class=\"pl-ent\">P</span>>&#x3C;<span class=\"pl-ent\">A</span> <span class=\"pl-e\">HREF</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>/faq/<span class=\"pl-pds\">\"</span></span>>FAQ&#x3C;/<span class=\"pl-ent\">A</span>>&#x3C;<span class=\"pl-ent\">P</span>>&#x3C;<span class=\"pl-ent\">A</span> <span class=\"pl-e\">HREF</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>/book/<span class=\"pl-pds\">\"</span></span>>Book&#x3C;/<span class=\"pl-ent\">A</span>>&#x3C;<span class=\"pl-ent\">P</span>>&#x3C;<span class=\"pl-ent\">A</span> <span class=\"pl-e\">HREF</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>/info/<span class=\"pl-pds\">\"</span></span>>General Info&#x3C;/<span class=\"pl-ent\">A</span>>&#x3C;<span class=\"pl-ent\">P</span>>&#x3C;<span class=\"pl-ent\">A</span> <span class=\"pl-e\">HREF</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>/getslack/<span class=\"pl-pds\">\"</span></span>>Get Slack&#x3C;/<span class=\"pl-ent\">A</span>>&#x3C;<span class=\"pl-ent\">P</span>>&#x3C;<span class=\"pl-ent\">A</span> <span class=\"pl-e\">HREF</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>/install/<span class=\"pl-pds\">\"</span></span>>Install Help&#x3C;/<span class=\"pl-ent\">A</span>>&#x3C;<span class=\"pl-ent\">P</span>>&#x3C;<span class=\"pl-ent\">A</span> <span class=\"pl-e\">HREF</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>/config/<span class=\"pl-pds\">\"</span></span>>Configuration&#x3C;/<span class=\"pl-ent\">A</span>>&#x3C;<span class=\"pl-ent\">P</span>>&#x3C;<span class=\"pl-ent\">A</span> <span class=\"pl-e\">HREF</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>/packages/<span class=\"pl-pds\">\"</span></span>>Packages&#x3C;/<span class=\"pl-ent\">A</span>>&#x3C;<span class=\"pl-ent\">P</span>>&#x3C;<span class=\"pl-ent\">A</span> <span class=\"pl-e\">HREF</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>/changelog/<span class=\"pl-pds\">\"</span></span>>ChangeLogs&#x3C;/<span class=\"pl-ent\">A</span>>&#x3C;<span class=\"pl-ent\">P</span>>&#x3C;<span class=\"pl-ent\">A</span> <span class=\"pl-e\">HREF</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>/~msimons/slackware/grfx/<span class=\"pl-pds\">\"</span></span>>Propaganda&#x3C;/<span class=\"pl-ent\">A</span>>&#x3C;<span class=\"pl-ent\">P</span>>&#x3C;<span class=\"pl-ent\">A</span> <span class=\"pl-e\">HREF</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>/ports/<span class=\"pl-pds\">\"</span></span>>Ports&#x3C;/<span class=\"pl-ent\">A</span>>&#x3C;<span class=\"pl-ent\">P</span>>&#x3C;<span class=\"pl-ent\">A</span> <span class=\"pl-e\">HREF</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>/links/<span class=\"pl-pds\">\"</span></span>>Other Sites&#x3C;/<span class=\"pl-ent\">A</span>>&#x3C;<span class=\"pl-ent\">P</span>>&#x3C;<span class=\"pl-ent\">A</span> <span class=\"pl-e\">HREF</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>/support/<span class=\"pl-pds\">\"</span></span>>Support&#x3C;/<span class=\"pl-ent\">A</span>>&#x3C;<span class=\"pl-ent\">P</span>>&#x3C;<span class=\"pl-ent\">A</span> <span class=\"pl-e\">HREF</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>/contact/<span class=\"pl-pds\">\"</span></span>>Contact&#x3C;/<span class=\"pl-ent\">A</span>>&#x3C;<span class=\"pl-ent\">P</span>>&#x3C;<span class=\"pl-ent\">A</span> <span class=\"pl-e\">HREF</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>/lists/<span class=\"pl-pds\">\"</span></span>>Mailing Lists&#x3C;/<span class=\"pl-ent\">A</span>>&#x3C;<span class=\"pl-ent\">P</span>>&#x3C;<span class=\"pl-ent\">A</span> <span class=\"pl-e\">HREF</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>/about/<span class=\"pl-pds\">\"</span></span>>About&#x3C;/<span class=\"pl-ent\">A</span>>&#x3C;/<span class=\"pl-ent\">B</span>>&#x3C;/<span class=\"pl-ent\">FONT</span>>\n</code></pre>\n<h2>Debian</h2>\n<p><picture><source srcset=\"/web/debian.avif\" type=\"image/avif\"><img src=\"https://mmap.page/web/debian.png\" alt=\"debian\" width=\"704\" height=\"381\"></picture></p>\n<p>As one of two oldest Linux distributions still alive today,\n(the other is Slackware),\nDebian is also quite old fashioned.\nIts website uses HTML 4.01.\nHowever, the Debian website uses HTML 4.01 Strict,\ninstead of HTML 4.01 Transitional (used to be much more popular).\nDebian is famous for its strictness on software licences.\nI do not think these two factors are related. ;-)</p>\n<pre><code class=\"language-html\">\n&#x3C;!DOCTYPE HTML PUBLIC <span class=\"pl-s\">\"-//W3C//DTD HTML 4.01//EN\"</span> <span class=\"pl-s\">\"http://www.w3.org/TR/html4/strict.dtd\"</span>>\n&#x3C;<span class=\"pl-ent\">html</span> <span class=\"pl-e\">lang</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>en<span class=\"pl-pds\">\"</span></span>>\n&#x3C;<span class=\"pl-ent\">head</span>>\n  &#x3C;<span class=\"pl-ent\">meta</span> <span class=\"pl-e\">http-equiv</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>Content-Type<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">content</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>text/html; charset=utf-8<span class=\"pl-pds\">\"</span></span>>\n  &#x3C;<span class=\"pl-ent\">title</span>>Debian -- The Universal Operating System &#x3C;/<span class=\"pl-ent\">title</span>>\n  &#x3C;<span class=\"pl-ent\">link</span> <span class=\"pl-e\">rel</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>author<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">href</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>mailto:webmaster@debian.org<span class=\"pl-pds\">\"</span></span>>\n  &#x3C;<span class=\"pl-ent\">meta</span> <span class=\"pl-e\">name</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>Description<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">content</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>Debian is an operating system and a distribution of Free Software. It is maintained and updated through the work of many users who volunteer their time and effort.<span class=\"pl-pds\">\"</span></span>>\n  &#x3C;<span class=\"pl-ent\">meta</span> <span class=\"pl-e\">name</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>Generator<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">content</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>WML 2.0.12 (16-Apr-2008)<span class=\"pl-pds\">\"</span></span>>\n  &#x3C;<span class=\"pl-ent\">meta</span> <span class=\"pl-e\">name</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>Modified<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">content</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>2018-02-20 03:50:42<span class=\"pl-pds\">\"</span></span>>\n  &#x3C;<span class=\"pl-ent\">meta</span> <span class=\"pl-e\">name</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>viewport<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">content</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>width=device-width<span class=\"pl-pds\">\"</span></span>>\n  &#x3C;<span class=\"pl-ent\">meta</span> <span class=\"pl-e\">name</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>mobileoptimized<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">content</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>300<span class=\"pl-pds\">\"</span></span>>\n  &#x3C;<span class=\"pl-ent\">meta</span> <span class=\"pl-e\">name</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>HandheldFriendly<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">content</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>true<span class=\"pl-pds\">\"</span></span>>\n&#x3C;<span class=\"pl-ent\">link</span> <span class=\"pl-e\">rel</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>alternate<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">type</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>application/rss+xml<span class=\"pl-pds\">\"</span></span>\n <span class=\"pl-e\">title</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>Debian News<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">href</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>News/news<span class=\"pl-pds\">\"</span></span>>\n&#x3C;<span class=\"pl-ent\">link</span> <span class=\"pl-e\">rel</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>alternate<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">type</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>application/rss+xml<span class=\"pl-pds\">\"</span></span>\n <span class=\"pl-e\">title</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>Debian Project News<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">href</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>News/weekly/dwn<span class=\"pl-pds\">\"</span></span>>\n&#x3C;<span class=\"pl-ent\">link</span> <span class=\"pl-e\">rel</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>alternate<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">type</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>application/rss+xml<span class=\"pl-pds\">\"</span></span>\n <span class=\"pl-e\">title</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>Debian Security Advisories (titles only)<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">href</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>security/dsa<span class=\"pl-pds\">\"</span></span>>\n&#x3C;<span class=\"pl-ent\">link</span> <span class=\"pl-e\">rel</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>alternate<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">type</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>application/rss+xml<span class=\"pl-pds\">\"</span></span>\n <span class=\"pl-e\">title</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>Debian Security Advisories (summaries)<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">href</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>security/dsa-long<span class=\"pl-pds\">\"</span></span>>\n&#x3C;<span class=\"pl-ent\">link</span> <span class=\"pl-e\">href</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>./debhome.css<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">rel</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>stylesheet<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">type</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>text/css<span class=\"pl-pds\">\"</span></span>>\n  &#x3C;<span class=\"pl-ent\">link</span> <span class=\"pl-e\">href</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>./debian-en.css<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">rel</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>stylesheet<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">type</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>text/css<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">media</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>all<span class=\"pl-pds\">\"</span></span>>\n  &#x3C;<span class=\"pl-ent\">link</span> <span class=\"pl-e\">rel</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>shortcut icon<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">href</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>favicon.ico<span class=\"pl-pds\">\"</span></span>>\n  &#x3C;<span class=\"pl-ent\">meta</span> <span class=\"pl-e\">name</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>Keywords<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">content</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>debian, GNU, linux, unix, open source, free, DFSG<span class=\"pl-pds\">\"</span></span>>\n&#x3C;<span class=\"pl-ent\">link</span> <span class=\"pl-e\">rel</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>search<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">type</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>application/opensearchdescription+xml<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">title</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>Debian website search<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">href</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>./search.en.xml<span class=\"pl-pds\">\"</span></span>>\n&#x3C;/<span class=\"pl-ent\">head</span>>\n&#x3C;<span class=\"pl-ent\">body</span>>\n&#x3C;<span class=\"pl-ent\">div</span> <span class=\"pl-e\">id</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>header<span class=\"pl-pds\">\"</span></span>>\n   &#x3C;<span class=\"pl-ent\">div</span> <span class=\"pl-e\">id</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>upperheader<span class=\"pl-pds\">\"</span></span>>\n   &#x3C;<span class=\"pl-ent\">div</span> <span class=\"pl-e\">id</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>logo<span class=\"pl-pds\">\"</span></span>>\n  &#x3C;<span class=\"pl-ent\">a</span> <span class=\"pl-e\">href</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>./<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">title</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>Debian Home<span class=\"pl-pds\">\"</span></span>>&#x3C;<span class=\"pl-ent\">img</span> <span class=\"pl-e\">src</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>./Pics/openlogo-50.png<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">alt</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>Debian<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">width</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>50<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">height</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>61<span class=\"pl-pds\">\"</span></span>>&#x3C;/<span class=\"pl-ent\">a</span>>\n  &#x3C;/<span class=\"pl-ent\">div</span>> <span class=\"pl-c\">&#x3C;!-- end logo --></span>\n\t&#x3C;<span class=\"pl-ent\">div</span> <span class=\"pl-e\">id</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>searchbox<span class=\"pl-pds\">\"</span></span>>\n\t\t&#x3C;<span class=\"pl-ent\">form</span> <span class=\"pl-e\">name</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>p<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">method</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>get<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">action</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>https://search.debian.org/cgi-bin/omega<span class=\"pl-pds\">\"</span></span>>\n\t\t&#x3C;<span class=\"pl-ent\">p</span>>\n&#x3C;<span class=\"pl-ent\">input</span> <span class=\"pl-e\">type</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>hidden<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">name</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>DB<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">value</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>en<span class=\"pl-pds\">\"</span></span>>\n\t\t\t&#x3C;<span class=\"pl-ent\">input</span> <span class=\"pl-e\">name</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>P<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">value</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"\"</span></span> <span class=\"pl-e\">size</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>27<span class=\"pl-pds\">\"</span></span>>\n\t\t\t&#x3C;<span class=\"pl-ent\">input</span> <span class=\"pl-e\">type</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>submit<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">value</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>Search<span class=\"pl-pds\">\"</span></span>>\n\t\t&#x3C;/<span class=\"pl-ent\">p</span>>\n\t\t&#x3C;/<span class=\"pl-ent\">form</span>>\n\t&#x3C;/<span class=\"pl-ent\">div</span>>   <span class=\"pl-c\">&#x3C;!-- end sitetools --></span>\n &#x3C;/<span class=\"pl-ent\">div</span>> <span class=\"pl-c\">&#x3C;!-- end upperheader --></span>\n</code></pre>\n<h2>FreeBSD</h2>\n<p><picture><source srcset=\"/web/freebsd.avif\" type=\"image/avif\"><img src=\"https://mmap.page/web/freebsd.png\" alt=\"freebsd\" width=\"693\" height=\"412\"></picture></p>\n<p>FreeBSD website uses XHTML 1.0 Transitional with CSS.\nHowever, it does not work well with small screens as shown above.\nIronically, Slackware website layouted with tables work well under small screens.</p>\n<p>Compared to HTML 4.01, XHTML is quite \"new\".\nHowever, these days no one cares about XHTML any more.\nTo some extent, this is just like that among the BSD families FreeBSD has the fastest paces of developing and integrating new technologies and features.\nBut outside the BSD family...</p>\n<pre><code class=\"language-html\">\n&#x3C;?<span class=\"pl-ent\">xml</span> <span class=\"pl-e\">version</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>1.0<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">encoding</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>iso-8859-1<span class=\"pl-pds\">\"</span></span>?>\n&#x3C;!DOCTYPE html PUBLIC <span class=\"pl-s\">\"-//W3C//DTD XHTML 1.0 Transitional//EN\"</span> <span class=\"pl-s\">\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\"</span>>\n&#x3C;<span class=\"pl-ent\">html</span> <span class=\"pl-e\">xmlns</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>http://www.w3.org/1999/xhtml<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">xmlns:db</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>http://docbook.org/ns/docbook<span class=\"pl-pds\">\"</span></span>>\n  &#x3C;<span class=\"pl-ent\">head</span>>\n    &#x3C;<span class=\"pl-ent\">title</span>>The FreeBSD Project&#x3C;/<span class=\"pl-ent\">title</span>>\n    &#x3C;<span class=\"pl-ent\">meta</span> <span class=\"pl-e\">http-equiv</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>Content-Type<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">content</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>text/html; charset=iso-8859-1<span class=\"pl-pds\">\"</span></span> />\n    &#x3C;<span class=\"pl-ent\">link</span> <span class=\"pl-e\">rel</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>shortcut icon<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">href</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>./favicon.ico<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">type</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>image/x-icon<span class=\"pl-pds\">\"</span></span> />\n    &#x3C;<span class=\"pl-ent\">link</span> <span class=\"pl-e\">rel</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>stylesheet<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">media</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>screen,print<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">href</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>./layout/css/fixed.css?20130112<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">type</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>text/css<span class=\"pl-pds\">\"</span></span> />\n    &#x3C;<span class=\"pl-ent\">script</span> <span class=\"pl-e\">type</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>text/javascript<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">src</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>./layout/js/google.js<span class=\"pl-pds\">\"</span></span>>&#x3C;/<span class=\"pl-ent\">script</span>>\n  &#x3C;/<span class=\"pl-ent\">head</span>>\n  &#x3C;<span class=\"pl-ent\">body</span>>\n    &#x3C;<span class=\"pl-ent\">div</span> <span class=\"pl-e\">id</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>containerwrap<span class=\"pl-pds\">\"</span></span>>\n      &#x3C;<span class=\"pl-ent\">div</span> <span class=\"pl-e\">id</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>container<span class=\"pl-pds\">\"</span></span>>\n        &#x3C;<span class=\"pl-ent\">span</span> <span class=\"pl-e\">class</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>txtoffscreen<span class=\"pl-pds\">\"</span></span>>&#x3C;<span class=\"pl-ent\">a</span> <span class=\"pl-e\">href</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>#content<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">title</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>Skip site navigation<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">accesskey</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>1<span class=\"pl-pds\">\"</span></span>>Skip site navigation&#x3C;/<span class=\"pl-ent\">a</span>> (1)\n  &#x3C;<span class=\"pl-ent\">a</span> <span class=\"pl-e\">href</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>#contentwrap<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">title</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>Skip section navigation<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">accesskey</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>2<span class=\"pl-pds\">\"</span></span>>Skip section navigation&#x3C;/<span class=\"pl-ent\">a</span>> (2)\n&#x3C;/<span class=\"pl-ent\">span</span>>\n        &#x3C;<span class=\"pl-ent\">div</span> <span class=\"pl-e\">id</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>headercontainer<span class=\"pl-pds\">\"</span></span>>\n          &#x3C;<span class=\"pl-ent\">div</span> <span class=\"pl-e\">id</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>header<span class=\"pl-pds\">\"</span></span>>\n            &#x3C;<span class=\"pl-ent\">h2</span> <span class=\"pl-e\">class</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>blockhide<span class=\"pl-pds\">\"</span></span>>Header And Logo&#x3C;/<span class=\"pl-ent\">h2</span>>\n            &#x3C;<span class=\"pl-ent\">div</span> <span class=\"pl-e\">id</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>headerlogoleft<span class=\"pl-pds\">\"</span></span>>\n              &#x3C;<span class=\"pl-ent\">a</span> <span class=\"pl-e\">href</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>.<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">title</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>FreeBSD<span class=\"pl-pds\">\"</span></span>>\n                &#x3C;<span class=\"pl-ent\">img</span> <span class=\"pl-e\">src</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>./layout/images/logo-red.png<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">width</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>457<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">height</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>75<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">alt</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>FreeBSD<span class=\"pl-pds\">\"</span></span> />\n              &#x3C;/<span class=\"pl-ent\">a</span>>\n            &#x3C;/<span class=\"pl-ent\">div</span>>\n</code></pre>\n<h2>Gentoo</h2>\n<p><picture><source srcset=\"/web/gentoo.avif\" type=\"image/avif\"><img src=\"https://mmap.page/web/gentoo.png\" alt=\"gentoo\" width=\"707\" height=\"393\"></picture></p>\n<p>The cutting edge Gentoo website uses HTML5.\nBy the way, another cutting edge Linux distribution Arch also uses HTML5 on its web site.</p>\n<pre><code class=\"language-html\">&#x3C;!DOCTYPE html>\n&#x3C;<span class=\"pl-ent\">html</span>>\n  &#x3C;<span class=\"pl-ent\">head</span>>\n  &#x3C;<span class=\"pl-ent\">meta</span> <span class=\"pl-e\">charset</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>utf-8<span class=\"pl-pds\">\"</span></span>>\n  &#x3C;<span class=\"pl-ent\">title</span>>Welcome – Gentoo Linux&#x3C;/<span class=\"pl-ent\">title</span>>\n  &#x3C;<span class=\"pl-ent\">meta</span> <span class=\"pl-e\">name</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>description<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">content</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>The website of Gentoo, a flexible Linux or BSD distribution.<span class=\"pl-pds\">\"</span></span>>\n  &#x3C;<span class=\"pl-ent\">meta</span> <span class=\"pl-e\">name</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>theme-color<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">content</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>#54487a<span class=\"pl-pds\">\"</span></span>>\n  &#x3C;<span class=\"pl-ent\">meta</span> <span class=\"pl-e\">name</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>viewport<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">content</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>width=device-width, initial-scale=1.0<span class=\"pl-pds\">\"</span></span>>\n  &#x3C;<span class=\"pl-ent\">meta</span> <span class=\"pl-e\">http-equiv</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>X-UA-Compatible<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">content</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>IE=edge<span class=\"pl-pds\">\"</span></span>>\n  &#x3C;<span class=\"pl-ent\">meta</span> <span class=\"pl-e\">property</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>og:title<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">content</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>Welcome – Gentoo Linux<span class=\"pl-pds\">\"</span></span>>\n  &#x3C;<span class=\"pl-ent\">meta</span> <span class=\"pl-e\">property</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>og:image<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">content</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>https://www.gentoo.org/assets/img/logo/gentoo-g.png<span class=\"pl-pds\">\"</span></span>>\n  &#x3C;<span class=\"pl-ent\">meta</span> <span class=\"pl-e\">property</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>og:description<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">content</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>The website of Gentoo, a flexible Linux or BSD distribution.<span class=\"pl-pds\">\"</span></span>>\n  &#x3C;<span class=\"pl-ent\">meta</span> <span class=\"pl-e\">name</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>twitter:image<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">content</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>https://www.gentoo.org/assets/img/logo/gentoo-g.png<span class=\"pl-pds\">\"</span></span>>\n  &#x3C;<span class=\"pl-ent\">link</span> <span class=\"pl-e\">rel</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>apple-touch-icon<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">href</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>https://www.gentoo.org/assets/img/logo/icon-192.png<span class=\"pl-pds\">\"</span></span>>\n  &#x3C;<span class=\"pl-ent\">link</span> <span class=\"pl-e\">rel</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>icon<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">sizes</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>192x192<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">href</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>https://www.gentoo.org/assets/img/logo/icon-192.png<span class=\"pl-pds\">\"</span></span>>\n  &#x3C;<span class=\"pl-ent\">link</span> <span class=\"pl-e\">href</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>https://assets.gentoo.org/tyrian/bootstrap.min.css<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">rel</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>stylesheet<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">media</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>screen<span class=\"pl-pds\">\"</span></span>>\n  &#x3C;<span class=\"pl-ent\">link</span> <span class=\"pl-e\">href</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>https://assets.gentoo.org/tyrian/tyrian.min.css<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">rel</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>stylesheet<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">media</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>screen<span class=\"pl-pds\">\"</span></span>>\n  &#x3C;<span class=\"pl-ent\">link</span> <span class=\"pl-e\">href</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>/assets/css/screen.css<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">rel</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>stylesheet<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">media</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>screen<span class=\"pl-pds\">\"</span></span>>\n\n  &#x3C;<span class=\"pl-ent\">link</span> <span class=\"pl-e\">rel</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>icon<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">href</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>/favicon.ico<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">type</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>image/x-icon<span class=\"pl-pds\">\"</span></span>>\n  &#x3C;<span class=\"pl-ent\">link</span> <span class=\"pl-e\">rel</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>search<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">type</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>application/opensearchdescription+xml<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">href</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>https://www.gentoo.org/search/www-gentoo-org.xml<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">title</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>Gentoo Website<span class=\"pl-pds\">\"</span></span>>\n  &#x3C;<span class=\"pl-ent\">link</span> <span class=\"pl-e\">rel</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>search<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">type</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>application/opensearchdescription+xml<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">href</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>https://www.gentoo.org/search/forums-gentoo-org.xml<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">title</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>Gentoo Forums<span class=\"pl-pds\">\"</span></span>>\n  &#x3C;<span class=\"pl-ent\">link</span> <span class=\"pl-e\">rel</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>search<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">type</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>application/opensearchdescription+xml<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">href</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>https://www.gentoo.org/search/bugs-gentoo-org.xml<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">title</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>Gentoo Bugzilla<span class=\"pl-pds\">\"</span></span>>\n  &#x3C;<span class=\"pl-ent\">link</span> <span class=\"pl-e\">rel</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>search<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">type</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>application/opensearchdescription+xml<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">href</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>https://www.gentoo.org/search/packages-gentoo-org.xml<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">title</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>Gentoo Packages<span class=\"pl-pds\">\"</span></span>>\n  &#x3C;<span class=\"pl-ent\">link</span> <span class=\"pl-e\">rel</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>search<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">type</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>application/opensearchdescription+xml<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">href</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>https://www.gentoo.org/search/archives-gentoo-org.xml<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">title</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>Gentoo List Archives<span class=\"pl-pds\">\"</span></span>>\n  &#x3C;<span class=\"pl-ent\">link</span> <span class=\"pl-e\">rel</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>alternate<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">type</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>application/atom+xml<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">title</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>Gentoo Linux news<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">href</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>/feeds/news.xml<span class=\"pl-pds\">\"</span></span>>\n&#x3C;/<span class=\"pl-ent\">head</span>>\n\n  &#x3C;<span class=\"pl-ent\">body</span> <span class=\"pl-e\">class</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"\"</span></span>>\n    &#x3C;<span class=\"pl-ent\">header</span>>\n  &#x3C;<span class=\"pl-ent\">div</span> <span class=\"pl-e\">class</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>site-title<span class=\"pl-pds\">\"</span></span>>\n    &#x3C;<span class=\"pl-ent\">div</span> <span class=\"pl-e\">class</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>container<span class=\"pl-pds\">\"</span></span>>\n      &#x3C;<span class=\"pl-ent\">div</span> <span class=\"pl-e\">class</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>row<span class=\"pl-pds\">\"</span></span>>\n        &#x3C;<span class=\"pl-ent\">div</span> <span class=\"pl-e\">class</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>site-title-buttons<span class=\"pl-pds\">\"</span></span>>\n          &#x3C;<span class=\"pl-ent\">div</span> <span class=\"pl-e\">class</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>btn-group btn-group-sm<span class=\"pl-pds\">\"</span></span>>\n            &#x3C;<span class=\"pl-ent\">a</span> <span class=\"pl-e\">href</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>https://get.gentoo.org/<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">role</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>button<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">class</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>btn get-gentoo<span class=\"pl-pds\">\"</span></span>>&#x3C;<span class=\"pl-ent\">span</span> <span class=\"pl-e\">class</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>fa fa-fw fa-download<span class=\"pl-pds\">\"</span></span>>&#x3C;/<span class=\"pl-ent\">span</span>> &#x3C;<span class=\"pl-ent\">strong</span>>Get Gentoo!&#x3C;/<span class=\"pl-ent\">strong</span>>&#x3C;/<span class=\"pl-ent\">a</span>>\n            &#x3C;<span class=\"pl-ent\">div</span> <span class=\"pl-e\">class</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>btn-group btn-group-sm<span class=\"pl-pds\">\"</span></span>>\n              &#x3C;<span class=\"pl-ent\">a</span> <span class=\"pl-e\">class</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>btn gentoo-org-sites dropdown-toggle<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">data-toggle</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>dropdown<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">data-target</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>#<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">href</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>#<span class=\"pl-pds\">\"</span></span>>\n                &#x3C;<span class=\"pl-ent\">span</span> <span class=\"pl-e\">class</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>fa fa-fw fa-map-o<span class=\"pl-pds\">\"</span></span>>&#x3C;/<span class=\"pl-ent\">span</span>> &#x3C;<span class=\"pl-ent\">span</span> <span class=\"pl-e\">class</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>hidden-xs<span class=\"pl-pds\">\"</span></span>>gentoo.org sites&#x3C;/<span class=\"pl-ent\">span</span>> &#x3C;<span class=\"pl-ent\">span</span> <span class=\"pl-e\">class</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>caret<span class=\"pl-pds\">\"</span></span>>&#x3C;/<span class=\"pl-ent\">span</span>>\n              &#x3C;/<span class=\"pl-ent\">a</span>>\n              &#x3C;<span class=\"pl-ent\">ul</span> <span class=\"pl-e\">class</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>dropdown-menu dropdown-menu-right<span class=\"pl-pds\">\"</span></span>>\n                &#x3C;<span class=\"pl-ent\">li</span>>&#x3C;<span class=\"pl-ent\">a</span> <span class=\"pl-e\">href</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>https://www.gentoo.org/<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">title</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>Main Gentoo website<span class=\"pl-pds\">\"</span></span>>&#x3C;<span class=\"pl-ent\">span</span> <span class=\"pl-e\">class</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>fa fa-home fa-fw<span class=\"pl-pds\">\"</span></span>>&#x3C;/<span class=\"pl-ent\">span</span>> gentoo.org&#x3C;/<span class=\"pl-ent\">a</span>>&#x3C;/<span class=\"pl-ent\">li</span>>\n                &#x3C;<span class=\"pl-ent\">li</span>>&#x3C;<span class=\"pl-ent\">a</span> <span class=\"pl-e\">href</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>https://wiki.gentoo.org/<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">title</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>Find and contribute documentation<span class=\"pl-pds\">\"</span></span>>&#x3C;<span class=\"pl-ent\">span</span> <span class=\"pl-e\">class</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>fa fa-file-text-o fa-fw<span class=\"pl-pds\">\"</span></span>>&#x3C;/<span class=\"pl-ent\">span</span>> Wiki&#x3C;/<span class=\"pl-ent\">a</span>>&#x3C;/<span class=\"pl-ent\">li</span>>\n                &#x3C;<span class=\"pl-ent\">li</span>>&#x3C;<span class=\"pl-ent\">a</span> <span class=\"pl-e\">href</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>https://bugs.gentoo.org/<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">title</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>Report issues and find common issues<span class=\"pl-pds\">\"</span></span>>&#x3C;<span class=\"pl-ent\">span</span> <span class=\"pl-e\">class</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>fa fa-bug fa-fw<span class=\"pl-pds\">\"</span></span>>&#x3C;/<span class=\"pl-ent\">span</span>> Bugs&#x3C;/<span class=\"pl-ent\">a</span>>&#x3C;/<span class=\"pl-ent\">li</span>>\n                &#x3C;<span class=\"pl-ent\">li</span>>&#x3C;<span class=\"pl-ent\">a</span> <span class=\"pl-e\">href</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>https://forums.gentoo.org/<span class=\"pl-pds\">\"</span></span> <span class=\"pl-e\">title</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>Discuss with the community<span class=\"pl-pds\">\"</span></span>>&#x3C;<span class=\"pl-ent\">span</span> <span class=\"pl-e\">class</span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>fa fa-comments-o fa-fw<span class=\"pl-pds\">\"</span></span>>&#x3C;/<span class=\"pl-ent\">span</span>> Forums&#x3C;/<span class=\"pl-ent\">a</span>>&#x3C;/<span class=\"pl-ent\">li</span>>\n</code></pre>","date_published":"Tue, 20 Feb 2018 12:33:49 GMT","date_modified":"Sun, 24 May 2020 14:51:37 GMT"},{"id":"https://mmap.page/dive-into/osx/","url":"https://mmap.page/dive-into/osx/","title":"macOS Survival Guide","content_html":"<h1>macOS Survival Guide</h1>\n<h2>Create a Bootable Installer</h2>\n<p>I created a bootable installer to install macOS offline,\nin case that something went wrong.\nAlthough macOS can be installed from Internet in recovery mode, it is unreliable and slow.\nI first tried a Sandisk 16GB USB drive, and it failed during copying the installer content.\nThen I tried a Toshiba 32GB USB drive, and the creation succeeded.\nI am not sure if 16GB is too small or macOS installer is fussy on USB drive models.</p>\n<p>I also set secure boot to medium security, to avoid connecting to Apple servers when installing operating systems.</p>\n<h2>Enable TouchID for sudo</h2>\n<p>Add <code>auth sufficient pam_tid.so</code> in <code>/etc/pam.d/sudo_local</code>.</p>\n<h2>Set Timezone to GMT</h2>\n<p>I am frustrated to dealing with timezones.\nWhy not everyone uses UTC+0?</p>\n<pre><code class=\"language-sh\">sudo systemsetup -settimezone GMT\n</code></pre>\n<p>And got a <a href=\"https://github.com/LnL7/nix-darwin/issues/359#issuecomment-1209428101\">-99 error</a>.\nBut it seems that the timezone has changed to GMT.</p>\n<pre><code class=\"language-sh\"><span class=\"pl-k\">;</span> sudo systemsetup -gettimezone\nTime Zone: GMT\n</code></pre>\n<p>For safety, I unselect the \"Set time zone automatically using current location\" option in \"System Preferences > Date &#x26; Time > Time Zone\".</p>\n<h2>Keyboard</h2>\n<p>In System Preference > Keyboard > Modifier Keys, I set CapsLock as Esc.</p>\n<p>By the way, OS X has native system-wide support for some Emacs keybinds, e.g.</p>\n<table>\n<thead>\n<tr>\n<th>Command</th>\n<th>Key</th>\n<th>Alternatives</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>beginning-of-line</td>\n<td><code>^a</code></td>\n<td><code>&#x3C;D-Left></code></td>\n</tr>\n<tr>\n<td>end-of-line</td>\n<td><code>^e</code></td>\n<td><code>&#x3C;D-Right></code></td>\n</tr>\n<tr>\n<td>previous-line</td>\n<td><code>^p</code></td>\n<td><code>&#x3C;Up></code></td>\n</tr>\n<tr>\n<td>next-line</td>\n<td><code>^n</code></td>\n<td><code>&#x3C;Down></code></td>\n</tr>\n<tr>\n<td>forward-char</td>\n<td><code>^f</code></td>\n<td><code>&#x3C;Right></code></td>\n</tr>\n<tr>\n<td>backward-char</td>\n<td><code>^b</code></td>\n<td><code>&#x3C;Left></code></td>\n</tr>\n<tr>\n<td>delete-char</td>\n<td><code>^d</code></td>\n<td>N/A</td>\n</tr>\n<tr>\n<td>backward-delete-char</td>\n<td><code>^h</code></td>\n<td><code>&#x3C;Delete></code></td>\n</tr>\n<tr>\n<td>transpose-char</td>\n<td><code>^t</code></td>\n<td>N/A</td>\n</tr>\n<tr>\n<td>kill-line</td>\n<td><code>^k</code></td>\n<td>N/A</td>\n</tr>\n<tr>\n<td>yank-line</td>\n<td><code>^y</code></td>\n<td>N/A</td>\n</tr>\n<tr>\n<td>insert-line</td>\n<td><code>^o</code></td>\n<td>N/A</td>\n</tr>\n<tr>\n<td>page-down</td>\n<td><code>^v</code></td>\n<td><code>&#x3C;Fn+Down></code></td>\n</tr>\n<tr>\n<td>recenter</td>\n<td><code>^l</code></td>\n<td>N/A</td>\n</tr>\n</tbody>\n</table>\n<p>And there are some keybinds slightly different the original Emacs keybinds:</p>\n<ul>\n<li>forward/backward-word, use two keys (<code>Control</code> and <code>Option</code>) for the <code>Meta</code> key. Alternatives: <code>Option</code> with arrow keys.</li>\n<li><code>M-&#x3C;</code> and <code>M-></code> are unavailable on macOS. But <code>&#x3C;D-Up></code> and <code>&#x3C;D-Down></code> can be used to go to the begin and end of document.</li>\n<li><code>M-v</code> is unavailable, but <code>&#x3C;Fn+Up></code> can be used for page up.</li>\n<li><code>C-l</code> for recenter is unavailable.</li>\n<li>Also, <code>C-s</code> and <code>C-r</code> for search is unavailable.</li>\n<li>shrink/extend-selection, add an additional <code>Shift</code> key but not needing to enter the selection mode (<code>C-SPC</code>) first.</li>\n</ul>\n<p>My keyboad has arrow keys and I feel using arrow keys are more nature.</p>\n<h2>Trackpad</h2>\n<p>In System Preferences > Trackpad:</p>\n<ul>\n<li>\n<p>Change \"Look up\" to three-finger tap.</p>\n</li>\n<li>\n<p>Select \"Swipe down with three fingers\" for App Expose.</p>\n</li>\n<li>\n<p>Unselect \"Lanuchpad\" and \"Show Desktop\".</p>\n</li>\n<li>\n<p>Select \"Tap to click\".</p>\n</li>\n<li>\n<p>Unselect \"Scroll direction: Natural\".</p>\n<p>It may be natural on touchsceen, but I feel it unnatural on trackpad and mouse.</p>\n</li>\n</ul>\n<h2>Turn off Internal Display</h2>\n<p><strong>When the power adapter is connected:</strong></p>\n<ol>\n<li>Close the lid to put laptop to sleep.</li>\n<li>Reactivate laptop via external input devices, e.g. keyboard.</li>\n</ol>\n<h2>Window Management</h2>\n<p>I feel the window management under macOS weird.</p>\n<h3>Stage Manager</h3>\n<p>I do not use stage manager.\nIt is inaccessible from keyboard shortcuts.\nBesides, it causes latency when switching between windows.</p>\n<h3>Tiling</h3>\n<p>By default, macOS only supports tiling two windows vertically.\nI want to tile windows via keyboard shortcuts.\nTherefore, in Settings > Keyboard > Keyboard Shortcuts > App Shortcuts,\nI add the following two shortcuts under \"All Applications\":</p>\n<ul>\n<li>\"Move Window to Left Side of Screen\": <code>C-A-Left</code></li>\n<li>\"Move Window to Right Side of Screen\": <code>C-A-Right</code></li>\n</ul>\n<h3>Virtual Desktops</h3>\n<p>Press <code>Ctrl-Left/Right</code> or swipe three fingers from left to right to switch among virtual desktops.</p>\n<p>Press <code>Ctrl-Up</code> to show an overview of desktops.</p>\n<p><code>Fn-f</code> will turn the focused application to full screen.\nAll full screen application will occupy an entire virtual desktop,\nwhich will be created and destroyed upon the application entered and exited full screen.</p>\n<p><code>Ctrl-Down</code> shows all windows of the current application\nand ``Cmd-``` switches among windows of the current application.\nBoth of them only apply to windows in the current virtual desktop.\nTherefore, full screen applications do not work with them.</p>\n<p>There is no such concept called maximize under recent versions of macOS.\nThe most similar thing is \"zoom\", which sometimes maximizes the window,\nsometimes not, depending on the type of the window and its content.\nSimilarly to tilling, I added keyboard shortcut for it:</p>\n<ul>\n<li>\"Zoom\": <code>Alt-Cmd-f</code></li>\n</ul>\n<p>Also, I enabled <code>Ctrl-Num</code> shortcuts under\n<code>Settings > Keyboard > Keyboard shortcuts > Mission Control > Mission Control</code>.\nHowever, this only works for virtual desktops I created by myself,\nnot automatically managed desktops for full screen applications.</p>\n<h2>Finder</h2>\n<p>By default, <code>~/Library</code> is hidden.\nTo reveal it in Finder temporarily,\nhold the Option key, then click the <code>Go</code> menu,\nand the Library folder is revealed in the dropdown menu.</p>\n<p>To permanently reveal the Library folder in Finder, run the following command:</p>\n<pre><code class=\"language-sh\">chflags nohidden <span class=\"pl-k\">~</span>/Library/\n</code></pre>\n<p>BTW, most applications' user configuration files are in <code>~/Library/Application Support</code>.</p>\n<h2>Safari</h2>\n<p>To enable developer tools, select \"Show Develop menu in menu bar\" in Safari > Preferences > Advanced.\nYou can also change the default encoding to UTF-8.</p>\n<p>There are several vi shortcuts extensions for safari, for example, <a href=\"https://github.com/televator-apps/vimari\">vimari</a>.</p>\n<p>Due to the limitation of Safari, vimari has fewer key bindings than similar extensions for other browsers.\nAlso, by default it binds <code>w/q</code> for next/previous tab, which I feel hard to remember.\n<a href=\"https://github.com/philc/vimium\">Vimium</a> uses <code>J/K</code>, which I also hard to remember.\nThus, I just remove them and use Safari native keyboard shortcuts.\nAlso, I find myself more frequently open links in new tabs,\nso I swapped <code>f</code> and <code>F</code>, using <code>f</code> to toggle links for opening the link in background tab.</p>\n<pre><code class=\"language-json\"><span class=\"pl-ent\">\"hintToggle\"</span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>shift+f<span class=\"pl-pds\">\"</span></span>,\n<span class=\"pl-ent\">\"newTabHintToggle\"</span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>f<span class=\"pl-pds\">\"</span></span>,\n</code></pre>\n<h2>Google</h2>\n<p>Google accounts can be added to the Mail.app.\nBesides gmail, other osx applications can also sync with Google account:</p>\n<ul>\n<li>Contacts</li>\n<li>Calenders</li>\n<li>Messages (with Google Talk)</li>\n<li>Notes (via gmail, tagged as notes)</li>\n</ul>","date_published":"Wed, 24 Jan 2018 17:43:01 GMT","date_modified":"Sat, 03 Feb 2024 12:35:21 GMT"},{"id":"https://mmap.page/dive-into/jetbrains/","url":"https://mmap.page/dive-into/jetbrains/","title":"Dive into JetBrains IDEs","content_html":"<h1>Dive into JetBrains IDEs</h1>\n<h2>Appearance</h2>\n<ul>\n<li>Appearance: <strong>Darcula</strong></li>\n<li>Color Scheme: <strong>Colorful Darcula</strong></li>\n<li>Color Scheme Font: <strong>24</strong> for 13-inch display</li>\n</ul>\n<h2>Keymaps</h2>\n<p>I use Sublime Text keymap with a few tweaks:</p>\n<ul>\n<li>Basic completion: <strong>Tab</strong>. With the auto formatting function, I do not need to use Tab to indent. Thus, Tab can be used to trigger completion. And when the completions pop up, I can press Tab again to confirm the completion candidate, very convenient.</li>\n<li>Find Action: the ultimate keyboard shortcut deserves <strong>F1</strong> (inspired by vscode)</li>\n<li>Rename variable name: <strong>F2</strong> is used for renaming file names in most file managers and renaming variables in vscode. For consistency, I also removed <code>Ctrl+F2</code> for toggling bookmark, and bind <code>Ctrl+F2</code> to introducing variables, <code>Shift+F2</code> to inline variables, <code>Ctrl+Shift+F2</code> to introduce constants, <code>Alt+F2</code> to introduce functions (extract methods).</li>\n<li>Go to declaration or usage: <strong>F4</strong> since this powerful navigation includes the function of \"go to source\".</li>\n<li>Quick documentation: <strong>F5</strong> is near <strong>F4</strong> (jump to source). I have poor memory and check documentation and source frequently.</li>\n<li>Go to symbol: <strong>F6</strong> goes to address bar in web browsers. Thus I use F6 to navigate. And F6 is near F5 (go to documentation) and F4 (go to source). The default three-key combo (ctrl+shift+R) is too hard to remember and type.</li>\n<li>Find usage: <strong>F7</strong> since it is consistent with <code>Ctrl+F7</code> (find usage in current file). Although <strong>F4</strong> can go find usages at the declaration , sometimes I still want to find other usages when not at the declaration.</li>\n<li>Last edit location: <strong>F8</strong> since it is near F9.</li>\n<li>Toggle bookmark: <strong>F9</strong> inspired by Yin Wang. I also set alt/ctrl/shift + F9 to show/next/previous bookmark. P.S. F2 - F9 are all used for navigation.</li>\n<li>Terminal: <strong>F12</strong> since I use terminal a lot and already bind go to declaration/usage to F4. Why not keep the default? Because I want all navigation related actions are in nearby keys (F2-F9). Also, F12 in web browser opens the console.</li>\n<li>Complete Current Statement: <strong>C-Enter</strong> since I used it far more frequently than inserting a new line.</li>\n</ul>\n<h3>Fn</h3>\n<p>I bind frequently used actions to F keys, so they are easier to reach.\nThe \"Sublime\" field refers to the default keyboard shorts for the real Sublime Text editor, not the Sublime Text keymap for JetBrains IDEs.</p>\n<table>\n<thead>\n<tr>\n<th>Key</th>\n<th>Default</th>\n<th>Sublime</th>\n<th>Me</th>\n<th>Rationale</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>F1</td>\n<td>help</td>\n<td>n/a</td>\n<td>find action</td>\n<td>inspired by vscode</td>\n</tr>\n<tr>\n<td>F2</td>\n<td>next error</td>\n<td>next bookmark</td>\n<td>refactor: rename</td>\n<td>inspired by file managers and vscode</td>\n</tr>\n<tr>\n<td>F3</td>\n<td>next occurrence</td>\n<td>next occurrence</td>\n<td>next occurrence</td>\n<td>convention</td>\n</tr>\n<tr>\n<td>F4</td>\n<td>jump to source</td>\n<td>next results in find all</td>\n<td>go to declaration/usage</td>\n<td>more powerful than \"jump to source\"</td>\n</tr>\n<tr>\n<td>F5</td>\n<td>refactor: copy</td>\n<td>n/a</td>\n<td>quick documentation</td>\n<td>near F4</td>\n</tr>\n<tr>\n<td>F6</td>\n<td>refactor: move</td>\n<td>toggle spell check</td>\n<td>go to symbol</td>\n<td>inspired by go to address bar in web browser</td>\n</tr>\n<tr>\n<td>F7</td>\n<td>debug: step into</td>\n<td>build</td>\n<td>find usage</td>\n<td>consistent with <code>Ctrl+F7</code> (find usage in current file)</td>\n</tr>\n<tr>\n<td>F8</td>\n<td>debug: step out</td>\n<td>n/a</td>\n<td>last edit location</td>\n<td>near F9</td>\n</tr>\n<tr>\n<td>F9</td>\n<td>debug: resume</td>\n<td>sort lines</td>\n<td>toggle bookmark</td>\n<td>Inspired by Yin Wang.</td>\n</tr>\n<tr>\n<td>F10</td>\n<td>menu (os)</td>\n<td>menu (os)</td>\n<td>menu (os)</td>\n<td></td>\n</tr>\n<tr>\n<td>F11</td>\n<td>toggle fullscreen</td>\n<td>toggle fullscreen</td>\n<td>toggle fullscreen</td>\n<td>convention</td>\n</tr>\n<tr>\n<td>F12</td>\n<td>go to declaration/usage</td>\n<td>go to definition</td>\n<td>terminal</td>\n<td>Already bind go to declaration/usage to F4 and inspired by web browser (F12 for the console).</td>\n</tr>\n</tbody>\n</table>\n<h2>Other Tweaks</h2>\n<ul>\n<li>Editor > General > Code Completion: enable \"sort completion suggestions based on machine learning\".</li>\n<li>Tools > Terminal > Application Settings > Shell path: change from <code>/bin/bash</code> to <code>/usr/bin/fish</code>.</li>\n</ul>","date_published":"Wed, 24 Jan 2018 17:37:19 GMT","date_modified":"Fri, 21 Apr 2023 06:31:30 GMT"},{"id":"https://mmap.page/dapi/wash-clothes/","url":"https://mmap.page/dapi/wash-clothes/","content_html":"<h2>混洗内外衣或使用公共洗衣机</h2>\n<p>为了避免交叉感染：</p>\n<ol start=\"0\">\n<li>使用滴露等杀菌剂</li>\n<li>使用60度温水</li>\n</ol>\n<h2>毛衣</h2>\n<ol start=\"0\">\n<li>购买可机洗的毛衣。</li>\n<li>选择最轻柔的模式。</li>\n<li>选择酸碱度中性、温和的洗涤剂，或者也可以使用洗发水（毕竟毛衣的原料是羊的毛发）。</li>\n<li>将毛衣翻过来，放进网袋或枕套里，减少磨损。</li>\n<li>不要使用烘干机。避免把毛衣挂在衣架上晾干，以免水的重量将毛衣拉拽变形。建议将毛衣平铺在架子上晾干。</li>\n<li>如果不在乎变形，洗涤说明上注明不可机洗的毛衣同样可以机洗，洗后也可以挂在衣架上晾干。</li>\n</ol>","date_published":"Thu, 18 Jan 2018 16:38:33 GMT","date_modified":"Fri, 17 Dec 2021 15:43:01 GMT"},{"id":"https://mmap.page/dapi/packaging/","url":"https://mmap.page/dapi/packaging/","content_html":"<p>总的思路是精简衣物，以及选择便于携带的衣物。</p>\n<ol>\n<li>选择轻便的衣物。比如避免厚重的皮大衣。</li>\n<li>选择柔软的衣物，这样可以卷起来放置。避免无法卷起来的衣物。</li>\n<li>内衣不够的话可以途中采购。比如沃尔玛的简适系列（有一次性内衣，即使非一次性内衣也不贵）。</li>\n<li>长羽绒服可以穿在身上。如果出发地和目的地温差大，或目的地本身温差大的话，选择轻型羽绒服，甚至轻型羽绒背心。</li>\n<li>美利奴羊毛衫比较轻便，透气纤维也比较适合温差大的环境。</li>\n<li>如果运动量较大，或环境比较潮湿，可以选择AIRism之类透气性强的面料。不推荐HEATTECH之类吸汗保暖的面料，增温效果未必有多好，却显著降低舒适性。</li>\n<li>轻便衣物的多层次搭配，是应对温差大的环境的秘方。</li>\n<li>尽量少带鞋子。鞋子内部可以塞别的东西，比如袜子。</li>\n</ol>","date_published":"Thu, 18 Jan 2018 16:31:28 GMT","date_modified":"Sat, 23 Nov 2019 19:11:50 GMT"},{"id":"https://mmap.page/dapi/law-labor/","url":"https://mmap.page/dapi/law-labor/","title":"劳动法","content_html":"<h1>劳动法</h1>\n<h2>劳动关系和劳务关系</h2>\n<p>注意劳动关系和劳务关系的区别。</p>\n<p>劳动关系存在的原因：</p>\n<ol>\n<li>劳动力交易成本</li>\n<li>历史惯性</li>\n</ol>\n<h2>仲裁时效</h2>\n<p>劳动仲裁的时效为 1 年。</p>\n<p>例外：劳动关系存续期间因拖欠劳动报酬发生争议的，时效延长至劳动关系终止后 1 年。</p>\n<p>例外的例外：由于法律规定用工单位只需保存劳动者的加班工资支付记录 2 年时间，\n因此在 2 年内追诉加班工资的，举证具体加班时间的责任在用工单位。\n而追诉 2 年前的加班工资，劳动者需要自行举证自己的加班时间。</p>\n<p>劳动仲裁是 CN 劳动争议解决的诉前必经程序。</p>\n<h2>招聘</h2>\n<h3>虚假招聘广告</h3>\n<p>法律层面，劳动者应对虚假招聘广告并没有什么有效的方法：</p>\n<ol>\n<li>\n<p>劳动合同法 s.8 规定用人单位有如实告知的义务，但是并没有规定不如实告知的责任。除非用人单位极其过分，会被认定为欺诈。</p>\n</li>\n<li>\n<p>就业服务与就业管理虽然规定 s. 14 禁止用人单位提供虚假招聘信息，发布虚假招聘广告，但是相应的责任只是「劳动保障行政部门责令改正，并可处以一千元以下的罚款；对当事人造成损害的，应当承担赔偿责任。」(s. 67) 也就是说用人单位基本上只要改正就可以了，运气不好也就是承担 1k 以下的罚款，不痛不痒。而劳动者要举证自己因为虚假招聘广告受到损害，难度很大。</p>\n</li>\n<li>\n<p>合同法 s. 15 虽然规定「商业广告的内容符合要约规定的，视为要约」，但一般而言招聘广告都是要约邀请，很难认定为要约。因为要认定为要约，除了内容具体确定外（大多数招聘广告都没详细具体到这个程度），还要「表明经受要约人承诺，要约人即受该意思表示约束」(合同法 s. 14)</p>\n</li>\n</ol>\n<p>所以，被虚假招聘广告坑了，在法律层面，劳动者也只能向劳动保障行政部门举报下，虽然即使举报成功了也并没有什么卵用。</p>\n<h3>歧视</h3>\n<p>法律层面，歧视不能放到台面上来，\n或者说，可以 implicit 地歧视，不能 explicit 地歧视。</p>\n<ol>\n<li>招聘广告不得带有歧视内容</li>\n<li>招聘过程中不得明确告知劳动者不符合歧视性的录用条件</li>\n</ol>\n<h3>告知义务</h3>\n<p>用人单位需要主动告知，劳动者在用人单位要求时才告知。</p>\n<p>劳动者的告知范围仅限于与劳动合同直接相关的基本情况，无关情况有权拒绝告知。</p>\n<p>工作内容、条件、地点、职业危害、安全生产状况、劳动报酬等内容，用人单位需要主动告知。</p>\n<p>其他情况，劳动者如果要求了解，用人单位没有拒绝告知的权利，除非涉及商业秘密。</p>\n<p>注意，这里用人单位告知虚假情况，使劳动者在违背真实意思的情况下订立或者变更劳动合同的，可能被认定为欺诈(劳动合同法 s. 26)。\n法律对此的打击力度和虚假招聘广告完全不同。</p>\n<h3>录用通知书</h3>\n<p>录用通知书只是用人单位的要约，和劳动合同是两回事。\n用人单位反悔，单方面撤销要约，属于预期违约，劳动者可以要求用人单位就其损失承担赔偿责任。</p>\n<h2>订立合同</h2>\n<p>据劳动合同法 s. 17, 劳动合同的必备条款如下：</p>\n<ol>\n<li>\n<p>用人单位的名称、住所和法定代表人或者主要负责人。</p>\n<p>名称为注册登记时所登记的名称。</p>\n<p>用人单位办事机构的所在地的具体地址。</p>\n</li>\n<li>\n<p>劳动者的姓名、住址和居民身份证或者其他有效身份证件号码。</p>\n<p>劳动者的住址，以其户籍所在的居住地为住所，其经常居住地与住所不一致的，经常居住地视为住所。</p>\n</li>\n<li>\n<p>劳动合同期限。</p>\n<p>固定期限、无固定期限、以完成一定工作任务为期限。</p>\n</li>\n<li>\n<p>工作内容和工作地点。</p>\n<p>工作内容包括劳动者从事劳动的工种、岗位和劳动定额、工作的任务等。</p>\n</li>\n</ol>\n<p>　　工作地点，是指劳动者可能从事工作的具体位置。</p>\n<pre><code>很多地方的司法实务中规定，超过地级市行政区域的工作地点变更，劳动者有权拒绝。\n</code></pre>\n<p>5. 工作时间和休息休假。</p>\n<pre><code>休息日安排加班，可以安排劳动者补休，也可以支付加班工资。\n法定节假日安排加班，不能以调休代替加班工资。\n\n带薪年休假，5/10/15 天（跨单位工作年限 1/10/20 年）。\n\n休息休假期间照常支付工资(劳动法 s. 51, 工资支付暂行规定 s. 11)\n\n探亲假待遇仅限国家机关、人民团体和全民所有制企业、事业单位工作的职工。\n\n婚假遇法定节假日和休息日能否顺延，各地政策不一样。如上海规定遇法定节假日顺延。(上海市计划生育奖励与补助若干规定 s. 2) 如果地方性政策不支持的话，只能通过提前申请或延后申请避免法定休假冲掉婚假的问题。\n\n再婚同样享受婚假（劳动和社会保障部《关于对再婚职工婚假问题的复函》）。\n\n晚婚假限于初婚。一方初婚，另一方再婚，或者双方初婚，一方符合晚婚年龄，另一方不符合的，不符合晚婚条件的一方不能被认定为晚婚，符合晚婚条件的一方是否能认定为晚婚取决于当地的计划生育条例（如北京要求双方初婚，上海未限定双方初婚）。\n\n工作时间不限于实际工作时间。工作时间的范围，不仅包括作业时间，还包括准备工作时间、 结束工作时间以及法定劳动消耗时间。其中，法定非劳动消耗时间是指劳动者自然中断的时间、工艺需中断时间、停工待活时间、女职工哺乳婴儿时间、出差时间等。此外，工作时间还包括依据法律、法规或单位行政安排离岗从事其他活动的时间。\n</code></pre>\n<p>6. 劳动报酬。</p>\n<pre><code>以货币形式支付给劳动者的工资。\n\n《工资支付暂行规定》规定，用工单位必须在约定的日期支付工资。\n如遇节假日或休息日，应提前在最近的工作日支付。\n工资至少每月支付一次。\n\n国家统计局发布的《关于工资总额组成的规定》规定股票期权不列入工资范畴。(s. 11) 当然，行权时税务机关会按照工资、薪金所得给你算个人所得税的(国家税务总局《关于个人股票期权所得征收个人所得税问题的通知》)。\n\n病假期间（规定的医疗期内）可以减工资，最多可以减到当地最低工资标准的 80% (关于贯彻执行《中华人民共和国劳动法》若干问题的意见 s. 59)。部分地方另有规定，比如深圳规定不得低于 `max(本人正常工作时间工资 * 0.6, 最低工资 * 0.8)`(深圳市员工工资支付条例 s. 23)\n\n事假期间，可以不支付工资。例外：1) 部分地区有特别规定 2) 用工单位不扣工资，事假达到一定天数后冲抵年休假\n</code></pre>\n<p>7. 社会保险。</p>\n<pre><code>养老保险、失业保险、医疗保险、工伤保险、生育保险五项，政府强制参加。\n\n另外，住房公积金也是强制参加，但地位比上述五险低。\n五险是《劳动法》强制的，公积金是国务院《住房公积金管理条例》强制的。\n</code></pre>\n<p>8. 劳动保护、劳动条件和职业危害防护。</p>\n<ol start=\"9\">\n<li>\n<p>法律、法规规定应当纳入劳动合同的其他事项。</p>\n<p>给《劳动合同法》以外的法律法规留的扩展接口。</p>\n</li>\n</ol>\n<p>基本上，<code>[1, 2, 3, 4, 6]</code> 比较重要，其他的都可以 fallback 到相关法律法规规定。\n其实 3 理论上也可以 fallback, 不过一般用工单位并不愿意 fallback 到无固定期限。</p>\n<h2>规章制度</h2>\n<p>规章制度的制定有程序上的要求，\n没有通过民主程序制定和公示的规章制度，依法不能成为处理劳动纠纷的处理依据。\n(劳动合同法 s.4)</p>\n<p>但是，法律并没有规定用工单位和劳动者无法就规章制度达成一致时如何处理。\n此问题的裁量取决于法院。\n有一些地方性的 patch,\n比如《深圳市中级人民法院关于审理劳动争议案件若干问题的指导意见（试行）》 s. 79 规定</p>\n<blockquote>\n<p>《劳动合同法》第四条第二款规定的“平等协商确定”主要是指程序上的要求，\n如果平等协商无法达成一致，最后决定权在用人单位。\n如该规章制度违反法律法规的规定，给劳动者造成损害的，\n劳动者可依据《劳动合同法》第八十条寻求救济。</p>\n</blockquote>\n<p>另外，有些含糊其辞的规章制度并没有什么卵用，\n比如「由于员工失职或营私舞弊给公司造成重大损失的，公司可以解除合同，并要求赔偿」之类的，由于「重大损失」没有明确定义，基本上没什么用。</p>\n<h2>解除合同</h2>\n<h3>劳动者</h3>\n<p>提前 30 日书面通知用人单位（试用期内提前 3 日）。(劳动合同法 s. 37)</p>\n<p>当然，用人单位有特定过错的，劳动者可以直接解除合同，不用提前 30 日通知。(劳动合同法 s. 38, s. 26)\n最容易抓的小辫子是工资不当月发，拖到下个月发，或者因为财务的问题超过约定日期好久才发。\n但一般用人单位不是有意侵犯劳动者权利的，也没有必要为了省那些交接的时间揪用人单位的小辫子。</p>\n<p>另外，小辫子也不是都能让劳动者直接解除合同的。\n有的违法行为，劳动者只能向当地劳动监察部门举报，\n如果举报成功，用人单位的责任也是改正和罚款，并不能免除劳动者提前通知的义务。\n而且最终结果取决于当地的执法力度，\n如果执法力度不够，劳动者只能起诉相关部门行政不作为。</p>\n<h3>用人单位</h3>\n<h4>非过失性解雇</h4>\n<p>非因劳动者过错，\n但根据劳动者健康状况、工作能力、情势变更而导致劳动合同不能或无法履行的，\n（具体情形见劳动合同法 s. 40）\n用人单位提前 30 日书面通知劳动者或者额外支付一个月工资后，\n解除劳动合同。</p>\n<p>健康状况：患病或非因工负伤，取决于总工作年限和本单位工作年限，有 3 个月到 2 年的医疗期。医疗期满后，如果不能从事原工作，用工单位还得设法另行安排工作，仍然不行的，用工单位才能解除合同。</p>\n<p>工作能力：用工单位还需要培训或者为其调整工作岗位，\n经过一定期间的培训或重新安排的工作也不胜任的，才能解除合同。\n关于如何评定不能胜任，\n单一领导的结论、末尾淘汰制、同一群体不同标准是不能成立的，\n其他取决于法院的裁量。</p>\n<p>情势变更：需要是重大变化，比如被兼并、合并、分立、转产、重大技术改造，使员工的原工作岗位不复存在，且当事人协商不能达成协议。</p>\n<p>还有一个批量解除合同的方法是裁员，但裁员的条件和程序都相当复杂，\n除了依照企业破产法进行重整比较容易裁员外，其他裁员的条件认证都比较困难。</p>\n<h4>迫使员工自愿离职</h4>\n<ol>\n<li>\n<p>降薪</p>\n<p>降薪属于变更劳动合同的必备条款，需要经劳动者同意才行，并不能单方面降薪。</p>\n</li>\n<li>\n<p>调岗</p>\n<p>和降薪一样，需要和劳动者协商，调岗后收入水平比原岗位大大降低的，以及侮辱性的调岗，需承担违法责任。</p>\n</li>\n<li>\n<p>减少加班或不安排加班</p>\n<p>只对部分低工资的行业有效。</p>\n</li>\n<li>\n<p>放假</p>\n<p>首先，必须有停工、停产的事实。其次，需要支付工资（停工、停产在一个工资支付周期以内）及生活费（长期停工、停产）。</p>\n</li>\n<li>\n<p>威胁以后碰到背调说员工坏话</p>\n<p>员工不一定把这段工作经历写到简历里，即使写入，一家用工单位的评价和其他用工单位的评价不一致的话，新单位很可能不采信。</p>\n</li>\n</ol>\n<h4>违法解雇</h4>\n<p>违法解雇需要支付经济补偿。</p>\n<p>总之，劳动者无过错的情况下，用工单位要解雇劳动者，成本不低。\n换句话说，政府提倡用工单位尽量避免解雇劳动者。\n否则劳动者预期自己随时可能被解雇，可能就不敢背房贷买房了。</p>\n<h2>试用期</h2>\n<h3>工资</h3>\n<pre><code class=\"language-java\"><span class=\"pl-c\">// 加班工资、保险、福利待遇不作为最低工资的组成部分。</span>\n<span class=\"pl-k\">double</span> 最低工资;\n<span class=\"pl-k\">double</span> 本单位同岗位最低档工资或合同约定工资;\n<span class=\"pl-k\">double</span> 试用期工资;\n\n<span class=\"pl-c\">// 劳动合同法 s. 20</span>\n<span class=\"pl-k\">assert</span> 试用期工资 <span class=\"pl-k\">>=</span> 最低工资;\n<span class=\"pl-k\">assert</span> 试用期工资 <span class=\"pl-k\">>=</span> <span class=\"pl-c1\">0.8</span> <span class=\"pl-k\">*</span> 本单位同岗位最低档工资或合同约定工资;\n</code></pre>\n<h3>期限</h3>\n<pre><code class=\"language-java\"><span class=\"pl-c\">// 劳动合同法 s. 19</span>\n<span class=\"pl-smi\">Period</span> 合同期限;\n<span class=\"pl-smi\">Period</span> 试用期;\n<span class=\"pl-k\">boolean</span> 试用过;\n\n<span class=\"pl-k\">if</span> (试用过) {\n    <span class=\"pl-k\">throw</span> <span class=\"pl-k\">new</span> <span class=\"pl-smi\">Exception</span>(<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>同一用人单位与同一劳动者只能约定一次试用期<span class=\"pl-pds\">\"</span></span>);\n}\n} <span class=\"pl-k\">else</span> <span class=\"pl-k\">if</span> (合同期限 <span class=\"pl-k\">&#x3C;</span> <span class=\"pl-smi\">Period</span><span class=\"pl-k\">.</span>ofYears(<span class=\"pl-c1\">1</span>)) {\n    <span class=\"pl-k\">assert</span> 试用期 <span class=\"pl-k\">&#x3C;=</span> <span class=\"pl-smi\">Period</span><span class=\"pl-k\">.</span>ofMonths(<span class=\"pl-c1\">1</span>);\n} <span class=\"pl-k\">else</span> <span class=\"pl-k\">if</span> (合同期限 <span class=\"pl-k\">&#x3C;</span> <span class=\"pl-smi\">Period</span><span class=\"pl-k\">.</span>ofYears(<span class=\"pl-c1\">3</span>)) {\n    <span class=\"pl-k\">assert</span> 试用期 <span class=\"pl-k\">&#x3C;=</span> <span class=\"pl-smi\">Period</span><span class=\"pl-k\">.</span>ofMonths(<span class=\"pl-c1\">2</span>);\n} <span class=\"pl-k\">else</span> {\n    <span class=\"pl-k\">assert</span> 试用期 <span class=\"pl-k\">&#x3C;=</span> <span class=\"pl-smi\">Period</span><span class=\"pl-k\">.</span>ofMonths(<span class=\"pl-c1\">6</span>);\n}\n</code></pre>\n<h2>经济补偿</h2>\n<pre><code class=\"language-java\"><span class=\"pl-c\">// 劳动合同法 s. 47</span>\n<span class=\"pl-k\">class</span> <span class=\"pl-en\">经济补偿</span> {\n    <span class=\"pl-k\">private</span> <span class=\"pl-smi\">Period</span> 工作年限;\n    <span class=\"pl-k\">private</span> <span class=\"pl-k\">double</span> 月工资; <span class=\"pl-c\">// 合同解除或终止前 12 个月平均</span>\n    <span class=\"pl-c\">// 用人单位所在直辖市、设区的市级人民政府公布的本地区上年度职工平均工资</span>\n    <span class=\"pl-k\">private</span> <span class=\"pl-k\">double</span> 平均工资;\n\n    <span class=\"pl-k\">public</span> <span class=\"pl-en\">经济补偿</span>(<span class=\"pl-k\">int</span> <span class=\"pl-v\">year</span>, <span class=\"pl-k\">double</span> <span class=\"pl-v\">salary</span>, <span class=\"pl-k\">double</span> <span class=\"pl-v\">averageSalary</span>) {\n        <span class=\"pl-c1\">this</span><span class=\"pl-k\">.</span>工作年限 <span class=\"pl-k\">=</span> <span class=\"pl-smi\">Period</span><span class=\"pl-k\">.</span>ofYears(year);\n        <span class=\"pl-c1\">this</span><span class=\"pl-k\">.</span>月工资 <span class=\"pl-k\">=</span> salary;\n        <span class=\"pl-c1\">this</span><span class=\"pl-k\">.</span>平均工资 <span class=\"pl-k\">=</span> averageSalary;\n    }\n\n    <span class=\"pl-k\">public</span> <span class=\"pl-en\">get补偿</span>() {\n        <span class=\"pl-k\">if</span> (月工资 <span class=\"pl-k\">></span> <span class=\"pl-c1\">3</span> <span class=\"pl-k\">*</span> 平均工资) {\n            <span class=\"pl-k\">if</span> (工作年限 <span class=\"pl-k\">&#x3C;</span> <span class=\"pl-smi\">Period</span><span class=\"pl-k\">.</span>ofMonths(<span class=\"pl-c1\">6</span>)) {\n                <span class=\"pl-k\">return</span> <span class=\"pl-c1\">3</span> <span class=\"pl-k\">*</span> 平均工资 <span class=\"pl-k\">*</span> <span class=\"pl-c1\">0.5</span>;\n            } <span class=\"pl-k\">else</span> <span class=\"pl-k\">if</span> (工作年限 <span class=\"pl-k\">>=</span> <span class=\"pl-smi\">Period</span><span class=\"pl-k\">.</span>ofMoths(<span class=\"pl-c1\">6</span>) <span class=\"pl-k\">&#x26;&#x26;</span> 工作年限 <span class=\"pl-k\">&#x3C;</span> <span class=\"pl-smi\">Period</span><span class=\"pl-k\">.</span>ofYears(<span class=\"pl-c1\">1</span>)) {\n                <span class=\"pl-k\">return</span> <span class=\"pl-c1\">3</span> <span class=\"pl-k\">*</span> 平均工资;\n            } <span class=\"pl-k\">else</span> <span class=\"pl-k\">if</span> (工作年限 <span class=\"pl-k\">&#x3C;</span> <span class=\"pl-smi\">Period</span><span class=\"pl-k\">.</span>ofYears(<span class=\"pl-c1\">12</span>)) {\n                <span class=\"pl-k\">return</span> <span class=\"pl-c1\">3</span> <span class=\"pl-k\">*</span> 平均工资 <span class=\"pl-k\">*</span> 工作年限;\n            } <span class=\"pl-k\">else</span> {\n                <span class=\"pl-k\">return</span> <span class=\"pl-c1\">3</span> <span class=\"pl-k\">*</span> 平均工资 <span class=\"pl-k\">*</span> <span class=\"pl-c1\">12</span>;\n            }\n        } <span class=\"pl-k\">else</span> {\n            <span class=\"pl-k\">if</span> (工作年限 <span class=\"pl-k\">&#x3C;</span> <span class=\"pl-smi\">Period</span><span class=\"pl-k\">.</span>ofMonths(<span class=\"pl-c1\">6</span>)) {\n                <span class=\"pl-k\">return</span> 月工资 <span class=\"pl-k\">*</span> <span class=\"pl-c1\">0.5</span>;\n            } <span class=\"pl-k\">else</span> <span class=\"pl-k\">if</span> (工作年限 <span class=\"pl-k\">>=</span> <span class=\"pl-smi\">Period</span><span class=\"pl-k\">.</span>ofMoths(<span class=\"pl-c1\">6</span>) <span class=\"pl-k\">&#x26;&#x26;</span> 工作年限 <span class=\"pl-k\">&#x3C;</span> <span class=\"pl-smi\">Period</span><span class=\"pl-k\">.</span>ofYears(<span class=\"pl-c1\">1</span>)) {\n                <span class=\"pl-k\">return</span> 月工资;\n            } <span class=\"pl-k\">else</span> {\n                <span class=\"pl-k\">return</span> 月工资 <span class=\"pl-k\">*</span> 工作年限;\n            }\n        }\n    }\n}\n</code></pre>\n<p>经济补偿金不能在劳动者工资中预发，\n作为法定的强制经济补偿措施，当事人不得自行决定。</p>\n<h2>其他</h2>\n<h3>劳务派遣</h3>\n<p>坑比较多，立法也很不完善，争议性问题较多，法规本身也不稳定，执法倾向地区性差异很大。如果有纠纷，是三方纠纷，比一般的劳资纠纷复杂多了。</p>\n<p>慎重选择。</p>\n<h3>不安排公休</h3>\n<p>单位确因工作需要不能安排职工休年休假的，经职工本人同意后，\n可以不安排其公休，按照日工资 300% 支付应休未休的报酬。</p>\n<p>如果放假宅家尚可接受，\n但如果打算旅游的话，节假日旅行多付出的花费远远超过应休未休的补偿。</p>\n<p>用工单位无故不批准劳动者申请年休假，劳动者又执意休假未上班的，\n是否视为旷工，法律上没有规定，可能取决于地方性规定。</p>\n<p>劳动者以个人原因辞职，用工单位尚未安排年休假的，是否应支付未休年假工资，\n法律上同样没有规定，可能取决于地方性规定。</p>\n<h3>员工违纪罚款</h3>\n<p>用工单位是否可以通过依法制定的规章或劳动合同约定的途径进行罚款，\n各地的规定和司法惯例不同。</p>\n<h3>值班</h3>\n<ol>\n<li>安排值班不需要经工会和劳动者双重协商程序</li>\n<li>如何值班、一次值多久不受《劳动法》约束，由用工单位内部规章制度规定（虽然理论上来说内部规章制度也需要公示并与劳动者协商，但这个主要是程序上的规定）</li>\n<li>值班没有加班费，待遇由用工单位内部规章制度规定，唯一的保障是值班报酬的标准需要一致（劳动法 s. 46 同工同酬）</li>\n</ol>\n<h3>不定时工作制</h3>\n<ol>\n<li>需要注册地区县劳动部门批准，且审批难度较大。</li>\n<li>需先经员工同意。</li>\n<li>原则上每天工作 8 小时，每周至少休息 1 天。</li>\n<li>无加班工资，节假日除外。</li>\n</ol>\n<h3>用人单位变动</h3>\n<ol>\n<li>非组织实体变动（名称、法人代表、地址等）不影响劳动合同履行。 (劳动合同法 s.33)</li>\n<li>分立、合并后，如履行条件发生变化，用人单位和劳动者可以对原劳动合同进行协商变更。(民法通则 s. 44; 劳动合同法 s. 34)</li>\n</ol>\n<h3>服务期</h3>\n<p>注意只有用工单位为劳动者提供专项培训费用，对其进行专业技术培训，才可以约定服务期。</p>\n<p>以下服务期和违约金的规定不受法律保护：</p>\n<ol>\n<li>适应性培训</li>\n<li>上岗和转岗培训</li>\n<li>高薪</li>\n<li>解决户口</li>\n<li>分配住房、轿车</li>\n</ol>\n<p>另外，服务期的约定是否对用工单位也有约束力，\n即约定的服务期长于劳动合同期限的，是否视为对劳动合同期限的延长，\n法律上有争议。\n有些区域通过地方性规定 patch 了，有些区域则处于不确定状态。</p>\n<h3>未订立劳动合同</h3>\n<p>用工之日起 1 个月内应当订立书面劳动合同。</p>\n<p>如果用工单位超期未订立合同，用工单位应支付双倍工资，(劳动合同法实施条例 s. 7)\n但相应的劳动者也需要收集证据证明劳动关系的存在。\n对于这种不及时订立劳动合同的用工单位，还是尽早抽身为妙，\n没有必要贪图那一点双倍工资先干着，事后再耗费时间精力谈判或仲裁。</p>\n<p>如果劳动者经用工单位书面通知后，不与用工单位订立书面劳动合同，\n用工单位应书面通知劳动者终止劳动关系，并依法向劳动者支付其实际工作时间的劳动报酬。(劳动合同法实施条例 s. 5)\n出现这种情况，一般是双方就合同条款不能达成一致。</p>\n<h3>倒签劳动合同</h3>\n<p>用工单位超期未订立合同，为了规避风险，在补签合同时将签字日期倒签在法定界限之内。\n这时候劳动者如果签字了，是否视为劳动者放弃要求用人单位支付双倍工资的权利，在法律上有争议。</p>\n<h3>单独试用合同</h3>\n<p>试用期只能在劳动合同内约定。\n单独试用合同会被认定为一份固定期限劳动合同。(劳动合同法 s.19)\n由于试用期一般不会太长，因此用工单位签一次自以为的「试用合同」，\n结束试用期后再签一次正式的劳动合同，\n就达成了「连续订立二次固定期限劳动合同」的条件，\n按劳动合同法规定，已经属于应当订立无固定期限劳动合同的情形。\n到时如果劳动者不主动提出订立固定期限劳动合同的话，\n用工单位就比较尴尬了。</p>\n<p>另外，试用期也需要办理五险一金，如果用工单位不办的话，\n（搞这种合同的单位未必有这个意识）\n将面临被责令补缴等法律责任，\n同时面临被劳动者以此为理由直接解除劳动合同并要求支付补偿的风险。</p>\n<p>所以说搞这种合同的用工单位都是在作死，避开为妙。</p>\n<h3>再就业培训补贴</h3>\n<p>城镇登记失业人员中由就业转失业人员，可享受免费再就业培训，或申请职业培训补贴。</p>\n<p>不过那些培训的质量么。。。</p>\n<h3>集体协商、工会、集体合同</h3>\n<p>在 CN 能动用这个内耗很高的机制的话，说明劳资矛盾已经极其尖锐了，\n也就是说雇主完全不知道自己在干什么。\n（当然也有小部分可能是大部分雇员不知道自己在干什么，\n但雇主招这么多不知道自己在干什么的雇员，也是不知道自己在干什么。）</p>\n<p>还有一种情况，是政府部门推区域性集体合同或行业性集体合同。\n区域性集体合同因为缺少针对性，基本只有某些特别的小镇能推行。\n行业性集体合同主要针对建筑业、采矿业、餐饮服务业等。</p>","date_published":"Thu, 05 Oct 2017 01:49:28 GMT","date_modified":"Sat, 26 Jul 2025 05:29:46 GMT"},{"id":"https://mmap.page/dapi/law-rent/","url":"https://mmap.page/dapi/law-rent/","title":"房屋租赁","content_html":"<h1>房屋租赁</h1>\n<h2>合同</h2>\n<p>商品房屋租赁管理办法 s. 7 规定，\n房屋租赁合同的内容由当事人双方约定，一般应当包括以下内容：</p>\n<ol>\n<li>\n<p>房屋租赁当事人的姓名（名称）和住所</p>\n<p>出示身份证原件，留存复印件</p>\n</li>\n<li>\n<p>房屋的坐落、面积、结构、附属设施，家具和家电等室内设施状况</p>\n<p>业主出示房产证、土地证，留存复印件。房本没下来的，出示购房合同。</p>\n<p>特别是家电，需要试用，并将状况记录在合同中。</p>\n</li>\n<li>\n<p>租金和押金数额、支付方式</p>\n<p>争取银行转账而不是现金支付，记录银行账号。\n银行转账有转账记录，也能避免出租人拒绝收租反以租客不交租为由解除合同。</p>\n<p>明确退还押金的条件，避免出租人以含糊理由在合同期满后扣除押金。</p>\n</li>\n<li>\n<p>租赁用途和房屋使用要求</p>\n</li>\n<li>\n<p>房屋和室内设施的安全性能</p>\n</li>\n<li>\n<p>租赁期限</p>\n<p>租赁期限六个月以上的，应当采用书面形式。当事人未采用书面形式的，视为不定期租赁。(合同法 s. 215)</p>\n<p>租赁期间届满，承租人继续使用租赁物，出租人没有提出异议的，原租赁合同继续有效，但租赁期限为不定期。(合同法 s. 236) 当事人可以随时解除合同，但出租人解除合同应当在合理期限之前通知承租人。(合同法 s. 232)</p>\n</li>\n<li>\n<p>房屋维修责任</p>\n<p>出租人应当履行租赁物的维修义务，但当事人另有约定的除外。(合同法 s. 220)</p>\n<p>承租人在租赁物需要维修时可以要求出租人在合理期限内维修。出租人未履行维修义务的，承租人可以自行维修，维修费用由出租人负担。因维修租赁物影响承租人使用的，应当相应减少租金或者延长租期。(合同法 s. 221)</p>\n<p>承租人未经出租人同意，对租赁物进行改善或者增设他物的，出租人可以要求承租人恢复原状或者赔偿损失。(合同法 s. 223)</p>\n</li>\n<li>\n<p>物业服务、水、电、燃气等相关费用的缴纳</p>\n<p>水、电、燃气表读数</p>\n</li>\n<li>\n<p>争议解决办法和违约责任</p>\n<p>租赁物危及承租人的安全或者健康的，即使承租人订立合同时明知该租赁物质量不合格，承租人仍然可以随时解除合同。(合同法 s. 233)</p>\n<p>当事人以房屋租赁合同未按照法律、行政法规规定办理登记备案手续为由，请求确认合同无效的，人民法院不予支持。\n(最高人民法院关于审理城镇房屋租赁合同纠纷案件具体应用法律若干问题的解释 s. 4)</p>\n<p>房屋租赁合同无效，当事人请求参照合同约定的租金标准支付房屋占有使用费的，人民法院一般应予支持。\n(最高人民法院关于审理城镇房屋租赁合同纠纷案件具体应用法律若干问题的解释 s. 5)</p>\n<p>出租人就同一房屋订立数份租赁合同，在合同均有效的情况下，承租人均主张履行合同的，人民法院按照下列顺序确定履行合同的承租人：</p>\n<ol>\n<li>已经合法占有租赁房屋的；</li>\n<li>已经办理登记备案手续的；</li>\n<li>合同成立在先的。</li>\n</ol>\n<p>不能取得租赁房屋的承租人请求解除合同、赔偿损失的，依照合同法的有关规定处理。\n(最高人民法院关于审理城镇房屋租赁合同纠纷案件具体应用法律若干问题的解释 s. 6)</p>\n</li>\n<li>\n<p>其他约定</p>\n</li>\n<li>\n<p>房屋被征收或者拆迁时的处理办法</p>\n</li>\n</ol>\n<p>合同当面签署，超过 1 页的，每页均加签名（或仅签姓）。</p>\n<h2>转租</h2>\n<h3>次承租人的风险</h3>\n<ol>\n<li>\n<p>转租未经出租人同意</p>\n<p>承租人未经出租人同意转租的，出租人可以解除合同。(合同法 s. 224)</p>\n<p>承租人未经出租人书面同意转租的，出租人可以解除租赁合同，收回房屋并要求承租人赔偿损失。(商品房屋租赁管理办法 s. 11)</p>\n<p>出租人知道或者应当知道承租人转租，但在六个月内未提出异议，其以承租人未经同意为由请求解除合同或者认定转租合同无效的，人民法院不予支持。\n(最高人民法院关于审理城镇房屋租赁合同纠纷案件具体应用法律若干问题的解释 s. 16)</p>\n</li>\n<li>\n<p>转租人丧失承租权</p>\n<p>次承租人的承租权依附于承租人的承租权。</p>\n</li>\n</ol>\n<h4>救济</h4>\n<ol>\n<li>\n<p>转租人因欠租导致出租人解除合同</p>\n<p>因承租人拖欠租金，出租人请求解除合同时，次承租人请求代承租人支付欠付的租金和违约金以抗辩出租人合同解除权的，人民法院应予支持。但转租合同无效的除外。\n(最高人民法院关于审理城镇房屋租赁合同纠纷案件具体应用法律若干问题的解释 s. 17)</p>\n<p>次承租人代为支付的租金和违约金超出其应付的租金数额，可以折抵租金或者向承租人追偿。\n(最高人民法院关于审理城镇房屋租赁合同纠纷案件具体应用法律若干问题的解释 s. 17)</p>\n</li>\n</ol>\n<h3>转租人的风险</h3>\n<ol>\n<li>\n<p>次承租人无力支付租金或拖欠租金时，转租人仍需向出租人付租金。</p>\n<p>承租人转租的，承租人与出租人之间的租赁合同继续有效。(合同法 s. 224)</p>\n</li>\n<li>\n<p>次承租人对租赁物造成损失，转租人需先承担责任，再设法向此承租人追偿。</p>\n<p>第三人对租赁物造成损失的，承租人应当赔偿损失。(合同法 s. 224)</p>\n</li>\n</ol>\n<h2>所有权变动</h2>\n<p>租赁期间所有权变动，房屋受让人继续履行原租赁合同。例外：</p>\n<ol>\n<li>当事人另有约定</li>\n<li>房屋在出租前已设立抵押权，因抵押权人实现抵押权发生所有权变动的</li>\n<li>房屋在出租前已被人民法院依法查封的</li>\n</ol>\n<p>出租人出卖房屋，或与抵押权人协议折价、变卖租赁房屋偿还债务的，\n应当在合理期限内通知承租人。</p>\n<p>出租人委托拍卖人拍卖租赁房屋，应当在拍卖5日前通知承租人。</p>\n<p>(最高人民法院关于审理城镇房屋租赁合同纠纷案件具体应用法律若干问题的解释 ss. 20-23)</p>\n<h2>群租</h2>\n<p>商品房屋租赁管理办法 s. 8 规定：</p>\n<blockquote>\n<p>出租住房的，应当以原设计的房间为最小出租单位，\n人均租住建筑面积不得低于当地人民政府规定的最低标准。</p>\n</blockquote>\n<blockquote>\n<p>厨房、卫生间、阳台和地下储藏室不得出租供人员居住。</p>\n</blockquote>\n<p>因此群租的法律风险取决于：</p>\n<ol>\n<li>政策变动（当地规定的最低人均面积）</li>\n<li>执法力度（「违反本办法第八条规定的，由直辖市、市、县人民政府建设（房地产）主管部门责令限期改正，逾期不改正的，可处以五千元以上三万元以下罚款。」商品房屋租赁管理办法 s. 22）</li>\n</ol>","date_published":"Mon, 02 Oct 2017 12:01:38 GMT","date_modified":"Sat, 26 Jul 2025 05:29:46 GMT"},{"id":"https://mmap.page/dapi/chufenger/","url":"https://mmap.page/dapi/chufenger/","content_html":"<p>楚风儿（一首）</p>\n<p>苏州二题选一</p>\n<p>袅袅烟青四五家，竹炉细雨坐烹茶。此身只合苏州老，短巷横斜栀子花。</p>\n<p>（网人七绝三百首）</p>\n<p>【笺注】</p>\n<p><strong>身</strong> 一身。</p>\n<p><strong>只合苏州老</strong> 【唐】韦庄《菩萨蛮》「人人尽说江南好，游人只合江南老。春水碧于天，画船听雨眠。垆边人似月，皓腕凝霜雪。未老莫还乡，还乡须断肠。」</p>\n<p><strong>短巷</strong> 今苏州犹存短巷。</p>\n<p><strong>横斜</strong> 【宋】林逋《山园小梅》「疎影横斜水清浅，暗香浮动月黄昏。」林逋早岁游江淮间，后归杭州，隐居西湖孤山二十年。种梅养鹤，时称「梅妻鹤子」。《宋史》云「逋不娶，無子，教兄子宥，登進士甲科」。林正秋《林净因和中日饮食文化交流》（杭州师院学报(社会科学版)，1986-06）谓林逋有后代 2 支，一在浙江奉化，一在日本，日本馒头创制者林净因即林逋后裔。</p>\n<p><strong>栀子</strong> 【唐】彦谦《离鸾》「庭前佳树名梔子，试结同心寄谢娘 。」</p>","date_published":"Mon, 25 Sep 2017 12:12:02 GMT","date_modified":"Sat, 23 Nov 2019 19:11:50 GMT"},{"id":"https://mmap.page/dapi/law/","url":"https://mmap.page/dapi/law/","title":"An Introduction to Law for Programmers","content_html":"<h1>An Introduction to Law for Programmers</h1>\n<h2>预备知识和技能</h2>\n<ul>\n<li>基本的编程知识</li>\n<li>粗浅的英文阅读能力</li>\n</ul>\n<h2>书籍</h2>\n<p>法律方面有很多粗制滥造的书籍，\n一个幼稚的辨别方法是排除以下 4 类书籍：</p>\n<ol>\n<li>面向普通大众的书（反正你们也不懂，我搞一个 quick and dirty 的东西就行，剩下的是营销的活）</li>\n<li>面向司法考试的书（教辅书本来就是粗制滥造的重灾区，而且出于应试需要，严重偏向司法考试出题人的学术倾向，较少照顾实际层面的惯例）</li>\n<li>各种学术会议的砖头书（有的注水严重，有的离实际层面的问题较远）</li>\n<li>纯法律条文书（没法跳转到定义，没有相关的 patch 信息，读起来效率太低）</li>\n</ol>\n<p>当然会有误杀的情况，但总体来说效果很好。</p>\n<p>推荐以下 2 类书籍：</p>\n<ol>\n<li>最近出版的法学专业的教材（帮助提炼领域知识的精华）</li>\n<li>面向法务工作者（比如律师、企业法务人员、HR 等）的手册（实务中的坑以及填坑、绕坑的经验）</li>\n</ol>\n<h2>法学理论</h2>\n<p>具有XX特色的社会主义法学理论，类似XX语言是程序员最好的朋友，都是广告。</p>\n<p>学东西光看广告是不行的，还是要多读书提高一下知识水平。</p>\n<blockquote>\n<p>这都是些初步意见，还没有作最后决定，以后可能不算数。\n刘伯承同志经常讲一句四川话：\n「黄猫、黑猫，只要捉住老鼠就是好猫。」\n我们之所以能够打败蒋介石，\n就是不讲老规矩，不按老路子打，一切看情况，打赢算数。</p>\n</blockquote>\n<p>-- 邓小平《怎样恢复农业生产》</p>\n<h2>法律文本的结构</h2>\n<p>这里的法律文本，指成文法(statutes)。</p>\n<p>由大到小，依次为编、章、节、条、款、项、目。（立法法 s. 54）</p>\n<h3>编</h3>\n<p>篇幅很大的法律有这个。</p>\n<p>比如民事诉讼法分四编(part):</p>\n<ol>\n<li>总则</li>\n<li>审判程序</li>\n<li>执行程序</li>\n<li>涉外民事诉讼程序的特别规定</li>\n</ol>\n<h3>章</h3>\n<p>大部分法律直接由章(chapter)构成，跳过编这个层级。</p>\n<h3>节</h3>\n<p>篇幅较长的章分节(section).</p>\n<p>注意，这里的 section 是一般英文文本中的 section.\n某些英语国家法律语境下的 section 是有特定含义的：</p>\n<blockquote>\n<p>Section: a subdivision of a statute or document ...\nMost statutes and codes are divided into sections.</p>\n</blockquote>\n<p>-- A Dictionary of the Law (Clapp, 2000, p. 389)</p>\n<p>也就是说，这 section 其实对应中文法律语境下的「条」。</p>\n<h3>条</h3>\n<p>这个是法律最基本的结构，粒度大概相当于程序语言中的函数或方法。</p>\n<p>条翻译为 article, 但如前所述，其实很多时候翻译为 section 可能更有助于交流。</p>\n<p>因为这个是最基本的结构，所以引用法律条文往往注明条的序数，\n比如前面引用《立法法》，就用<code>s. 54</code>标明是第 54 条。\n除了<code>s.</code>以外，习惯上更常用<code>§ 54</code>的形式。\n个人偏好<code>s.</code>, 因为输入起来比较方便。</p>\n<h3>款</h3>\n<p>长的条会分成款(paragraph)。款的开头缩进两格，末尾换行。\n这和长的函数定义用空行划分段落的做法类似。</p>\n<h3>项</h3>\n<p>翻译为 subparagraph, 但其实相当于 HTML 中的<code>ol</code>.</p>\n<p>前面我们已经提到了中文和英文里 section 的错位，\n其实款和条也有错位，台湾的法律文本，款和项是倒过来的，\n台湾的「项」其实是 paragraph, 而「款」才是 subparapraph,\n台湾目前的这个用法，是沿用了中华民国时期的做法。\n最早可能是借鉴了日本法律文本的结构。</p>\n<h3>目</h3>\n<p>翻译为 item, 也是一种<code>ol</code>.</p>\n<p>「项」与「目」的区别</p>\n<ul>\n<li>语法(syntax)层面，项用括起来的中文数字标序，目用阿拉伯数字标序。</li>\n<li>语义(semantics)层面，目比项层级低。</li>\n<li>使用频率层面，目很少出现。</li>\n</ul>\n<h3>例子</h3>\n<p>民法通则 s. 134</p>\n<pre><code>承担民事责任的方式主要有：     // 第一款\n    （一）停止侵害；          // 第一款第一项\n    （二）排除妨碍；\n    （三）消除危险；\n    （四）返还财产；\n    （五）恢复原状；\n    （六）修理、重作、更换；\n    （七）赔偿损失；\n    （八）支付违约金；\n    （九）消除影响、恢复名誉；\n    （十）赔礼道歉。\n    以上承担民事责任的方式，可以单独适用，也可以合并\n适用。                                            // 第二款\n    人民法院审理民事案件，除适用上述规定外，还可以予以训\n诫、责令具结悔过、收缴进行非法活动的财物和非法所得，并可\n以依照法律规定处以罚款、拘留。\n</code></pre>\n<h3>作用</h3>\n<p>下面举两个例子，分别说明法律文本的结构如何帮助/阻碍我们理解法律。</p>\n<h4>个人合伙</h4>\n<p>《民法通则》里，「个人合伙」属于第二章「自然人」，\n不属于第三章「法人」，\n「个人合伙」前面一节是「个体工商户、农村承包经营户」。</p>\n<p>所以，不用读具体的条文，或者其他细法（部门法），\n从结构上就能看出，合伙企业和其他企业不同，并不属于法人。\n合伙企业其实是将家庭经营的个体工商户模式推广到家庭之外的产物。</p>\n<h4>诉讼时效</h4>\n<p>《民法通则》第七章《诉讼时效》可读性不是很好，\n这是法律文本结构的限制。\n法律文本只有章、条、项这些东西，表达力是很差的。\n所以有时候把法律文本改写成表格、流程图或者伪代码要容易理解一点。\n另外，改成伪代码也更容易暴露法条中一些含糊的地方\n（其中包括法条本身表述不明确及表述明确但自己没理解两种情况）。</p>\n<pre><code>class 民事权利 {\n    private Period 诉讼时效;\n    private Period 完整诉讼时效;\n    LocalDate 知道或应当知道被侵权;\n    LocalDate 被侵权;\n    boolean 当事人自愿履行;\n\n    public 民事权利(LocalDate 知道, LocalDate 被侵, boolean 自愿) {\n        this.完整诉讼时效 = Period.ofYears(2);\n        this.诉讼时效 = this.完整诉讼时效;\n        this.知道或应当知道被侵权 = 知道;\n        this.被侵权 = 被侵;\n        this.当事人自愿履行 = 自愿;\n    }\n\n    public Period get诉讼时效() {\n        return this.诉讼时效;\n    }\n    public void set诉讼时效(Period p) {\n        this.诉讼时效 = p;\n    }\n\n    public boolean is有效期内() {\n        if (当事人自愿履行) {\n            return true;\n        }\n        else {\n            // 民法通则 s. 137 规定有特殊情况的，人民法院可以延期。\n            // 实际诉讼中这个一般要援引司法解释具体 patch 的情况才能延期。\n            // 因此下面不考虑这个情况。\n            LocalDate today = LocalDate.now();\n            // 1988 年最高法关于执行通则的意见明确了 20 年期限不适用中止、中断的规定。(s. 175)\n            if (Period.between(被侵权, today) > Period.ofYears(20)) {\n                return false;\n            } else if (Period.between(知道或应当知道被侵权, today) > this.诉讼时效) {\n                return false;\n            } else {\n                return true;\n            }\n        }\n    }\n\n    public boolean 中止(boolean 因不可抗力或其他障碍无法行使请求权,\n                        LocalDate 中止原因消除) {\n        if (因不可抗力或其他障碍无法行使请求权) {\n            if (诉讼时效 &#x3C;= Period.ofMonths(6)) {\n                Period 中止期间 = Period.between(LocalDate.now(), 中止原因消除);\n                this.诉讼时效 += 中止期间;\n                return true;\n            } else {\n                return false;\n            }\n        } else {\n            return false;\n        }\n    }\n\n    public boolean 中断(boolean 提起诉讼, boolean 提出要求, boolean 同意履行) {\n        if (提起诉讼 || 提出要求 || 同意履行) {\n            this.诉讼时效 += this.完整诉讼时效;\n            return true;\n        } else {\n            return false;\n        }\n    }\n}\n\nclass 身体伤害 extends 民事权利 {\n    public 身体伤害(LocalDate 知道, LocalDate 被侵, boolean 自愿) {\n        super(知道，被侵，自愿);\n        this.完整诉讼时效 = Period.ofYears(1);\n        this.诉讼时效 = this.完整诉讼时效;\n    }\n}\n// 同理可定义 `class 质量不合格商品`, `class 延付拒付租金`, `class 寄存财物丢失损毁`，\n// 此处省略。\n\nabstract class 另有规定 extends 民事权利 {\n    @Override public boolean is有效期内();\n}\n</code></pre>\n<h2>Patch</h2>\n<p>法律文本的麻烦之处是 Patch 是分开来发表的，\n而且后来的 Patch 并不包括以前的 Patch.</p>\n<p>因此工具书很重要。</p>\n<p>同理，不建议直接看法条。</p>\n<p>如果一时找不到靠谱的工具书，不得已直接读法条，\n那要保持高度警惕，特别要注意 2 点：</p>\n<h3>1. 含糊的地方。</h3>\n<p>比如《民法通则》s. 153</p>\n<blockquote>\n<p>本法所称的「不可抗力」，是指不能预见、不能避免并不能克服的客观情况。</p>\n</blockquote>\n<p>这句话是很含糊的。\n阅读判例的时候可以帮助理解法官的思路，\n但想凭此主张自己不承担责任难度很大。\n还是要找细法里的具体规定以及司法解释。</p>\n<h3>2. 过时的地方。</h3>\n<p>比如 1988 年最高法出的执行民法通则的意见第 118 条规定：</p>\n<blockquote>\n<p>出租人出卖出租房屋，应提前三个月通知承租人，\n承租人在同等条件下，享有优先购买权;\n出租人未按此规定出卖房屋的，承租人可以请求人民法院宣告该房屋买卖无效。</p>\n</blockquote>\n<p>1988 年时候房屋买卖还不频繁。而现在房屋买卖是很频繁的。\n同时，有些地方因为房价波动厉害，因此往往希望尽快成交。\n要求每笔买卖都拖上 3 个月并不符合现在的实际情况。</p>\n<p>因此 2009 最高法就出 patch 更新了，先把 3 个月改成了更灵活的「合理期限」，\n其次把没有及时通知的违约责任由买卖无效改成了赔偿损失。\n（最高人民法院关于审理城镇房屋租赁合同纠纷案件具体应用法律若干问题的解释, s. 21）</p>","date_published":"Fri, 15 Sep 2017 10:10:30 GMT","date_modified":"Sat, 23 Nov 2019 19:16:00 GMT"},{"id":"https://mmap.page/cli/test/","url":"https://mmap.page/cli/test/","title":"Command Line Interface Testing","content_html":"<h1>Command Line Interface Testing</h1>\n<h2><a href=\"https://github.com/lehmannro/assert.sh\">assert.sh</a></h2>\n<p>Example:</p>\n<pre><code class=\"language-sh\"><span class=\"pl-c1\">.</span> assert.sh\n\n<span class=\"pl-c\"># `echo test` is expected to write \"test\" on stdout</span>\nassert <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>echo test<span class=\"pl-pds\">\"</span></span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>test<span class=\"pl-pds\">\"</span></span>\n<span class=\"pl-c\"># exit code of `true` is expected to be 0</span>\nassert_raises <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>true<span class=\"pl-pds\">\"</span></span>\n<span class=\"pl-c\"># exit code of `false` is expected to be 1</span>\nassert_raises <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>false<span class=\"pl-pds\">\"</span></span> 1\n<span class=\"pl-c\"># end of test suite</span>\nassert_end examples\n</code></pre>\n<p>Pros:</p>\n<ul>\n<li>simple (only <code>assert</code>, <code>assert_raises</code> and <code>assert_end</code>)</li>\n<li>light weight (just <code>source assert.sh</code>)</li>\n</ul>\n<p>Cons:</p>\n<ul>\n<li>It can only match result exactly, no support for \"output should contains ...\" like function.</li>\n<li>No setup/teardown.</li>\n</ul>\n<p>You can <a href=\"https://github.com/lehmannro/assert.sh/issues/10\">implement your own</a> <code>assert_contains</code> function.</p>\n<h2><a href=\"https://github.com/thinkerbot/ts\">ts</a></h2>\n<p>It is similar to assert.sh.</p>\n<p>Differences:</p>\n<ul>\n<li><code>setup ()</code> and <code>teardown ()</code>.</li>\n<li>Every test is a function. <code>exit 0</code> to pass tests.</li>\n</ul>\n<h2><a href=\"http://bmizerany.github.io/roundup\">roundup</a></h2>\n<p>Example:</p>\n<pre><code class=\"language-sh\"><span class=\"pl-c\">#!/usr/bin/env roundup</span>\n\ndescribe <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>group tests<span class=\"pl-pds\">\"</span></span>\n\n<span class=\"pl-en\">it_displays_the_title</span>() {\n    first_line=<span class=\"pl-s\"><span class=\"pl-pds\">$(</span>rup roundup-5 <span class=\"pl-k\">|</span> head -n 1<span class=\"pl-pds\">)</span></span>\n    <span class=\"pl-c1\">test</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span><span class=\"pl-smi\">$first_line</span><span class=\"pl-pds\">\"</span></span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>=<span class=\"pl-pds\">\"</span></span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>roundup(5)<span class=\"pl-pds\">\"</span></span>\n}\n\n<span class=\"pl-en\">it_exists_non_zero</span>() {\n    status=<span class=\"pl-s\"><span class=\"pl-pds\">$(</span>set +e <span class=\"pl-k\">;</span> rup roundup-5 <span class=\"pl-k\">></span>/dev/null <span class=\"pl-k\">;</span> <span class=\"pl-c1\">echo</span> <span class=\"pl-smi\">$?</span><span class=\"pl-pds\">)</span></span>\n    <span class=\"pl-c1\">test</span> 2 -eq <span class=\"pl-smi\">$status</span>\n}\n\n<span class=\"pl-en\">it_survives_edge_cases</span>() {\n    rup edge\n}\n</code></pre>\n<p>Differences to assert.sh:</p>\n<ul>\n<li>Use <code>describe</code> at the beginning of a test group instead of <code>assert_end</code> in the end.</li>\n<li>Put tests in functions.</li>\n</ul>\n<p>I think these differences add readability.</p>\n<p>Cons are similar to assert.sh.</p>\n<h2><a href=\"https://github.com/roman-neuhauser/rnt\">rnt</a></h2>\n<p>Save output of commands to <code>*.actual</code>, then compare them with <code>*.expected</code> via <code>diff</code>.</p>\n<p>Cons are similar to assert.sh, plus:</p>\n<ul>\n<li>Separate expected output with the corresponding command.</li>\n<li>A lot of tests lead to complex directory structure.</li>\n</ul>\n<h2><a href=\"http://liw.fi/cmdtest/\">cmdtest</a></h2>\n<p>Like rnt, cmdtest also uses a lot of files.\nBut it adds support for standard error and setup/teardown.</p>\n<pre><code>   foo.script\n          a script to run the test (this is required)\n\n   foo.stdin\n          the file fed to standard input\n\n   foo.stdout\n          the expected output to the standard output\n\n   foo.stderr\n          the expected output to the standard error\n\n   foo.exit\n          the expected exit code\n\n   foo.setup\n          a shell script to run before the test\n\n   foo.teardown\n          a shell script to run after test\n\n   setup-once\n          a shell script to run once, before any tests\n\n   setup  a shell script to run before each test\n\n   teardown\n          a shell script to run after each test\n\n   teardown-once\n          a shell script to run once, after all tests\n</code></pre>\n<p>Cons:</p>\n<ul>\n<li>No support for \"output should contains ...\" like function.</li>\n<li>Separate expected output with the corresponding command.</li>\n<li>A lot of tests lead to complex directory structure.</li>\n</ul>\n<h2><a href=\"https://github.com/tlevine/urchin\">urchin</a></h2>\n<p>urchin is similar to rnt, but it does use separate output files.\nInstead, <code>exit 0</code> passes tests.</p>\n<pre><code>tests/\n  setup\n  setup_dir\n  bar/\n    setup\n    test_that_something_works\n    teardown\n  baz/\n    jack-in-the-box/\n      setup\n      test_that_something_works\n      teardown\n    cat-in-the-box/\n      fixtures/\n        things.pdf\n      test_thingy\n  teardown\n</code></pre>\n<p>Cons are similar to rnt except for 'Separate expected output'.</p>\n<h2><a href=\"https://bitheap.org/cram/\">Cram</a></h2>\n<p>Tests look like documents:</p>\n<pre><code>This is a comment.\n\n  $ echo 'Lines beginning with two space followed by $ is a test.'\n  $ echo 'Multiline test\n  > exit 0 passes tests.'\n\n  $ cram -h\n  [Uu]sage: cram \\[OPTIONS\\] TESTS\\.\\.\\. (re)\n\n  [Oo]ptions: (re)\n    -h, --help          show this help message and exit\n    -V, --version       show version information and exit\n    -q, --quiet         don't print diffs\n    -v, --verbose       show filenames and test status\n    -i, --interactive   interactively merge changed test output\n    -y, --yes           answer yes to all questions\n    -n, --no            answer no to all questions\n    -E, --preserve-env  don't reset common environment variables\n    --keep-tmpdir       keep temporary directories\n    --shell=PATH        shell to use for running tests\n    --indent=NUM        number of spaces to use for indentation\n\nLines beginning with two space not followed by $ or > is output.\nOutput lines ending with a space and (re) are matched against PCRE.\n</code></pre>\n<p>Cons:</p>\n<ul>\n<li>No setup/teardown.</li>\n<li><code>(re)</code> only matches a single line.</li>\n</ul>\n<h2><a href=\"http://joyful.com/shelltestrunner/\">shelltestrunner</a></h2>\n<pre><code class=\"language-sh\"><span class=\"pl-c\"># optional comment</span>\na one-line shell <span class=\"pl-c1\">command</span>\n&#x3C;&#x3C;&#x3C;\nzero or more lines of standard input\n>>>\nzero or more lines of expected standard output (or /REGEXP/ added to the previous line)\n>>>2\nzero or more lines of expected standard error output (or /REGEXP/ added to the previous line)\n>>>= STATUS (or /REGEXP/)\n</code></pre>\n<p>Cons:</p>\n<ul>\n<li>No setup/teardown.</li>\n</ul>\n<h2><a href=\"https://github.com/mpapis/tf\">tf</a></h2>\n<p>Example:</p>\n<pre><code class=\"language-tf\"><span class=\"pl-c\">## User comments start with double #</span>\n<span class=\"pl-c\">## command can be writen in one line with multiple tests:</span>\n<span class=\"pl-c1\">true</span> <span class=\"pl-c\"># status=0; match=/^$/</span>\n<span class=\"pl-c\">## or tests can be placed in following lines:</span>\n<span class=\"pl-c1\">false</span>\n<span class=\"pl-c\"># status=1</span>\n</code></pre>\n<p>Cons:</p>\n<ul>\n<li>No setup/teardown.</li>\n<li>Syntax: <code>env[]=~//</code>, <code>env[]?=</code>, <code>env[][]=</code>, etc.</li>\n</ul>\n<h2><a href=\"https://hg.reactionary.software/repo/bricolage/\">Bricolage</a></h2>\n<p>Example:</p>\n<pre><code class=\"language-sh\"><span class=\"pl-c\"># A test is a function. $T is a variable where test keeps its internal files</span>\n<span class=\"pl-en\">mytest</span>() {\n    <span class=\"pl-c\"># ok is the only assertion helper</span>\n    <span class=\"pl-c\"># It uses `test` to check the condition, so syntax is common</span>\n    ok 1 -eq 1\n    ok foo = foo\n    foo=<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>Foo bar<span class=\"pl-pds\">\"</span></span>\n    ok <span class=\"pl-s\"><span class=\"pl-pds\">\"</span><span class=\"pl-smi\">$foo</span><span class=\"pl-pds\">\"</span></span> = <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>Foo bar<span class=\"pl-pds\">\"</span></span>\n\n    <span class=\"pl-c\"># You can use `spy` to make a wrapper over a command.</span>\n    spy date\n\n    date\n\n    <span class=\"pl-c\"># Command output will be written into &#x3C;spy>.stdout file:</span>\n    ok <span class=\"pl-s\"><span class=\"pl-pds\">\"$(</span>cat <span class=\"pl-smi\">$T</span>/spy.date.stdout<span class=\"pl-pds\">)\"</span></span> = <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>foo<span class=\"pl-pds\">\"</span></span>\n\n    <span class=\"pl-c\"># Fake spy output can be specified in the &#x3C;spy> file:</span>\n    <span class=\"pl-c1\">echo</span> foo <span class=\"pl-k\">></span> <span class=\"pl-smi\">$T</span>/spy.date\n    date\n\n    <span class=\"pl-c\"># You can assert it using tail, sed, awk and other common unix tools</span>\n    ok <span class=\"pl-s\"><span class=\"pl-pds\">\"$(</span>tail -n 1 <span class=\"pl-smi\">$T</span>/spy.date.stdout<span class=\"pl-pds\">)\"</span></span> = <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>foo<span class=\"pl-pds\">\"</span></span>\n}\n\n<span class=\"pl-c\"># You may override test reports as you need</span>\n<span class=\"pl-en\">pass</span>() { <span class=\"pl-c1\">echo</span> PASS <span class=\"pl-smi\">$*</span> }\n<span class=\"pl-en\">fail</span>() { <span class=\"pl-c1\">echo</span> FAIL <span class=\"pl-smi\">$*</span> }\n\n<span class=\"pl-c\"># You have to run your tests manually</span>\nbricolage mytest\n\n<span class=\"pl-c\"># Clean test data</span>\nrm -rf <span class=\"pl-smi\">$T</span>\n</code></pre>\n<p>Pros:</p>\n<ul>\n<li>Extremely small (50 LOC).</li>\n<li>Ultimately minimal.</li>\n</ul>\n<p>Cons:</p>\n<ul>\n<li>Ultimately minimal.</li>\n</ul>","date_published":"Thu, 24 Aug 2017 14:15:21 GMT","date_modified":"Thu, 24 Jul 2025 12:16:07 GMT"},{"id":"https://mmap.page/dive-into/ruby/","url":"https://mmap.page/dive-into/ruby/","title":"Quirks of Ruby","content_html":"<h1>Quirks of Ruby</h1>\n<h2>Foreword</h2>\n<p>Ruby advertises its \"The Least Surprise\" principle.\nIf you are unsure about something on Ruby,\nyou can guess and try, and it usually works,\nexcept for some quirks mentioned below.</p>\n<p>If you prefer reading a tutorial before diving into Ruby,\nI would recommend <a href=\"http://poignant.guide/\">why's guide to Ruby</a>,\nwhich may be outdated,\nbut definitely poignant.</p>\n<h2><code>begin ... end while</code></h2>\n<pre><code class=\"language-ruby\"><span class=\"pl-k\">begin</span> <span class=\"pl-c1\">puts</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>code executed<span class=\"pl-pds\">\"</span></span> <span class=\"pl-k\">end</span> <span class=\"pl-k\">while</span> <span class=\"pl-c1\">false</span>\n<span class=\"pl-c1\">puts</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>code not executed<span class=\"pl-pds\">\"</span></span> <span class=\"pl-k\">while</span> <span class=\"pl-c1\">false</span>\n</code></pre>\n<p>This is really anti-intuitive.\nAnd the creator of Ruby said not using this.</p>\n<blockquote>\n<p>Don't use it please. I'm regretting this feature,\nand I'd like to remove it in the future if it's possible.</p>\n</blockquote>\n<p>-- <a href=\"http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/6745\">matz</a></p>\n<p>Unfortunately, this feature still exists in Ruby 3.3.</p>\n<h2><code>Proc.new</code></h2>\n<p>The <code>return</code> statement in proc created by <code>Proc.new</code> will not only return control just from itself, but <strong>also from the method enclosing it</strong>.</p>\n<pre><code class=\"language-ruby\"><span class=\"pl-k\">def</span> <span class=\"pl-en\">some_method</span>\n\tmyproc <span class=\"pl-k\">=</span> <span class=\"pl-c1\">Proc</span>.<span class=\"pl-k\">new</span> {<span class=\"pl-k\">return</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>End.<span class=\"pl-pds\">\"</span></span>}\n\tmyproc.call\n\n\t<span class=\"pl-c1\">puts</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>This will not get executed!<span class=\"pl-pds\">\"</span></span>\n<span class=\"pl-k\">end</span>\nsome_method\n</code></pre>\n<p>Well, you can argue that <code>Proc.new</code> inserts code into the enclosing method, just like block.\nBut <code>Proc.new</code> creates an object, while block are <em>part of</em> an object.</p>\n<p>And there is another difference between lambda and <code>Proc.new</code>.\nThat is their handling of (wrong) arguments.\nLambda complains about it, while <code>Proc.new</code> ignores extra arguments or considers absence of arguments as nil.</p>\n<pre><code>irb(main):021:0> l = -> (x) { x.to_s }\n=> #&#x3C;Proc:0x8b63750@(irb):21 (lambda)>\nirb(main):022:0> p = Proc.new { |x| x.to_s}\n=> #&#x3C;Proc:0x8b59494@(irb):22>\nirb(main):025:0> l.call\nArgumentError: wrong number of arguments (0 for 1)\n        from (irb):21:in `block in irb_binding'\n        from (irb):25:in `call'\n        from (irb):25\n        from /usr/bin/irb:11:in `&#x3C;main>'\nirb(main):026:0> p.call\n=> \"\"\nirb(main):049:0> l.call 1, 2\nArgumentError: wrong number of arguments (2 for 1)\n        from (irb):47:in `block in irb_binding'\n        from (irb):49:in `call'\n        from (irb):49\n        from /usr/bin/irb:11:in `&#x3C;main>'\nirb(main):050:0> p.call 1, 2\n=> \"1\"\n</code></pre>\n<p>BTW, <code>proc</code> in Ruby 1.8 creates a lambda, while in Ruby 1.9+ behaves like <code>Proc.new</code>, really confusing.</p>\n<h2><code>def</code> does not create closures.</h2>\n<p>Closures are simple in Python:</p>\n<pre><code class=\"language-python\"><span class=\"pl-k\">def</span> <span class=\"pl-en\">a</span>(<span class=\"pl-smi\">x</span>):\n  <span class=\"pl-k\">def</span> <span class=\"pl-en\">b</span>():\n    <span class=\"pl-k\">return</span> x\n  b()\n</code></pre>\n<p>This won't work in Ruby.</p>\n<pre><code class=\"language-ruby\"><span class=\"pl-k\">def</span> <span class=\"pl-en\">a</span>(<span class=\"pl-smi\">x</span>)\n  <span class=\"pl-k\">def</span> <span class=\"pl-en\">b</span>\n    x\n  <span class=\"pl-k\">end</span>\n  b\n<span class=\"pl-k\">end</span>\na(<span class=\"pl-c1\">1</span>) <span class=\"pl-c\"># in `b': undefined local variable or method `x' for main (NameError)</span>\n</code></pre>\n<p>In Ruby, <code>def</code> starts a new scope, without access to outer variables.\nOnly <code>@var</code> and <code>$var</code> can be accessed.\nAnd no <code>extern</code> keyword like in C.</p>\n<p>Lambda and <code>define_method</code> do create closure though:</p>\n<pre><code class=\"language-ruby\"><span class=\"pl-k\">def</span> <span class=\"pl-en\">a</span>(<span class=\"pl-smi\">x</span>)\n  b <span class=\"pl-k\">=</span> <span class=\"pl-c1\">-></span>{ x }\n  b.call\n<span class=\"pl-k\">end</span>\na(<span class=\"pl-c1\">1</span>) <span class=\"pl-c\"># 1</span>\n\n<span class=\"pl-k\">def</span> <span class=\"pl-en\">c</span>(<span class=\"pl-smi\">x</span>)\n  define_method(<span class=\"pl-c1\">:d</span>) { x }\n  d\n<span class=\"pl-k\">end</span>\nc(<span class=\"pl-c1\">1</span>) <span class=\"pl-c\"># 1</span>\n</code></pre>\n<p>In Ruby 1.9, <code>define_method</code> is not available in main Object, you can\nuse <code>define_singleton_method</code> instead.</p>","date_published":"Thu, 24 Aug 2017 14:08:34 GMT","date_modified":"Mon, 14 Jul 2025 20:20:32 GMT"},{"id":"https://mmap.page/dive-into/pry/","url":"https://mmap.page/dive-into/pry/","title":"Dive into Pry","content_html":"<h1>Dive into Pry</h1>\n<p><strong>This note was written for Ruby &#x3C; 2.0, thus outdated now.</strong></p>\n<h2>Input</h2>\n<ul>\n<li><code>!</code>: clear input buffer</li>\n<li><code>code;</code>: suppress evaluation output, useful when it's long or uninterested.</li>\n<li><code>amend-line N replacement code</code>: to amend lines of input. Use <code>!</code> for replacement to delete. You can use <code>show-input</code> to get line numbers.</li>\n<li><code>.shellcommad #{ruby code}</code></li>\n</ul>\n<h2>Special locals</h2>\n<ul>\n<li><code>_</code>: last result</li>\n<li><code>_ex_</code>: the most recently caught exception</li>\n<li><code>_in_</code> and <code>_out_</code>: Input expressions and output results are automatically stored in array-like data structures.</li>\n<li><code>_file_</code> and <code>_dir_</code>: last file and last directory</li>\n<li><code>_pry_</code>: current Pry instance</li>\n</ul>\n<h2>Browsing code</h2>\n<p>Use <code>cd</code> to move into an object or scope.\nAs in UNIX shells use <code>cd ..</code> to go\nback, <code>cd /</code> to return to Pry top-level and <code>cd -</code> to toggle between last two\nscopes. Complex syntax (e.g <code>cd ../@x/@y</code>) also supported.</p>\n<p>Use <code>whereami</code>(alias <code>@</code>) to show code surrounding the current context.</p>\n<p>Use <code>show-source</code>(alias <code>$</code> or <code>show-method</code>) and <code>show-code</code>(alias <code>?</code>).</p>\n<p>Use <code>find-method</code> to recursively search for a method within a class/module or the current namespace.</p>\n<p>Use <code>stat method_name</code> for basic method information.</p>\n<p>Use <code>ls</code> to get a list of variables in current scope\nYou can also use <code>ls Class/Module</code>, or <code>ls variable</code>.</p>\n<p>Use <code>watch</code> to watch the value of an expression and print a notification whenever it changes.</p>\n<p><code>cat</code> automatic syntax highlighting for a number of file types.</p>\n<p><code>cat</code> accepts the following options:</p>\n<ul>\n<li><code>--[l]inenumbers</code> causes line numbers to be displayed along side each line.</li>\n<li><code>--[t]ype</code>: syntax highlight type</li>\n<li><code>--[s]tart</code> and <code>--[e]nd</code>: the line of the file with which to begin/end</li>\n<li><code>--ex</code>: last exception</li>\n<li><code>--in</code>: one or more entries from Pry's expression history (default: -5..-1)</li>\n</ul>\n<h2>Editing code</h2>\n<p><code>edit</code> brings you to <code>EDITOR</code>.\nIt accepts the following options:</p>\n<ul>\n<li><code>-c</code>: current file/line</li>\n<li><code>my_method</code>: method in the scope</li>\n<li><code>Class#a_method</code> or <code>Class.a_class_method</code></li>\n<li><code>&#x3C;filename></code> or <code>&#x3C;filename>:&#x3C;line-number></code></li>\n<li><code>--in 1..2</code>: a range of the Pry input buffer</li>\n<li><code>-t</code>: open a temporary empty file in an editor</li>\n<li><code>--ex</code>: the relevant file at the line that generated the last exception</li>\n<li><code>--ex N</code>: the Nth line of the backtrace</li>\n<li><code>-l</code>: jump to the specified line number</li>\n<li><code>-n</code>: stop the automatic reloading of <code>.rb</code> files after you have edited them</li>\n<li><code>-r</code>: force Pry to reload and eval a file, even if it does not end in <code>.rb</code></li>\n</ul>\n<p>Being run without any arguments, the <code>edit</code> command modifies the last input expression.</p>\n<h2>History</h2>\n<p><code>hist</code> to display Pry history.</p>\n<p>It accepts the following options:</p>\n<ul>\n<li><code>--grep REGEX</code></li>\n<li><code>--exclude</code>: when displaying history, exclude pry commands</li>\n<li><code>--tail N</code> and <code>--head N</code>: <code>N</code> defaults to 10</li>\n<li><code>--no-numbers</code> or <code>-n</code>: turns off line numbers when displaying history</li>\n<li><code>--show A..B</code></li>\n<li><code>--replay A..B</code>: replay lines of history.</li>\n<li><code>--save [A..B] FILE</code>: save to a file</li>\n<li><code>--clear</code>: clear all current session history</li>\n</ul>\n<h2>Debug</h2>\n<p>Write <code>binding.pry</code> as a breakpoint in your code. When executing, it\nwill stop here and open a Pry console.</p>\n<h2>Gems</h2>\n<ul>\n<li><code>gem-cd</code> Change working directory to specified gem's directory.</li>\n<li><code>gem-install</code> Install a gem and refresh the gem cache.</li>\n<li><code>gem-list</code> List and search installed gems.</li>\n<li><code>gem-open</code> Opens the working directory of the gem in your editor.</li>\n</ul>\n<h2>Customization</h2>\n<p>For current session:</p>\n<pre><code class=\"language-ruby\"><span class=\"pl-c1\">Pry</span>.config.[option]\n</code></pre>\n<p>You can store <code>Pry.config.[option]</code> in <code>.pryrc</code> (project or global <code>~/.pryrc</code>).</p>\n<h2>Plugins</h2>\n<h3>pry-byebug</h3>\n<p>Use <code>byebug</code> (Ruby debugger) with pry.</p>\n<p>I don't use it due to <a href=\"https://github.com/deivid-rodriguez/pry-byebug/issues/44\">this bug</a>.\nBesides, most of time, I just need pry-rescue.</p>\n<h2>pry-coolline</h2>\n<p>By default, code gets highlighted after you end your input.\nThis plugin supports real time highlight.</p>\n<h2>pry-macro</h2>\n<p>Record and play macros.\nYou can save macros to a file.</p>\n<h3>pry-rescue</h3>\n<p>Whenever an unhandled exception happens in your program, pry-rescue opens an interactive pry shell right at the point it was raised.</p>\n<p>Install it together with <code>pry-stack_explorer</code>, then run <code>rescue file.rb</code> instead of <code>ruby file.rb</code>.</p>\n<p>In the rescue Pry session, use <code>up</code> and <code>down</code> to move around the stack, and use <code>wtf?</code> or <code>cat --ex</code> to examine stack traces and the associated code.\nAfter identifying the problem, use <code>edit-method</code> (alias <code>$</code>) to fix the code, and <code>try-again</code> to verify the fix worked.</p>\n<p><code>cd-cause</code> lets you rewind back the previously raised exception. So, if you've rescued one exception, and then raised another (it happens…) you can jump back to the original cause of the problem.</p>\n<p>You can also call <code>Pry::rescue</code> to control over which parts of your code are rescued:</p>\n<pre><code class=\"language-ruby\"><span class=\"pl-k\">require</span> <span class=\"pl-s\"><span class=\"pl-pds\">'</span>pry-rescue<span class=\"pl-pds\">'</span></span>\n\n<span class=\"pl-k\">def</span> <span class=\"pl-en\">test</span>\n  <span class=\"pl-k\">raise</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>foo<span class=\"pl-pds\">\"</span></span>\n<span class=\"pl-k\">rescue</span> => e\n  <span class=\"pl-k\">raise</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>bar<span class=\"pl-pds\">\"</span></span>\n<span class=\"pl-k\">end</span>\n\n<span class=\"pl-c1\">Pry</span>.rescue <span class=\"pl-k\">do</span>\n  <span class=\"pl-c1\">test</span>\n<span class=\"pl-k\">end</span>\n</code></pre>\n<p>You can also use <code>Pry::rescue</code> in the <code>rescue</code> clause:</p>\n<pre><code class=\"language-ruby\"><span class=\"pl-k\">def</span> <span class=\"pl-en\">test</span>\n  <span class=\"pl-k\">raise</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>foo<span class=\"pl-pds\">\"</span></span>\n<span class=\"pl-k\">rescue</span> => e\n  <span class=\"pl-c1\">Pry</span>::rescued(e)\n<span class=\"pl-k\">end</span>\n\n<span class=\"pl-c1\">Pry</span>::<span class=\"pl-k\">rescue</span>{ <span class=\"pl-c1\">test</span> }\n</code></pre>\n<h4>Testing</h4>\n<h5>rspec</h5>\n<pre><code class=\"language-sh\">rescue rspec\n</code></pre>\n<h5>MiniTest</h5>\n<p>Add the following to your <code>test_helper.rb</code> or to the top of your test file</p>\n<pre><code class=\"language-ruby\"><span class=\"pl-k\">require</span> <span class=\"pl-s\"><span class=\"pl-pds\">'</span>minitest/autorun<span class=\"pl-pds\">'</span></span>\n<span class=\"pl-k\">require</span> <span class=\"pl-s\"><span class=\"pl-pds\">'</span>pry-rescue/minitest<span class=\"pl-pds\">'</span></span>\n</code></pre>\n<p>It works perfectly with <code>yard-doctest</code> in terminal, but not is\nsublime-text.</p>\n<h2>Themes</h2>\n<p>In a pry session, run <code>pry-theme list</code> to list all installed themes.</p>\n<p>Try a theme:</p>\n<pre><code class=\"language-sh\">pry-theme try pry-modern-256\n</code></pre>\n<p>If the theme is not installed, you can install it:</p>\n<pre><code class=\"language-sh\">pry-theme install theme-name\n</code></pre>\n<p>You can use <code>uninstall</code> to uninstall it.</p>\n<p>Show current theme:</p>\n<pre><code class=\"language-sh\">pry-theme current\n</code></pre>\n<p>You can edit a theme:</p>\n<pre><code class=\"language-sh\">pry-theme edit\n</code></pre>\n<p>After you have decided your theme, write it in <code>.pryrc</code>:</p>\n<pre><code class=\"language-ruby\"><span class=\"pl-c1\">Pry</span>.config.theme <span class=\"pl-k\">=</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>pry-modern-256<span class=\"pl-pds\">\"</span></span>\n</code></pre>\n<p>You can get more themes at <a href=\"https://github.com/kyrylo/pry-theme-collection\">Pry theme collection</a>.</p>","date_published":"Thu, 24 Aug 2017 14:05:03 GMT","date_modified":"Sun, 23 Apr 2023 04:25:20 GMT"},{"id":"https://mmap.page/dive-into/gh-pages/","url":"https://mmap.page/dive-into/gh-pages/","title":"Build a Micro Static Site With GitHub Pages","content_html":"<h1>Build a Micro Static Site With GitHub Pages</h1>\n<h2>tl;tr</h2>\n<p>In repository settings, enable GitHub Pages for the <code>master</code> branch.</p>\n<p>Now you can access your site at <code>https://your-username.github.io/your-repo-name</code></p>\n<p>Done. Period.</p>\n<h2>How</h2>\n<p>GitHub Pages will use <code>README.md</code> as index page.\nAnd your project probably already have one.\nThere is no need to write <code>index.html</code> or <code>index.md</code>.</p>\n<h2>Why</h2>\n<p>Focus on content, not the site design and configuration.</p>\n<p>We use <code>README.md</code> and <code>master</code> branch.\nThis makes updating project site easier.\nJust update <code>README.md</code> without the hassles of sync documentation between <code>master</code> and <code>gh-pages</code> branches.</p>\n<h2>Bonus</h2>\n<p>Your project may have some additional documentary pages.\nThey are welcome by GitHub Pages.</p>\n<p>For example:</p>\n<pre><code>README.md\n...\ndocs/\n    README.md\n    quick-start.md\n    install/\n        linux.md\n        osx.md\n        bsd.md\n        win.md\n</code></pre>\n<p>URL paths will be:</p>\n<pre><code>/index.html\n/docs\n/docs/quick-start.html\n/docs/install/linux.html\n/docs/install/osx.html\n/docs/install/bsd.html\n/docs/install/win.html\n</code></pre>\n<p>And you can link them as <code>[quick start](quick-start.md)</code>,\nso the link will work on both GitHub and GitHub Pages.</p>\n<h2>Conclusion</h2>\n<p>Yes. You can have a site powered by GitHub Page up and running\nwithout writing a single line of\nyaml configuration, html template, css, javascript, etc.</p>","date_published":"Thu, 24 Aug 2017 14:04:26 GMT","date_modified":"Wed, 26 Apr 2023 09:13:36 GMT"},{"id":"https://mmap.page/dive-into/flow/","url":"https://mmap.page/dive-into/flow/","title":"Dive into Flow","content_html":"<h1>Dive into Flow</h1>\n<h2>Peek at the type system</h2>\n<ul>\n<li>Nullability. Maybe type <code>?T</code> is <code>T|null|void</code>.</li>\n<li>Optional object properties and function parameters are typed <code>T|void</code>,\ne.g. <code>function optional_parameter(p?: string) { (p: string|void) }</code>.</li>\n<li>Function parameters with a default value are typed <code>T|void</code> for callers but <code>T</code> in function body.</li>\n<li><code>any</code> is unchecked (supertype <em>and</em> subtype of all types),\n<code>mixed</code> is <code>Any</code> in other languages,\n<code>Object</code> is a supertype of all object types including functions,\nnot including primitive types and array types.\nand <code>Function</code> is a supertype of all functions.</li>\n<li>Flow does not do bound checking for arrays.\nThis means <code>[J, K]</code> is actually <code>[J, K, any...]</code>.\nThis is less strict than TypeScript.</li>\n<li>Object is also structural typed, but they have nominal alternatives <code>{| p: T |}</code>.</li>\n<li>Objects can be invariant(default), covariant(<code>{+p: T}</code>), or contravariant (<code>{-p: T}</code>).\nGenerics use the same variance syntax.</li>\n<li>Functions are modeled as object type with a callable property.</li>\n<li>Interfaces uses structural typing like Go.</li>\n<li>For a class <code>C</code>, <code>C</code> is its instance type, and its class type is <code>Class&#x3C;C></code>.</li>\n<li>Array types are invariant to element type.</li>\n<li>Rest parameters are annotated with an array type, e.g. <code>...xs: number[]</code>.</li>\n<li>Object type can include a callable property, e.g. <code>(...xs: number[]): number</code>,\nwhich allows values of that type be called like a function,\nand an indexer property, e.g. <code>[x: number]: string</code>,\nwhich allows values of that type to be used like a dictionary.</li>\n<li>Type aliases, interfaces, <code>import type</code> and <code>export type</code> are entirely erased at compile time.</li>\n<li>Destructing are annotated as a whole,\ne.g. <code>let {a, b: {c}}: {a: string, b: {c: number}} = {a: \"\", b: {c: 0}};</code></li>\n<li>Type casting uses the same syntax as type annotation <code>e: T</code>.</li>\n<li><code>typeof e</code> in type annotation represents the type of <code>e</code>.</li>\n</ul>\n<h2>Built-in types</h2>\n<h3>Boolean</h3>\n<p>JavaScript specifies many implicit conversions,\nwhich provide boolean semantics to values of other types.\nFlow allows this in conditional of <code>if</code> statements etc.</p>\n<p>Note that in JavaScript <code>Boolean(0)</code> and <code>new Boolean(0)</code> are different.\nThe formal is converting <code>0</code> to the <code>boolean</code> primitive type via the <code>Boolean</code> function,\nthe later is initialize a <code>Boolean</code> wrapped object, which is rarely used.\nSame thing applies to <code>number</code>/<code>Number</code> and <code>string</code>/<code>String</code>.</p>\n<h3>Number</h3>\n<p>JavaScript has a single number type, which is IEEE 754 floating point numbers.</p>\n<h3>Literal types</h3>\n<p><code>true</code>, <code>false</code>, any <code>number</code>, and any <code>string</code> is a literal type.</p>\n<p><code>let wrong: false = true &#x26;&#x26; false</code> is valid\nsince a type checker can infer that for <code>t</code> typed <code>true</code> and <code>f</code> typed <code>false</code>, <code>t &#x26;&#x26; f</code> is typed <code>false</code>,\njust like a type checker can infer that for <code>m</code> and <code>n</code> typed <code>number</code>, <code>m + n</code> is typed <code>number</code>.\nUnlike boolean, literal types of number and string has infinite members,\na type checker cannot infer if the sum of two number typed as literal type has another specific literal type.\nSo <code>let two: 2 = 1 + 1</code> is invalid.</p>\n<h2>Declaration files</h2>\n<p>Flow's declaration files are like C's header files.</p>\n<p>A declaration file of <code>foo.js</code> is named <code>foo.js.flow</code>:</p>\n<pre><code class=\"language-js\"><span class=\"pl-c\">/* @flow */</span>\n\ndeclare <span class=\"pl-k\">export</span> <span class=\"pl-k\">function</span> <span class=\"pl-en\">isLeapYear</span>(<span class=\"pl-smi\">year</span><span class=\"pl-k\">:</span> <span class=\"pl-smi\">string</span>): boolean;\ndeclare export let DEBUG: boolean;\n\ndeclare export class Counter {\n  val<span class=\"pl-k\">:</span> number;\n  <span class=\"pl-en\">increase</span>()<span class=\"pl-k\">:</span> <span class=\"pl-k\">void</span>;\n}\n\ndeclare <span class=\"pl-k\">export</span> <span class=\"pl-smi\">type</span> <span class=\"pl-smi\">Response</span> <span class=\"pl-k\">=</span> <span class=\"pl-s\"><span class=\"pl-pds\">'</span>yes<span class=\"pl-pds\">'</span></span> <span class=\"pl-k\">|</span> <span class=\"pl-s\"><span class=\"pl-pds\">'</span>no<span class=\"pl-pds\">'</span></span> <span class=\"pl-k\">|</span> <span class=\"pl-s\"><span class=\"pl-pds\">'</span>maybe<span class=\"pl-pds\">'</span></span>;\n\ndeclare <span class=\"pl-k\">export</span> <span class=\"pl-smi\">interface</span> <span class=\"pl-smi\">Stack</span><span class=\"pl-k\">&#x3C;</span><span class=\"pl-smi\">T</span><span class=\"pl-k\">></span> {\n  <span class=\"pl-smi\">push</span>(<span class=\"pl-smi\">item</span>: <span class=\"pl-smi\">T</span>): <span class=\"pl-smi\">void</span>;\n  <span class=\"pl-smi\">pop</span>(): <span class=\"pl-smi\">T</span>;\n  <span class=\"pl-smi\">isEmpty</span>(): <span class=\"pl-smi\">bool</span>;\n}\n</code></pre>\n<p>Declaration files supports mixin,\nwhich can also be used in implementations, for example,</p>\n<pre><code class=\"language-js\"><span class=\"pl-c\">/* @flow */</span>\n\ndeclare <span class=\"pl-k\">class</span> <span class=\"pl-en\">MyClass</span> <span class=\"pl-k\">extends</span> <span class=\"pl-e\">Child</span> mixins MixinA, MixinB {}\ndeclare <span class=\"pl-k\">class</span> <span class=\"pl-en\">MixinA</span> {\n  a<span class=\"pl-k\">:</span> number;\n  b<span class=\"pl-k\">:</span> number;\n}\n<span class=\"pl-c\">// Mixing in MixinB will NOT mix in MixinBase</span>\ndeclare <span class=\"pl-k\">class</span> <span class=\"pl-en\">MixinB</span> <span class=\"pl-k\">extends</span> <span class=\"pl-e\">MixinBase</span> {}\ndeclare <span class=\"pl-k\">class</span> <span class=\"pl-en\">MixinBase</span> {\n  c<span class=\"pl-k\">:</span> number;\n}\ndeclare <span class=\"pl-k\">class</span> <span class=\"pl-en\">Child</span> <span class=\"pl-k\">extends</span> <span class=\"pl-e\">Base</span> {\n  a<span class=\"pl-k\">:</span> string;\n  c<span class=\"pl-k\">:</span> string;\n}\ndeclare <span class=\"pl-k\">class</span> <span class=\"pl-en\">Base</span> {\n  b<span class=\"pl-k\">:</span> string;\n}\n\n<span class=\"pl-k\">var</span> c <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> <span class=\"pl-en\">MyClass</span>();\n(<span class=\"pl-smi\">c</span>.<span class=\"pl-smi\">a</span><span class=\"pl-k\">:</span> number); <span class=\"pl-c\">// Both Child and MixinA provide `a`, so MixinA wins</span>\n(<span class=\"pl-smi\">c</span>.<span class=\"pl-smi\">b</span><span class=\"pl-k\">:</span> number); <span class=\"pl-c\">// The same principle holds for `b`, which Child inherits</span>\n(<span class=\"pl-smi\">c</span>.<span class=\"pl-smi\">c</span><span class=\"pl-k\">:</span> string); <span class=\"pl-c\">// mixins does not copy inherited properties,</span>\n               <span class=\"pl-c\">// so `c` comes from Child</span>\n</code></pre>\n<h2>Problems</h2>\n<h3>Interfaces use structural typing.</h3>\n<p><a href=\"https://golang.org/doc/faq#guarantee_satisfies_interface\">Go's FAQ</a> suggests to add an additional method to doc implementations:</p>\n<pre><code class=\"language-go\"><span class=\"pl-k\">type</span> <span class=\"pl-v\">Fooer</span> <span class=\"pl-k\">interface</span> {\n    <span class=\"pl-c1\">Foo</span>()\n    <span class=\"pl-c1\">ImplementsFooer</span>()\n}\n</code></pre>\n<p>This is a simple workaround for documentation,\nwhich prevents accidental implementation of interfaces.\nHowever, it does not prevent a later modification of implementation of <code>Fooer</code>\nto remove <code>Foo()</code> and make <code>ImplementsFooer()</code> not correct any more.</p>\n<p>With JavaScript, a much better workaround is possible (mentioned in <a href=\"https://github.com/facebook/flow/issues/2376\">#2376</a>):</p>\n<pre><code class=\"language-js\"><span class=\"pl-c\">/* @flow */</span>\n<span class=\"pl-k\">interface</span> <span class=\"pl-c1\">A</span> {\n  <span class=\"pl-en\">foo</span>()<span class=\"pl-k\">:</span> number;\n}\n\n<span class=\"pl-k\">class</span> <span class=\"pl-en\">AImpl</span> {\n  <span class=\"pl-en\">constructor</span>(): A {\n    <span class=\"pl-k\">return</span> <span class=\"pl-c1\">this</span>;\n  }\n  <span class=\"pl-en\">foo</span>()<span class=\"pl-k\">:</span> number {\n    <span class=\"pl-k\">return</span> <span class=\"pl-c1\">1</span>\n  }\n}\n</code></pre>\n<p>So flow's structural typed interface is not as hopeless bad as Go.</p>\n<h3>Implicitly type casting <code>number</code> to <code>string</code> with <code>+</code>.</h3>\n<p>The <code>number + string</code> idiom is fairly common, so flow accepts it, like TypeScript.</p>\n<p>With this <a href=\"https://github.com/facebook/flow/pull/4610\">patch</a>, <code>flow</code> will reject <code>number + string</code>:</p>\n<pre><code>Error: main.js:3\n  3:    return 1 + \"s\"\n               ^ number. This type cannot be added to\n  3:    return 1 + \"s\"\n                   ^^^ string\n</code></pre>\n<h2>Hegel</h2>\n<p><a href=\"https://hegel.js.org/\">Hegel</a> has a more sound type system than Flow,\nand it does not have the two problems mentioned above:</p>\n<ol>\n<li>It does not support interface.</li>\n<li>No type coercion for <code>number + string</code>.</li>\n</ol>\n<p>It borrows Flow's syntax for type annotation, thus JavaScript can be generated via Flow tools (<code>@babel/preset-flow</code> or <code>flow-remove-types</code>).\nHowever, it uses TypeScript <code>d.ts</code> files for library definition, because TypeScript has a much larger ecosystem than Flow.\nNote some types are not supported, for example, Flow's interface and TypeScript's conditional typing.</p>\n<p>Its vscode extension is <a href=\"https://hegel.js.org/\">still in development</a>.</p>","date_published":"Thu, 24 Aug 2017 14:03:05 GMT","date_modified":"Mon, 05 Sep 2022 12:59:54 GMT"},{"id":"https://mmap.page/dapi/lingfeng/","url":"https://mmap.page/dapi/lingfeng/","title":"《铃丰的恋物语与剑道社》「用感觉来写」的文学追求：以语法特征分析为中心","content_html":"<h1>《铃丰的恋物语与剑道社》「用感觉来写」的文学追求：以语法特征分析为中心</h1>\n<h2>摘要</h2>\n<p>本文以初音《铃丰的恋物语与剑道社》《简介》、《序章》《第一话》语法特征分析为基础，\n揭示了「感觉」、「你」特殊用法背后「用感觉来写」的文学追求。</p>\n<h2>《简介》</h2>\n<blockquote>\n<p>铃丰是个剑道社的社长，\n他家里面还有个妹妹，是天依，你是妹妹是个厨师，</p>\n</blockquote>\n<p>用「你」指代前面提及的人物，视为「我」对指代人物说的话，即「天依，你是妹妹，是个厨师」。这里「我」是作者。「天依是妹妹是个厨师」只是平常的陈述，而「你是妹妹是个厨师」，突出了「妹妹」、「厨师」是作者的设定，同时给人作者正在进行设定的感觉。这种用法体现了强烈的虚构色彩，读者仿佛在现场亲历作者给出人设的场景。正如作者反驳读者评论「恕我直言，这语言障碍症不轻啊。」所言「我是写文学作品的」。</p>\n<p>注：「有个妹妹，是天依」用「是」分隔同位语。类似地，《第一话》「天气是阳光明媚」，分隔主语、谓语。（与本文主题无关，为帮助理解引文的说明，以「注：」标识。）</p>\n<blockquote>\n<p>铃丰社团四个成员，是小林、小海、小冰、灰哥是剑道社副社长，你一起打进比赛朋友吗。</p>\n</blockquote>\n<p>「你」这里指代「铃丰」，凸显了作者给主角设定了一个朋友。</p>\n<p>注：这里的「是」仍然是分隔同位语「灰哥」和「剑道社副社长」。「吗」为语气词，不表疑问，为陈述语气。</p>\n<blockquote>\n<p>铃丰在学校里面喜欢女同学，你叫未来，是在班上喜欢的。</p>\n</blockquote>\n<p>这里「你」指代女同学，「是在班上喜欢的」补充说明「在学校」。\n注意这里「未来」用了「你」，而前一句没有用「你」。\n「铃丰，你在学校里面喜欢女同学」，会突出铃丰喜欢女同学是作者设定，\n而作者并不想突出这一点，所以没用「你」。\n也就是说，虽然作者喜欢用「你」突出虚构性，\n但是铃丰作为第一主角，作者将自己代入了，如作者本人所说「铃丰感觉，就是我的感觉」。\n因此不希望铃丰的感情是虚构的。\n对比前文天依、灰哥，可见妹妹、朋友只是设定，并不是作者最关心的。</p>\n<h2>第一话</h2>\n<blockquote>\n<p>... 未来感觉大家好想和我一起坐“救命啊，可以不要太多一起坐”，</p>\n</blockquote>\n<p>「感觉」引出主语的心理活动。引号用于标识心理活动中的内心独白。</p>\n<p>注：「未来」为女主角人名。「救命啊，可以不要太多一起坐」体现了异于通常语法的省略。</p>\n<blockquote>\n<p>她感觉感觉看到男生“真的好帅气”“老师你叫什么名字”，</p>\n</blockquote>\n<p>第一个「感觉」引出主语的心理活动，第二个「感觉」强调是主观感觉。\n表面重复，其实不重复。</p>\n<p>这里的「你」指代看到的男生（实为男主），而不是老师。\n这里「（帅气男生）你叫什么名字」中的「我」不是作者本人，而是女主「未来」。\n女主实际会说「老师他叫什么名字，以免老师误以为是问老师自己的名字，\n但是在文本是写为「你」，这一语法体现了女主虽然表面是问老师，实际心里是在和男主「对话」。</p>\n<p>这两个语法特征都是突出心理活动的。正如作者本人所说「我是把心理面，全部写出来」。</p>\n<p>当然，还有一种可能成立的解释，女主实际也说「老师你叫什么名字」，\n在现实中可能导致误解，但因为女主和老师都是作者虚构的人物，当然知道对方在说什么。\n用「你」指代男主，仍体现女主心里是在和男主「对话」。</p>\n<blockquote>\n<p>老师感觉“你说是谁”，</p>\n</blockquote>\n<p>这里的引号标识的是说出来的话，前面的「感觉」，表明这话正是老师心里所想，\n换言之，是说出来的内心独白。\n老师作主语，与未来对话，从老师的角度，当然用「你」。\n这种一致性说明老师说出来的话和其内心话语是一致的。</p>\n<blockquote>\n<p>未来感觉不知道我说什么“我指给你看”，就指了过去，老师感觉看到未来手指头，就知道是谁</p>\n</blockquote>\n<p>这里的「感觉」突出「看到未来手指头，就知道是谁」是老师的想法</p>\n<blockquote>\n<p>老师感觉“是不是好想铃丰坐在一起”，未来感觉“没有啊，我只是想知道你的名字”\n老师感觉看到好想没什么位子，就说道：“不要啊，你真的帅了”，</p>\n</blockquote>\n<p>这里的「你」仍指男主，表明老师也真心觉得男主帅，表面对女主说，心里是对男主说。</p>\n<p>注：「不要啊」省略「不想和铃丰坐在一起」。</p>\n<blockquote>\n<p>... 未来感觉想写告白，因为我想在舞台上和铃木告白，\n你写出歌名，还在继续写歌词了。</p>\n</blockquote>\n<p>这里「你」强调作者在进行设定。\n上一句用「我」，突出告白是未来自己的意愿（不想在此处突出女主喜欢男主是作者设定），\n写歌由于和人设密切相关，所以用「你」。</p>\n<p>同类的例子有《序章》第一句话：</p>\n<blockquote>\n<p>铃丰感觉“我叫铃丰，是高一学生，也是学校里面的老同学”\n铃丰感觉没有一个在学校的女同学知道你是肌肉的身体和台湾的脸型，\n在你们女生面前，我就是一个男神“真的好帅气”，也不知道有多少女同学喜欢上我，</p>\n</blockquote>\n<p>这里肌肉身体、台湾脸型，用「你」突出是人设。\n「在你们女生面前，我就是一个男神」，和「不知道有多少女同学喜欢上我」同样是不想突出男神是作者设定。\n「高一学生，也是学校里面的老同学」本来是设定，但因为前面是「我叫铃丰」，也连带不用「你」了，\n这样也更像内心独白的自我介绍。姓名和个人密切相关，例如「张三」给人虚构的感觉，因此不用「你」。</p>\n<p>如前所述，不想用「你」突出虚构性是为了避免影响代入性。\n实际上，这一语法也起到了区分可代入部分和难代入部分的作用。\n很多男性读者会代入「男神」，「不知道有多少女同学喜欢上我」，较少代入「肌肉身体」，很少代入「台湾脸型」。</p>\n<h2>结论</h2>\n<p>《铃丰的恋物语与剑道社》独特的语法，很多只是作者的习惯，例如作者在评论（接近日常语言）中说「在学校同学，对我说不喜欢话」，一般习惯在「在学校」后断句，作者在「同学」后断句，说明作者习惯上认为主语和谓语间隔较远，作品中用「是」区隔主语、谓语正体现作者这一习惯。</p>\n<p>但用「感觉」引出心理活动，用「你」展现人物的内心话语，则体现了作者对「心理面」描写的注重。\n用「你」体现人设的虚构性，起到区分可代入与难以代入成分的作用，可视为对读者「心理面」的描写。</p>\n<p>作者在回复《铃丰的恋物语与剑道社》读者评论时提出了对日本轻小说的文学批评：</p>\n<blockquote>\n<p>我自己一开始看日本轻小说，什么看的吗，\n用了三种方法，第一个看到，第二个想到，第三个是感觉。\n我用三种方法去看，发现日本轻小说，是用感觉来写的轻小说的。</p>\n</blockquote>\n<p>姑且不论这一批评观是否合理，至少能说明「用感觉来写」是作者的文学创作追求，「用感觉来读」是作者认可的阅读方法。</p>\n<p>用「感觉」引出心理活动，用「你」展现人物的内心话语，注重对人物「心理面」的描写，体现了作者「用感觉来写」的文学创作追求；用「你」体现人设的虚构性，起到区分可代入与难以代入成分的作用，可视为对读者「心理面」的描写，是作者促使读者「用感觉来读」文学创作尝试，与「用感觉来写」相呼应。</p>","date_published":"Thu, 24 Aug 2017 13:13:54 GMT","date_modified":"Sat, 23 Nov 2019 19:11:50 GMT"},{"id":"https://mmap.page/dapi/jyqxz3-gumu/","url":"https://mmap.page/dapi/jyqxz3-gumu/","title":"金庸群侠传3古墓版攻略","content_html":"<h1>金庸群侠传3古墓版攻略</h1>\n<h2>建立角色篇</h2>\n<p>删除名字，姓名会成为隐藏【半瓶神仙醋】，基础属性附加额外5点属性值。\n如果不喜欢这个名字可以不改，反正后来学了玉女心经各属性会补满的。</p>\n<p>由于《玉女心经》研习不加福缘，因此为了入古墓派，福缘要大于 69，\n如果不想辛苦钓鱼的话，分配属性点和回答问题时要注意了。\n如果希望属性全满，分配属性时确保福缘 28（分配属性点，不够或者超过的\n重选属性点，有金2存档时福缘 18）。</p>\n<p>注：常见的攻略都说福缘大于 80，其实是 69.\n在 <code>root.swf/DefineSprite2754/frame185</code> 中有</p>\n<pre><code>if(_root.body[19] > 69)\n{\n    gotoAndStop(188);\n}\nelse\n{\n    gotoAndStop(186);\n}\n</code></pre>\n<h3>回答问题</h3>\n<p>1.【半瓶神仙醋】 基本属性 +2，福缘 30.\n2. 保留存档时，【不知道】或【当然保留着】，基本属性 +10、武功属性 +5、银两 +1000、修为点 +10.\n3.【极端的工作狂人】 修为点 +1\n4. 随便\n5. 选【寒冰真气】，侠义 -10，选其他练习经验会减少。由于玉女心经招式以自创为基础，因此不要选【自创】。\n6. 选 1-4项，对应角色好感度 -20.\n7. 有存档且第 2 题正确回答，选 1，现有的基本拳、指、剑、刀、暗 10 级；选 2，龟息功 1 级；选 3，随机武器;\n选4，得皮甲。\n8. 选【家道中落，流浪街头】，福缘 +20，福缘 50.\n9. 选【拳掌】，【拳掌】属性 +15-25. 因研习玉女心经后武功属性都会补满。而研习前在古墓学两种拳掌、一种暗器。\n10. 不要选【福缘】，否则浪费。\n11. 选【资质异常低劣】，福缘 +50, 福缘 100.\n12. 选 1 侠义 -15，选 2 定力 -8，选 3 侠义 -30、悟性 +3，选 4 侠义 -10，悟性 +1.\n13. 选 1 定力 -8，选 2 武功属性各 -2，选 3 基本属性 -5，选 4 悟性 -6. 不要选 3，否则福缘不满了。\n14. 选 1 侠义 -5、定力 -5，选 2 悟性 -3，选 3 金钱 -500，选 4 福缘 -20， 选 5, 生命减去1/3.\n不要选 4， 否则福缘不满。建议选 3，只有第一天能进全真，钱多了无用，除非要买吃的给乞丐丙（黄蓉）。\n15. 相应角色好感度增加 20.\n16. 选 1 失去所有金钱和物，只剩下金钱100 （超级存档的物品不受影响，金钱照样扣）；选 2 侠义 -50；\n选 3 武功属性 -4、2；选 4 悟性 -20.</p>\n<h2>入全真</h2>\n<p>第一天午时至酉时是入全真的唯一机会，不要睡觉。</p>\n<p>砍树消磨时光：砍树加力道，捕猎抓够一定毒虫可找何红药得蜈蚣爪和千蛛手，基本来不及，而且这两门武功无用，\n除非你想连六脉神剑，需要搜集指法加指力），钓鱼钓到特殊鱼加福缘，然而福缘已经满了，而且砍树只要狂点即可（游戏有 bug，看着时机点反而不如狂点效果好），比捕猎、钓鱼快。</p>\n<p>午时至酉回村遇官差敲诈事件，上前阻挡被秒杀，力道、根骨减半。</p>\n<p>丘处机出现，醒来后马上去树林找他，加入全真派。</p>\n<p>回答问题，除了最后一个最下流无耻的选赵志敬以外，其他全不选赵志敬，这样赵志敬只给你全真心法，不会传全真剑法。\n也不要找赵志敬切磋连胜 10 次得全真剑法。学了全真剑法就去不了古墓了。可找甄志丙学金雁功，这个学了没关系，学了\n也没什么大用。</p>\n<p>到大殿找丘处机不断养生，算好时机，剩下的时间休息，3 月 1 日（只要是 3 月就可以，选 1 日可以在全真少呆点\n几日，在古墓多呆点时间）比武，第一个随便，第二个必须输。</p>\n<h2>入古墓</h2>\n<p>输后争吵、逃跑、被玉蜂蜇，醒后选择以死相逼，成为古墓派弟子。</p>\n<p>因某些古墓功夫需前置武功达到一定级别才传授，而升级只能与小龙女切磋。因此先修炼寡欲至顶级，\n再研习全真心法，升到顶级，装备。这样生命、内力较高，切磋时可以支持得较久。</p>\n<p>小龙女传天罗地网掌，切磋至 9 级，传捕雀功。捕雀功升到 5 级并装备，传掷针术。\n掷针术 7 级传美女拳法。</p>\n<p>继续与小龙女切磋，磨练天罗地网掌与美女拳法。胜利后小龙女实力增强，有 1/5 概率得玉蜂浆。</p>\n<p>随着切磋不断获胜，小龙女实力也不断增强，直到无法战胜的程度。这时可以再修炼寡欲，虽然寡欲等级不会再提升，\n但是等级会随之提升。只是要注意算好时间，12 月 15 日后李莫愁会来古墓。若想在古墓多呆 15 日，可以在 12 月\n14 日修炼寡欲 15 天。</p>\n<h2>出古墓</h2>\n<p>与李莫愁一战，不论输赢，小龙女都会说打不过师姐快走。</p>\n<p>然后会获得玉女心经。玉女心经到手，闯荡江湖、通关无忧。这时选离开便能出古墓，否则会在石棺得到半部九阴真经，\n同时看到密道提示，提示有三种：</p>\n<ol>\n<li>【东.东.西.北.东.西】</li>\n<li>【西.东.南.北.东.西】</li>\n<li>【南.北.南.北.东.西】</li>\n</ol>\n<p>最后一个需赌 1/2 的可能性：</p>\n<ol>\n<li>东或北</li>\n<li>东或西</li>\n<li>南或北</li>\n</ol>\n<p>出古墓后被传送到聚贤庄，然后研习玉女心经，脱胎换骨。自此以后随意：如果想通关，可以马上征服一批门派攒够声望，\n上华山之巅即可；如果想做公告任务，那就做。</p>\n<p>注： 常见的攻略有的说最后一个是随机的，其实固然是随机的，却不是 4 个方向随机。还有的说东、北概率较大，确实如此，但不够精确：若是第 2 种，则断不会是北；若是第 3 种，则断不会是东。</p>","date_published":"Thu, 24 Aug 2017 13:06:40 GMT","date_modified":"Sat, 26 Jul 2025 05:29:46 GMT"},{"id":"https://mmap.page/dapi/jyqxz3-cheat/","url":"https://mmap.page/dapi/jyqxz3-cheat/","title":"金庸群侠传 3 作弊教程","content_html":"<h1>金庸群侠传 3 作弊教程</h1>\n<h2>修改原理</h2>\n<p>金庸群侠传3是 Flash 游戏，修改 SOL(Flash Shared Object) 存档。</p>\n<p>SOL 存档的位置（Windows）：</p>\n<pre><code>C:\\Documents and Settings\\用户名\\Application Data\\Macromedia\\Flash Player\\\n#SharedObjects\\随机字母数字\\游戏网址目录\\JY1.sol\n</code></pre>\n<p>Linux:</p>\n<pre><code>~/.config/google-chrome/Default/Pepper Data/Shockwave Flash/\nWritableRoot/#SharedObjects/随机字母数字/游戏网址目录/JY1.sol\n</code></pre>\n<p>如下载到本地玩，游戏网址目录是 <code>localhost</code> 或 <code>#localhost</code>。</p>\n<h2>修改工具</h2>\n<h3>tl;tr</h3>\n<p>会 Python 的用 pyamf，不会 Python 的学一下或者组合使用以下工具：</p>\n<ul>\n<li>minerva 浏览。</li>\n<li>金庸3人物属性修改器快速修改属性、金钱、修为、侠义等。</li>\n<li>flash游戏存档修改器 v1.5 修改其他变量。</li>\n</ul>\n<h3>金庸3人物属性修改器</h3>\n<p>针对金庸群侠传3的修改器，阿平工作室出品。</p>\n<h4>缺陷</h4>\n<ol>\n<li>点击保存后实未保存，需退出程序方保存成功。</li>\n<li>只能修改本地存档（在线存档可通过移动复制的方法修改）。</li>\n<li>只能修改姓名、等级、经验、名望、侠义值、属性、金钱等。</li>\n<li>姓只能修改为单字。</li>\n</ol>\n<h3>soleditor</h3>\n<p><a href=\"http://sourceforge.net/projects/soleditor/\">.sol editor</a> 是开源的 SOL 修改器。</p>\n<h4>缺陷</h4>\n<ol>\n<li>修改保存后 SOL 文档载入游戏后黑屏。</li>\n<li>无查找功能。</li>\n</ol>\n<h5>测试环境</h5>\n<ul>\n<li>soleditor 1.1</li>\n<li>金庸群侠传3 贺岁版</li>\n<li>Windows XP 专业版 SP3</li>\n<li>Flash for IE 17.0.0.188</li>\n</ul>\n<h3>minerva</h3>\n<p><a href=\"http://apps.coursevector.com/minerva/\">minerva</a> 是在线 SOL 编辑器。</p>\n<h4>缺陷</h4>\n<ul>\n<li>保存失败（<code>Uncaught RangeError: Maximum call stack size exceeded</code>）</li>\n</ul>\n<h3>flash游戏存档修改器</h3>\n<p><a href=\"http://www.cordyblog.cn/?action=show&#x26;id=275\">flash游戏存档修改器</a>是由 cordy 开发的修改器，目前最新版本为 <code>v1.5</code>.</p>\n<h4>缺陷</h4>\n<ol>\n<li>不支持 Windows 8.</li>\n<li>所有变量一张表，无层级显示，不支持按路径排序，不支持按路径搜索。</li>\n<li>无法删除变量。</li>\n</ol>\n<h4>窍门</h4>\n<p>如已知变量路径及类型，可直接添加变量，原变量数值将被覆盖，不必辛苦翻找修改。</p>\n<h3>flash游戏修改大师</h3>\n<p><a href=\"http://www.cordyblog.cn/\">flash游戏修改大师</a>同样由 cordy 开发，目前最新版本为 <code>3.2</code>.</p>\n<h4>缺陷</h4>\n<ol>\n<li>SOL 修改功能比flash游戏存档修改器还弱，除了无层级显示、不支持按路径排序、不支持按路径搜索外，无法新增删除变量。</li>\n<li>flash 文件修改功能不兼容金庸群侠传3 贺岁版。</li>\n</ol>\n<h3>pyamf</h3>\n<p><a href=\"https://pypi.python.org/pypi/PyAMF/\" title=\"PyAMF pypi page\">pyamf</a> 是可以读写 SOL 的 Python 模块。</p>\n<h4>示例代码</h4>\n<p>pyamf 使用很简单，只需掌握 <code>load</code> 和 <code>save</code> 两个方法，具体例子看<a href=\"https://raw.githubusercontent.com/hydralabs/pyamf/master/doc/tutorials/general/sharedobject.rst\">官方教程</a></p>\n<p>下面给出用 <a href=\"https://hylang.org/\" title=\"Lisp flavored Python\">Hy</a> 写的例子：</p>\n<pre><code class=\"language-hy\">(<span class=\"pl-k\">import</span> [pyamf [sol]])\n(<span class=\"pl-k\">import</span> os)\n(<span class=\"pl-k\">require</span> hy.contrib.anaphoric)\n# 存档路径\n(<span class=\"pl-k\">setv</span> <span class=\"pl-e\">path</span> (<span class=\"pl-en\">+</span>\n  (<span class=\"pl-en\">get</span> os.environ <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>HOME<span class=\"pl-pds\">\"</span></span>)\n  <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>/.config/google-chrome/Default/Pepper Data/Shockwave Flash/WritableRoot/#SharedObjects/U5KVCX46/#localhost<span class=\"pl-pds\">\"</span></span>))\n(<span class=\"pl-k\">setv</span> <span class=\"pl-e\">jy1_path</span> (<span class=\"pl-en\">+</span> path <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>/JY1.sol<span class=\"pl-pds\">\"</span></span>))\n# 读取存档一\n(<span class=\"pl-k\">setv</span> <span class=\"pl-e\">jy1</span> (<span class=\"pl-en\">sol.load</span> jy1_path))\n# 经脉齐通\n(<span class=\"pl-k\">setv</span> <span class=\"pl-e\">jm</span> (<span class=\"pl-en\">get</span> jy1 <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>n<span class=\"pl-pds\">\"</span></span>))\n(<span class=\"pl-en\">ap-each</span> jm (<span class=\"pl-en\">assoc</span> jm it <span class=\"pl-c1\">1</span>))\n# 保存\n(<span class=\"pl-en\">sol.save</span> jy1 jy1_path)\n</code></pre>\n<h3>soltool</h3>\n<p><a href=\"https://github.com/fmoo/soltool\">soltool</a> 是一个基于 pyamf 的命令行 SOL 读写工具。</p>\n<h4>缺陷</h4>\n<p><code>no attribute 'amf0'</code> 错误：</p>\n<pre><code>Traceback (most recent call last):\n  File \"~/bin/soltool\", line 328, in &#x3C;module>\n    main()\n  File \"~/bin/soltool\", line 320, in main\n    ns.cmd(ns)\n  File \"~/bin/soltool\", line 203, in _view\n    name, values = pyamf.sol.decode(stream)\n  File \"/usr/local/lib/python2.7/dist-packages/pyamf/sol.py\", line 64, in decode\n    decoder = pyamf.get_decoder(stream.read_uchar())\n  File \"/usr/local/lib/python2.7/dist-packages/pyamf/__init__.py\", line 518, in get_decoder\n    return _get_decoder_class()(*args, **kwargs)\n  File \"/usr/local/lib/python2.7/dist-packages/pyamf/__init__.py\", line 508, in _get_decoder_class\n    amf0 = _get_amf_module(AMF0, use_ext=use_ext)\n  File \"/usr/local/lib/python2.7/dist-packages/pyamf/__init__.py\", line 493, in _get_amf_module\n    return getattr(module, module_name)\nAttributeError: 'module' object has no attribute 'amf0'\n</code></pre>\n<p>估计是因为 soltool 比较老，和现在的 pyamf 不兼容。</p>\n<h3>ruby_sol</h3>\n<p><a href=\"https://github.com/filimonov/ruby_sol\">ruby_sol</a> 是一个读写 SOL 的 Ruby Gem。</p>\n<h4>缺陷</h4>\n<ul>\n<li>保存后的存档读取后无法习得武功。</li>\n</ul>\n<h4>示例代码</h4>\n<pre><code class=\"language-ruby\"><span class=\"pl-k\">require</span> <span class=\"pl-s\"><span class=\"pl-pds\">'</span>ruby_sol<span class=\"pl-pds\">'</span></span>\n\n<span class=\"pl-c\"># 存档路径</span>\npath <span class=\"pl-k\">=</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span><span class=\"pl-pse\">#{</span><span class=\"pl-c1\">ENV</span>[<span class=\"pl-pds\">'</span>HOME<span class=\"pl-pds\">'</span>]<span class=\"pl-pse\">}</span>/.config/google-chrome/Default/Pepper Data/Shockwave Flash/WritableRoot/#SharedObjects/U5KVCX46/#localhost<span class=\"pl-pds\">\"</span></span>\n<span class=\"pl-c\"># 读取存档一</span>\njy1 <span class=\"pl-k\">=</span> <span class=\"pl-c1\">RubySol</span>::read_sol(<span class=\"pl-c1\">File</span>.<span class=\"pl-k\">new</span>(<span class=\"pl-s\"><span class=\"pl-pds\">\"</span><span class=\"pl-pse\">#{</span>path<span class=\"pl-pse\">}</span>/JY1.sol<span class=\"pl-pds\">\"</span></span>).read)\n<span class=\"pl-c\"># 已知 `Hp` 为生命，查询还有哪些值与生命相关。</span>\njy1.each <span class=\"pl-k\">do</span> |<span class=\"pl-smi\">k</span>, <span class=\"pl-smi\">v</span>|\n  <span class=\"pl-c\"># 注意 ruby_sol 使用类哈希表而非列表</span>\n  <span class=\"pl-k\">if</span> v.is_a? <span class=\"pl-c1\">RubySol</span>::<span class=\"pl-c1\">Values</span>::<span class=\"pl-c1\">TypedHash</span>\n    v.each <span class=\"pl-k\">do</span> |<span class=\"pl-smi\">kk</span>, <span class=\"pl-smi\">vv</span>|\n      <span class=\"pl-k\">if</span> vv <span class=\"pl-k\">==</span> jy1[<span class=\"pl-s\"><span class=\"pl-pds\">'</span>Hp<span class=\"pl-pds\">'</span></span>]\n        <span class=\"pl-c1\">puts</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>jy1['<span class=\"pl-pse\">#{</span>k<span class=\"pl-pse\">}</span>']['<span class=\"pl-pse\">#{</span>kk<span class=\"pl-pse\">}</span>'] => <span class=\"pl-pse\">#{</span>vv<span class=\"pl-pse\">}</span><span class=\"pl-pds\">\"</span></span>\n      <span class=\"pl-k\">end</span>\n    <span class=\"pl-k\">end</span>\n  <span class=\"pl-k\">end</span>\n<span class=\"pl-k\">end</span>\n<span class=\"pl-c\"># 经脉齐通</span>\njingmai <span class=\"pl-k\">=</span> jy1[<span class=\"pl-s\"><span class=\"pl-pds\">'</span>n<span class=\"pl-pds\">'</span></span>]\n<span class=\"pl-c\"># 注意，ruby_sol 使用哈希表浮点数而非整数</span>\njingmai.each_key <span class=\"pl-k\">do</span> |<span class=\"pl-smi\">k</span>| jingmai[k] <span class=\"pl-k\">=</span> <span class=\"pl-c1\">1.0</span> <span class=\"pl-k\">end</span>\n<span class=\"pl-c\"># 保存后的存档读取后无法习得武功。</span>\n<span class=\"pl-c1\">open</span>(<span class=\"pl-s\"><span class=\"pl-pds\">\"</span><span class=\"pl-pse\">#{</span>path<span class=\"pl-pse\">}</span>/JY2.sol<span class=\"pl-pds\">\"</span></span>, <span class=\"pl-s\"><span class=\"pl-pds\">'</span>w<span class=\"pl-pds\">'</span></span>) <span class=\"pl-k\">do</span> |<span class=\"pl-smi\">f</span>|\n  f.write(<span class=\"pl-c1\">RubySol</span>::create_sol(jy1))\n<span class=\"pl-k\">end</span>\n</code></pre>\n<h2>变量列表</h2>\n<h3>个人基本资料</h3>\n<p>个人基本资料储存在列表 <code>m</code>.</p>\n<pre><code>1 姓\n2 名\n3 经验 (平时为数字，封顶为字符串`经验封顶`）\n4 等级 （游戏中 100 封顶，实际可改为任意值）\n5 修为点 （类似金钱，可贯通经脉、转化内力生命属性、修炼武功）\n8 门派 （可改为任意值）\n9 门派位阶 （可改为任意值）\n10 门派技能 （可改为任意值）\n11 技能等级 （10 封顶，超过 10 显示不正常）\n12 师承 （可改为任意值）\n13 妻室 （可改为任意值）\n14 名望\n15 侠义\n16 力道 （16-37 100 封顶）\n17 根骨\n18 悟性\n19 福缘\n20 灵敏\n21 定力\n22 拳掌之功\n23 弹指之力\n24 御剑之术\n25 耍刀之法\n26 舞棍之能\n27 内功修为\n28 拆招卸力\n29 搏击格斗\n30 闪躲纵跃\n31 轻身之法\n32 施毒之术\n33 医疗之术\n34 暗器技法\n35 读书识字\n36 交易之道\n37 烹饪之道\n41 是否阉割（0 未阉割，1 阉割）\n42 正在研习的秘籍\n50 自创武功名称\n52-55 四名队友 （可为任意 npc，npc 列表见下，可为同一人）\n67 休息前最后使用的招式\n110 金钱\n120 年 （数字，最大 10）\n121 月 （数字）\n122 日 （数字，每月均为 30 日）\n123 时辰 （数字）\n124 时刻 （数字）\n128 当前场景帧 （直接跳转到事件，注意某些数值可能错误，例如生命 undefiend，招式无法使用等，休息后恢复正常）\n139 游戏进程 （例如`序幕2`、`初入少林`、`叛出全真`、`聚贤庄`等)\n140 地点 （例如`酒 店`、`少林派`、`聚贤庄`等）\n147-150 每月公告任务 （代号见后）\n</code></pre>\n<h4>生命、内力、等级</h4>\n<p>由于某些内功可增加生命、内力，因此修改生命内力时需装备不加生命、内力的内功，例如自创。\n然后修改以下数值为 <code>99999</code>.</p>\n<ul>\n<li>生命： <code>Hp m[44] m[45] m[197]</code>, 其中，<code>m[45]</code> 是原始生命值（无内功加成），<code>m[44]</code> 是目前原始生命值 。</li>\n<li>内力： <code>Mp m[46] m[47] m[198]</code>, 其中， <code>m[47]</code> 是原始内力值，<code>m[46]</code> 是目前原始内力值。</li>\n</ul>\n<p>玩家当前生命、内力 <code>99999</code> 封顶。生命、内力若恰好为 <code>99999</code>，则受伤害、耗内力会正常扣血、内力。\n一旦生命、内力超过 <code>99999</code> （例如 <code>100000</code>），则生命、内力锁定为  <code>99999</code>，换言之，受伤害、耗内力后\n瞬间回复至 <code>99999</code>。战斗时开着人物面板，有时能看到受伤害生命值 <code>99999</code> 抖动。唯一一个例外，损耗超过\n<code>99999</code>，则打破锁定。因此对方一击带来的伤害超过 <code>99999</code>，则立时致死。暂时没碰到实力如此强悍的敌人，\n故 <code>99999+</code> 基本等于锁定。只是我把己方队友属性改到了 <code>900</code>，因此切磋时若闪避、拆招皆不成功立死。\n同理，我自己配玉女、凌波，五属性也有 <code>99x</code>，因此队友若闪拆不成亦立死。总之战斗的情况是要不闪避、要不\n个位数伤害、要不一招致命。</p>\n<p>生命原始值为 <code>100000</code>，配上加生命的内功会溢出，一受轻微伤害即死。故生命原始值当改为 <code>99999</code>。</p>\n<p>每个等级对应的经验储存在数组 <code>d</code> 中。所有拥有过的江湖绰号储存在列表 <code>e</code> 中。</p>\n<h4>回到开始</h4>\n<ul>\n<li><code>m[120-122,124]</code> 改为 1，<code>m[123]</code> 改为6.</li>\n<li><code>m[139]</code> 改为 <code>序幕2</code>.</li>\n<li><code>m[140]</code> 改为 <code>酒 店</code>.</li>\n</ul>\n<h3>物品</h3>\n<p>背包中的物品储存在列表 <code>f</code> 中。每种物品的数量储存在列表 <code>g</code> 中。</p>\n<p>例如，<code>f[0] = 29; g[29] = 2</code> 表示背包第一格中有倚天剑 2 把。</p>\n<p>物品快捷储存在列表 <code>i</code> 中。</p>\n<pre><code>2 木剑\n3 假倚天剑\n4 玉箫剑\n5 铁剑\n6 纯钢剑\n7 西洋剑\n8 碧水剑\n9 龙泉剑\n10 冷凝剑\n11 凝碧剑\n12 火龙剑\n13 松纹剑\n14 紫薇软剑\n15 白剑\n16 黑剑\n17 秦王剑\n18 龙渊剑\n19 白龙剑\n20 君子剑\n21 淑女剑 （可赠小龙女，游戏中有 bug，对话中要求馈赠淑女剑，实际收取的是君子剑）\n22 金蛇剑\n23 楚王剑\n24 夫差剑\n25 真武剑\n26 工布剑\n27 巨阙剑\n28 玄铁剑\n29 倚天剑 （除特定剑法宝剑组合外，威力最强）\n\n30 菜刀\n31 生锈铁刀\n32 单刀\n33 柳叶刀\n34 雁翎刀\n35 斩马刀\n36 九环刀\n37 屠牛刀\n38 破风刀\n39 天竺弯刀\n40 鬼头刀\n41 龙王刀\n42 穿云刀\n43 百辟刀\n44 金背大刀\n45 紫金八卦刀\n46 金貂刀\n47 血刀\n48 绿波香露刀\n49 金刀\n50 银弧刀\n51 狮头宝刀\n52 百炼宝刀\n53 虎头金刀\n54 冷月宝刀\n55 屠龙刀\n\n56 木棍\n57 狼牙棒\n58 盘龙棍\n59 打狗棒\n60 黄金杵\n61 西毒蛇杖\n62 杀狮杖\n\n63 飞镖\n64 柳叶飞刀\n65 金钱镖\n66 毒菱\n67 玉蜂针\n68 黑血神针\n69 生死符\n70 金蛇锥\n71 霹雳雷火弹\n72 火枪\n\n73 皮甲\n74 鳄鱼皮甲\n75 软猬甲\n76 乌蚕衣\n77 金丝背心\n78 布衣\n79 乞丐服\n80 虎裙皮\n81 棉衣\n82 将军甲衣\n83 黄金甲\n84 明教服饰 （征服门派时穿戴各派服饰可乔装混进直接找掌门）\n85 女装\n86 全真服饰\n87 日月教服饰\n88 少林派服饰\n89 神龙教服饰\n90 武当道袍\n91 夜行衣 （可混进少林寺藏经阁）\n\n92 葵花宝典 (武功可直接修改，不必修改物品再研习）\n93 辟邪剑法\n94 易筋经\n95 紫霞秘籍\n96 六脉神剑\n97 九阳真经\n98 胡家刀法\n99 金蛇秘笈\n100 神照经\n101 太极拳经\n102 毒经\n103 五毒秘传\n104 武穆遗书\n105 血刀秘笈\n106 药王神篇\n107 子午针灸图\n108 凌波微步\n109 北冥神功\n110 铁掌掌谱\n111 神木王鼎\n112 八荒六合功\n113 七伤拳谱\n114 乾坤大挪移\n115 少林绝技\n116 十八泥偶\n117 千金方\n118 九阴上卷\n119 九阴下卷\n120 峨眉九阳功\n121 玉女心经（可赠小龙女）\n122 斗转星移\n123 先天功\n124 少林九阳功\n125 武当九阳功\n126 龙象波若功\n127 梯云纵\n128 一苇渡江\n129 漫天花雨\n130 青字九打\n131 修罗刀法\n132 松风剑法\n133 狂风刀法\n134 玉女素心剑\n135 回风拂柳剑\n136 柴刀十八路\n137 峨眉心法\n138 华山心法\n139 全真心法\n140 武当心法\n141 太极劲\n142 神龙心法\n143 苗家剑法\n144 玉女十九剑\n145 神门十三剑\n146 绕指柔剑\n147 密宗内功\n148 段氏心法\n\n149 八宝肥鸭\n150 醋溜鱼\n151 洱海工鱼干\n152 咕噜肉\n153 煎豆腐\n154 煎饺\n155 佛跳墙\n156 好逑汤\n157 酱爆牛肉\n158 椒盐排骨\n159 叫花鸡\n160 烤玉米\n161 口菇鸡脚汤\n162 口菇焖鸡\n163 老鸭汤\n164 馒头\n165 烧饼\n166 双禽炒白菜\n167 素三鲜\n168 汤圆\n169 天麻鸽脯\n170 虾仁芝麻卷\n171 鲜笋炒豆芽\n172 香烹蜈蚣\n173 扬州炒饭\n174 银耳莲子粥\n175 油条\n176 玉笛听落梅\n177 鸳鸯五珍烩\n178 月饼\n179 炒鳝丝\n180 炸田鸡腿\n181 蒸豆腐\n182 蒸饺\n183 炙牛肉条\n184 煮鸡蛋\n185 粽子\n186 醉蟹\n187 关外白酒\n188 女儿红\n189 葡萄酒\n190 高粱酒\n191 百草美酒\n192 状元红\n193 梨花酒\n194 烧刀子\n195 玄冰碧火酒\n196 三锅头汾酒\n197 玉露酒\n198 五宝花蜜酒\n199 迷春酒\n200 毒酒\n201 洞庭碧螺春\n202 武夷黄金桂\n203 安溪铁观音\n204 黄山毛峰\n205 六安瓜片\n206 银针白毫\n207 西湖龙井\n208 大红袍\n209 太平猴魁茶\n210 君山毛尖\n211 安溪毛蟹\n212 朱睛冰蟾\n213 天山雪莲\n214 大蟠桃\n215 千年人参\n216 寒塘白鱼\n217 蛇胆\n218 熊胆\n219 玉真散\n220 三黄宝腊丸\n221 天心解毒丸\n222 六阳正气丸\n223 玉灵散\n224 大还丹\n225 无常丹\n226 九花玉露丸\n227 田七鲨胆散\n228 天香断续胶\n229 白云熊胆丸\n230 回阳五龙膏\n231 玉洞黑石丸\n232 九转灵宝丸\n233 九转熊蛇丸\n234 玉蜂浆 （可赠小龙女）\n235 雪参玉蟾丸\n236 牛黄血竭丹\n237 黄连解毒丸\n238 腊八粥\n239 小还丹\n240 镇心理气丸\n241 茯苓首乌丸\n242 生生造化丹\n243 续命八丸\n244 黑玉断续膏\n\n245 笑傲江湖曲谱\n246 正红旗\n247 镶红旗\n248 正蓝旗\n249 镶蓝旗\n250 正黄旗\n251 镶黄旗\n252 正白旗\n253 镶白旗\n254 黑木令\n255 五岳令牌\n256 西山行旅图\n257 呕血谱\n258 率意帖\n259 广陵散\n260 圣火令\n261 赏善罚恶令\n262 七宝指环\n263 七星海棠\n264 闯王宝藏\n265 唐诗选辑\n266 可兰经\n267 宝箱\n268 镖物\n269 书信1\n270 书信2\n271 书信3\n272 书信4\n273 龙脉宝藏\n274 擂鼓山请帖\n275 人皮面具\n\n276 银两\n277 弓箭\n278 剥皮刀\n279 锄头\n280 柴火\n281 铁镐\n282 鱼竿\n283 十香软筋散\n284 断肠草\n285 金银小蛇\n286 蝮蛇\n287 五彩蜘蛛\n288 莽牯朱蛤\n289 冰蚕\n290 小金蛇\n291 蝎子\n292 蜈蚣\n293 毒蛛\n294 蟾蜍\n295 大公鸡\n296 羊羔坐臀\n297 小猪耳朵\n298 小牛腰子\n299 獐腿肉\n300 兔肉\n301 荷花\n302 笋尖\n303 樱桃\n304 白菜\n305 鸭掌\n306 火腿\n307 豆腐\n308 华山蜈蚣\n309 鱼干\n310 铁矿\n311 铜矿\n312 红晶矿\n313 蓝晶矿\n314 白晶矿\n315 玄铁矿\n316 蓝宝石\n317 红宝石\n318 蚯蚓\n319 河蚌\n320 海螺\n321 草鱼\n322 鲤鱼\n323 娃娃鱼\n324 黄金鱼\n325 螃蟹\n326 鳖\n327 鹿皮\n328 虎皮\n329 熊掌\n330 虎掌\n331 野猪肉\n332 熊皮\n333 野猪皮\n334 油\n335 盐\n336 醋\n</code></pre>\n<h3>武功</h3>\n<p>类似背包，武功被存放于以下列表：</p>\n<pre><code>o 掌拳\np 指法\nq 剑法\nr 刀法\ns 棍法\nt 暗器\nu 内功 （自创武功在游戏界面中位于【其他】，其实属于内功）\nv_1 轻功\nw 其他\n</code></pre>\n<p>类似物品数量，轻功、内功等级储存于列表 <code>x</code> 中，除了轻功、内功、其他之外的武功经验值储存于列表 <code>v</code> 中，\n内功招式经验值亦储存于列表 <code>v</code> 中。</p>\n<p>列表 <code>v</code> 中的经验值建议改为 <code>999</code>，再大效果不明显。</p>\n<p>列表 <code>x</code> 为等级，游戏中 5 级封顶，升级至 5 级后无法再升级。实际可改得更大，\n修改为超过 5 级后可在游戏中升级。</p>\n<p>招式快捷键存放于列表 <code>h</code> 中。</p>\n<p>特别地，<code>h[7]</code> 可以改为无招式内功代号，如此则会显示相应内功图片（默认无招式内功不显示图片），\n若按快捷键，则出现招式 <code>undefined</code>，然后开始飘樱花（无实际效果）。\n或者，<code>h[7]</code> 可以修改为招式（先前装备的内功仍然有效），若内功无招式，可多出一个招式。\n不过一旦在游戏中装备内功，则 <code>h[7]</code> 会自动更新。</p>\n<p>此外，<code>h</code>中的代码为内功代表内功中的招式，所以装备多内功不可能，但是可以使用多种内功的招式：\n例如招式中包括加血的龟息功、复活的神照、吸内力的北冥、群攻的八荒等等。</p>\n<p>武功效果：游戏的 skill 文件夹下是每种武功的画面效果，通过复制、重命名的方法可以修改武功效果。</p>\n<h4>掌拳</h4>\n<pre><code>66.黯然销魂掌 67.白虹掌 68.白驼雪山掌 69.般若掌 70.碧波清掌 71.冰蚕神掌\n72-75.长拳 76.赤炼神掌 77.抽髓掌\n78.春蚕掌法 79.摧心掌 80.大力金刚掌 81.寒冰绵掌 82.化骨绵掌 83.火焰刀\n84.基本拳掌 85.降龙十八掌 86.金蛇游身掌 87.空明拳 88.灵蛇拳 89.罗汉拳\n90.落英神剑掌 91.美女拳法 92.美女三招 93.绵掌 94.南山掌法 95.劈空掌\n96.七伤拳 97.如来千叶手 98.三化聚顶掌 99.太极拳 100.天长掌法\n101.天罗地网掌 102.天山六阳掌 103.天山折梅手 104.铁掌 105.铜锤手\n106.五罗轻烟掌 107.五行六合掌 108.逍遥游(掌法) 109.须弥山掌\n110.野狐拳法 111.英雄三招(拳法) 112.震山铁掌 113.重阳神掌\n</code></pre>\n<h4>指法</h4>\n<pre><code>114.参合指 115.大力金刚指 116.分筋错骨手(指法) 117.虎爪绝户手(指法) 118.基本指法\n119.九阴白骨爪(指法) 120.兰花拂穴手 121.六脉神剑 122.龙爪功 123.拈花指 124.凝血神抓\n125.千蛛万毒手 126.三阴蜈蚣爪 127.锁喉擒拿手 128.无相劫指 129.一阳指 130.鹰爪擒拿手\n</code></pre>\n<h4>剑法</h4>\n<pre><code>33.百变千幻云雾剑法 34.辟邪剑法 35.冰雪剑法 36.达摩剑法 37.独孤九剑 38.段家剑法\n39.夺命连环三仙剑 40.华山剑法 41.回风拂柳剑 42.回风落雁剑 43.基本剑法 44.金蛇剑法\n45.快慢十七路 46.狂风剑法 47.苗家剑法 48.灭绝剑法 49.慕容剑法 50.宁氏一剑\n51.全真剑法 52.绕指柔剑 53.神门十三剑 54.松风剑法 55.太极剑法 56.太岳三青峰 57.躺尸剑法\n58.万花剑法 59.五大夫剑 60.五岳剑法 61.玄铁剑法 62.玉女剑法 63.玉女素心剑 64.玉萧剑法 65.越女剑法\n</code></pre>\n<h4>刀法</h4>\n<pre><code>10.柴刀十八路 11.胡家残刀 12.胡家刀法 13.火焰刀\n14.基本刀法 15.狂风刀法 16.慕容刀法 17.奇门三才刀\n18.燃木刀法 19.五虎断刀门 20.修罗刀法 21.玄虚刀法 22.血刀刀法\n</code></pre>\n<h4>棍法</h4>\n<pre><code>23.打狗棍法 24.伏魔杖法 25.基本棍法 26.叫化棍法 27.金刚降魔杵\n28.灵蛇杖法 29.慕容棍法 30.太祖棍 31.韦陀杖法 32.无上大力杵法\n</code></pre>\n<h4>暗器</h4>\n<pre><code>2.弹指神通 3.腐尸毒 4.基本暗器 5.满天星 6.漫天花雨 7.慕容暗器 8.掷针术 9.青字九打\n</code></pre>\n<h4>内功</h4>\n<pre><code>131.八荒六合唯我独尊功 132.北冥真气 133.蛤蟆功 134.龟息功\n135.化功大法 136.混元功 137.金刚不坏神功 138.九阳神功\n139.自创 140.葵花神功 141.龙象般若功(13) 142.乾坤大挪移(6)\n143.神龙心法 144.神照经 145.狮吼功 146.太玄经 147.吸星大法\n148.小无相功 149.紫霞神功 150.闭穴术 151.纯阳无极功 152.斗转星移\n153.段氏心法 154.峨眉九阳功 155.华山心法 156.叫化内功 157.逆转经脉\n158.九阴真经心法 159.罗汉伏魔功 160.密宗内功 161.全真心法\n162.少林九阳功 163.太极劲 164.桃花岛心法 165.武当功 166.先天功\n167.易筋经 168.玉女心经 169.紫薇心法\n</code></pre>\n<p>（括号内为金庸小说中该武功的最高等级，其实和游戏设定无关。）</p>\n<p>注意：</p>\n<ul>\n<li>龟息功可加己方生命，神照经可复活战斗中死去队友（另每级内功 +5，额外附带生命内力）。</li>\n<li>游戏中玩家内功 5 级封顶，自创 10 级封顶，npc 10 级封顶。</li>\n<li>由于自创每级内功、搏击、拆招均 +10，10 级封顶，可将内功、搏击、拆招加到 200，为游戏中最强内功。\n不过自创的等级由经验决定，需修改 <code>v[139]</code>，修改 <code>x[139]</code> 无效果，最多到 10 级，因此反不如\n玉女心经每级三项 +5，改高等级。 加三项属性的只有自创、玉女、九阴、太玄。\n其中太玄亦是每级三项 +5，且附带全体攻击招式（直接修改等级，无需低悟性）。九阴每级三项 +3。</li>\n<li>内功、搏击、拆招最多加到 300，再高的话虽然攻击力仍在上升，但防御力下降，高到一定程度攻击溢出，画面显示\n显示伤害为 3，实际任意敌人一击必杀。再高到一定程度则防御溢出，一受伤害即死。</li>\n</ul>\n<h4>轻功</h4>\n<pre><code>170.八步赶蟾 171.北斗仙踪 172.捕雀功 173.飞檐走壁 174.华山身法\n175.金雁功 176.凌波微步 177.少林身法 178.神行百变 179.四象步法\n180.踏雪无痕 181.梯云纵 182.一苇渡江 183-186 undefined\n</code></pre>\n<p>注意：</p>\n<ul>\n<li>装备轻功加轻身或闪避属性，由于属性 100 封顶，因此需改轻功等级提升属性。</li>\n<li>某些轻功只加单一属性，例如捕雀功只加轻身不加闪避。</li>\n<li>游戏中玩家轻功 5 级封顶，因此最佳轻功为凌波微步（每级轻+8、闪+13）及神行百变（每级轻+12、闪+8）。\n由于可修改，只需避开只加单一属性的轻功即可。\n凌波微步、神行百变、北斗仙踪、华山身法高等级，配合原始轻、闪 99 均可修改至 99x.</li>\n<li>轻、闪原始值 100，轻功等级过高会溢出。</li>\n<li>轻、闪刷到 99x 后，只需装备加轻、闪内功（等级不限），轻、闪即为 99x.</li>\n<li>闪刷到 99x 后，任何敌人的攻击均会闪避掉。</li>\n</ul>\n<h4>其他</h4>\n<pre><code>187.毒雾 188.驱蜂术 189.星宿解毒术 190.左右互搏\n</code></pre>\n<p>修改修为方法未知，可能无法修改。</p>\n<h4>NPC 专用武功</h4>\n<p>191.普通攻击 192.火枪术 193.混元掌 194.玄冥神掌 195.五轮大法\n196.阴阳捣乱刃 197.三僧鞭法 198.芷若鞭法 199. 易筋神功</p>\n<p>经验储存在列表 <code>v</code> 中。</p>\n<h4>经脉</h4>\n<p>经脉储存于列表 <code>n</code> 中，<code>1</code> 通，<code>0</code> 未通。</p>\n<h4>最强武功</h4>\n<p>单体：辟邪配倚天，玄铁剑法配玄铁剑，金蛇剑法配金蛇剑，胡家刀法配冷月宝刀，打狗棒法配打狗棒。</p>\n<p>其中辟邪速度最快，只需 1.5 格。</p>\n<p>剑、刀、棍可通用，甚至韦陀杖法配倚天优于配蟠龙棍。</p>\n<p>群体：独孤配倚天，六脉神剑次之。</p>\n<p>实际上属性改成 100-99x，内力改成 99999+，内功等级改成 10+，随便什么武功都是一招灭敌。</p>\n<p>唯一需要注意的是，改一个群体攻击的武功，这样人多的时候也可以秒杀。</p>\n<p>不配内功，属性值99、100，经验值999，配倚天剑，攻击萧峰，辟邪 6xxx、独孤 5xxx，\n八荒九阳易筋经 3000 出头、葵花 27xx、太玄 3500 出头，都差不多，画面效果八荒最美，易筋经最炫。\n自创秒杀，伤害溢出，具体原因未明。</p>\n<h4>所有武功威力</h4>\n<p>前十项为等级 1-10 时的威力，倒数第一个数字是内力消耗值，倒数第三个数字是攻击范围。</p>\n<pre><code class=\"language-actionscript\">Skills<span class=\"pl-k\">[</span><span class=\"pl-c1\">2</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"弹指神通\"</span>,<span class=\"pl-c1\">0.26</span>,<span class=\"pl-c1\">0.52</span>,<span class=\"pl-c1\">0.78</span>,<span class=\"pl-c1\">1.04</span>,<span class=\"pl-c1\">1.3</span>,<span class=\"pl-c1\">1.56</span>,<span class=\"pl-c1\">1.82</span>,<span class=\"pl-c1\">2.58</span>,<span class=\"pl-c1\">3.34</span>,<span class=\"pl-c1\">4.5</span>,<span class=\"pl-c1\">55</span>,<span class=\"pl-c1\">14</span>,<span class=\"pl-c1\">42</span>,<span class=\"pl-c1\">84</span>,<span class=\"pl-c1\">140</span>,<span class=\"pl-c1\">210</span>,<span class=\"pl-c1\">294</span>,<span class=\"pl-c1\">392</span>,<span class=\"pl-c1\">504</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">32</span>,<span class=\"pl-s\">\"主角指1\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">3</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"腐尸毒\"</span>,<span class=\"pl-c1\">0.18</span>,<span class=\"pl-c1\">0.36</span>,<span class=\"pl-c1\">0.54</span>,<span class=\"pl-c1\">0.72</span>,<span class=\"pl-c1\">0.9</span>,<span class=\"pl-c1\">1.08</span>,<span class=\"pl-c1\">1.26</span>,<span class=\"pl-c1\">1.44</span>,<span class=\"pl-c1\">1.62</span>,<span class=\"pl-c1\">2.5</span>,<span class=\"pl-c1\">45</span>,<span class=\"pl-c1\">9</span>,<span class=\"pl-c1\">29</span>,<span class=\"pl-c1\">58</span>,<span class=\"pl-c1\">97</span>,<span class=\"pl-c1\">146</span>,<span class=\"pl-c1\">205</span>,<span class=\"pl-c1\">273</span>,<span class=\"pl-c1\">352</span>,<span class=\"pl-c1\">440</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">440</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">17</span>,<span class=\"pl-s\">\"主角指1\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">4</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"基本暗器\"</span>,<span class=\"pl-c1\">0.13</span>,<span class=\"pl-c1\">0.26</span>,<span class=\"pl-c1\">0.39</span>,<span class=\"pl-c1\">0.52</span>,<span class=\"pl-c1\">0.65</span>,<span class=\"pl-c1\">0.78</span>,<span class=\"pl-c1\">0.91</span>,<span class=\"pl-c1\">1.04</span>,<span class=\"pl-c1\">1.17</span>,<span class=\"pl-c1\">1.8</span>,<span class=\"pl-c1\">35</span>,<span class=\"pl-c1\">6</span>,<span class=\"pl-c1\">18</span>,<span class=\"pl-c1\">37</span>,<span class=\"pl-c1\">62</span>,<span class=\"pl-c1\">93</span>,<span class=\"pl-c1\">130</span>,<span class=\"pl-c1\">174</span>,<span class=\"pl-c1\">224</span>,<span class=\"pl-c1\">280</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">280</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">12</span>,<span class=\"pl-s\">\"主角指1\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">5</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"满天星\"</span>,<span class=\"pl-c1\">0.15</span>,<span class=\"pl-c1\">0.3</span>,<span class=\"pl-c1\">0.45</span>,<span class=\"pl-c1\">0.6</span>,<span class=\"pl-c1\">0.75</span>,<span class=\"pl-c1\">0.9</span>,<span class=\"pl-c1\">1.05</span>,<span class=\"pl-c1\">1.2</span>,<span class=\"pl-c1\">1.35</span>,<span class=\"pl-c1\">2.2</span>,<span class=\"pl-c1\">60</span>,<span class=\"pl-c1\">11</span>,<span class=\"pl-c1\">34</span>,<span class=\"pl-c1\">69</span>,<span class=\"pl-c1\">115</span>,<span class=\"pl-c1\">173</span>,<span class=\"pl-c1\">242</span>,<span class=\"pl-c1\">323</span>,<span class=\"pl-c1\">416</span>,<span class=\"pl-c1\">520</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">520</span>,<span class=\"pl-c1\">5</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">26</span>,<span class=\"pl-s\">\"主角指1\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">6</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"漫天花雨\"</span>,<span class=\"pl-c1\">0.23</span>,<span class=\"pl-c1\">0.46</span>,<span class=\"pl-c1\">0.69</span>,<span class=\"pl-c1\">0.92</span>,<span class=\"pl-c1\">1.15</span>,<span class=\"pl-c1\">1.38</span>,<span class=\"pl-c1\">1.61</span>,<span class=\"pl-c1\">1.84</span>,<span class=\"pl-c1\">2.07</span>,<span class=\"pl-c1\">3</span>,<span class=\"pl-c1\">60</span>,<span class=\"pl-c1\">11</span>,<span class=\"pl-c1\">34</span>,<span class=\"pl-c1\">69</span>,<span class=\"pl-c1\">115</span>,<span class=\"pl-c1\">173</span>,<span class=\"pl-c1\">242</span>,<span class=\"pl-c1\">323</span>,<span class=\"pl-c1\">416</span>,<span class=\"pl-c1\">520</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">520</span>,<span class=\"pl-c1\">5</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">35</span>,<span class=\"pl-s\">\"主角指1\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">7</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"慕容暗器\"</span>,<span class=\"pl-c1\">0.16</span>,<span class=\"pl-c1\">0.32</span>,<span class=\"pl-c1\">0.48</span>,<span class=\"pl-c1\">0.64</span>,<span class=\"pl-c1\">0.8</span>,<span class=\"pl-c1\">0.96</span>,<span class=\"pl-c1\">1.12</span>,<span class=\"pl-c1\">1.28</span>,<span class=\"pl-c1\">1.44</span>,<span class=\"pl-c1\">2.8</span>,<span class=\"pl-c1\">35</span>,<span class=\"pl-c1\">9</span>,<span class=\"pl-c1\">29</span>,<span class=\"pl-c1\">58</span>,<span class=\"pl-c1\">97</span>,<span class=\"pl-c1\">146</span>,<span class=\"pl-c1\">205</span>,<span class=\"pl-c1\">273</span>,<span class=\"pl-c1\">352</span>,<span class=\"pl-c1\">440</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">440</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">23</span>,<span class=\"pl-s\">\"主角指1\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">8</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"掷针术\"</span>,<span class=\"pl-c1\">0.52</span>,<span class=\"pl-c1\">0.92</span>,<span class=\"pl-c1\">1.36</span>,<span class=\"pl-c1\">1.78</span>,<span class=\"pl-c1\">2.1</span>,<span class=\"pl-c1\">2.52</span>,<span class=\"pl-c1\">2.94</span>,<span class=\"pl-c1\">3.36</span>,<span class=\"pl-c1\">3.78</span>,<span class=\"pl-c1\">4.3</span>,<span class=\"pl-c1\">35</span>,<span class=\"pl-c1\">9</span>,<span class=\"pl-c1\">29</span>,<span class=\"pl-c1\">58</span>,<span class=\"pl-c1\">97</span>,<span class=\"pl-c1\">146</span>,<span class=\"pl-c1\">205</span>,<span class=\"pl-c1\">273</span>,<span class=\"pl-c1\">352</span>,<span class=\"pl-c1\">440</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">440</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">29</span>,<span class=\"pl-s\">\"主角指1\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">9</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"青字九打\"</span>,<span class=\"pl-c1\">0.21</span>,<span class=\"pl-c1\">0.42</span>,<span class=\"pl-c1\">0.63</span>,<span class=\"pl-c1\">0.84</span>,<span class=\"pl-c1\">1.05</span>,<span class=\"pl-c1\">1.26</span>,<span class=\"pl-c1\">1.47</span>,<span class=\"pl-c1\">1.68</span>,<span class=\"pl-c1\">1.89</span>,<span class=\"pl-c1\">2.8</span>,<span class=\"pl-c1\">35</span>,<span class=\"pl-c1\">9</span>,<span class=\"pl-c1\">29</span>,<span class=\"pl-c1\">58</span>,<span class=\"pl-c1\">97</span>,<span class=\"pl-c1\">146</span>,<span class=\"pl-c1\">205</span>,<span class=\"pl-c1\">273</span>,<span class=\"pl-c1\">352</span>,<span class=\"pl-c1\">440</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">250</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">25</span>,<span class=\"pl-s\">\"主角指1\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">10</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"柴刀十八路\"</span>,<span class=\"pl-c1\">0.14</span>,<span class=\"pl-c1\">0.28</span>,<span class=\"pl-c1\">0.42</span>,<span class=\"pl-c1\">0.56</span>,<span class=\"pl-c1\">0.7</span>,<span class=\"pl-c1\">0.84</span>,<span class=\"pl-c1\">0.98</span>,<span class=\"pl-c1\">1.12</span>,<span class=\"pl-c1\">1.36</span>,<span class=\"pl-c1\">3.6</span>,<span class=\"pl-c1\">45</span>,<span class=\"pl-c1\">9</span>,<span class=\"pl-c1\">29</span>,<span class=\"pl-c1\">58</span>,<span class=\"pl-c1\">97</span>,<span class=\"pl-c1\">146</span>,<span class=\"pl-c1\">205</span>,<span class=\"pl-c1\">273</span>,<span class=\"pl-c1\">352</span>,<span class=\"pl-c1\">440</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">440</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">17</span>,<span class=\"pl-s\">\"主角刀1\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">11</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"胡家残刀\"</span>,<span class=\"pl-c1\">0.16</span>,<span class=\"pl-c1\">0.32</span>,<span class=\"pl-c1\">0.48</span>,<span class=\"pl-c1\">0.64</span>,<span class=\"pl-c1\">0.8</span>,<span class=\"pl-c1\">0.96</span>,<span class=\"pl-c1\">1.12</span>,<span class=\"pl-c1\">1.28</span>,<span class=\"pl-c1\">1.44</span>,<span class=\"pl-c1\">3.8</span>,<span class=\"pl-c1\">55</span>,<span class=\"pl-c1\">11</span>,<span class=\"pl-c1\">34</span>,<span class=\"pl-c1\">69</span>,<span class=\"pl-c1\">115</span>,<span class=\"pl-c1\">173</span>,<span class=\"pl-c1\">242</span>,<span class=\"pl-c1\">323</span>,<span class=\"pl-c1\">416</span>,<span class=\"pl-c1\">520</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">520</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">15</span>,<span class=\"pl-s\">\"主角刀2\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">12</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"胡家刀法\"</span>,<span class=\"pl-c1\">0.3</span>,<span class=\"pl-c1\">0.6</span>,<span class=\"pl-c1\">0.9</span>,<span class=\"pl-c1\">1.2</span>,<span class=\"pl-c1\">1.5</span>,<span class=\"pl-c1\">1.8</span>,<span class=\"pl-c1\">2.1</span>,<span class=\"pl-c1\">2.4</span>,<span class=\"pl-c1\">2.7</span>,<span class=\"pl-c1\">4.8</span>,<span class=\"pl-c1\">40</span>,<span class=\"pl-c1\">18</span>,<span class=\"pl-c1\">56</span>,<span class=\"pl-c1\">113</span>,<span class=\"pl-c1\">188</span>,<span class=\"pl-c1\">283</span>,<span class=\"pl-c1\">396</span>,<span class=\"pl-c1\">528</span>,<span class=\"pl-c1\">680</span>,<span class=\"pl-c1\">850</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">850</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">42</span>,<span class=\"pl-s\">\"主角刀2\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">13</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"火焰刀\"</span>,<span class=\"pl-c1\">0.25</span>,<span class=\"pl-c1\">0.5</span>,<span class=\"pl-c1\">0.75</span>,<span class=\"pl-c1\">1</span>,<span class=\"pl-c1\">1.25</span>,<span class=\"pl-c1\">1.5</span>,<span class=\"pl-c1\">1.75</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">2.25</span>,<span class=\"pl-c1\">3.8</span>,<span class=\"pl-c1\">60</span>,<span class=\"pl-c1\">14</span>,<span class=\"pl-c1\">42</span>,<span class=\"pl-c1\">84</span>,<span class=\"pl-c1\">140</span>,<span class=\"pl-c1\">210</span>,<span class=\"pl-c1\">294</span>,<span class=\"pl-c1\">392</span>,<span class=\"pl-c1\">504</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">35</span>,<span class=\"pl-s\">\"主角刀3\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">14</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"基本刀法\"</span>,<span class=\"pl-c1\">0.1</span>,<span class=\"pl-c1\">0.2</span>,<span class=\"pl-c1\">0.3</span>,<span class=\"pl-c1\">0.4</span>,<span class=\"pl-c1\">0.5</span>,<span class=\"pl-c1\">0.6</span>,<span class=\"pl-c1\">0.7</span>,<span class=\"pl-c1\">0.8</span>,<span class=\"pl-c1\">0.9</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">35</span>,<span class=\"pl-c1\">6</span>,<span class=\"pl-c1\">18</span>,<span class=\"pl-c1\">37</span>,<span class=\"pl-c1\">62</span>,<span class=\"pl-c1\">93</span>,<span class=\"pl-c1\">130</span>,<span class=\"pl-c1\">174</span>,<span class=\"pl-c1\">224</span>,<span class=\"pl-c1\">280</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">280</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">12</span>,<span class=\"pl-s\">\"主角刀1\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">15</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"狂风刀法\"</span>,<span class=\"pl-c1\">0.21</span>,<span class=\"pl-c1\">0.42</span>,<span class=\"pl-c1\">0.63</span>,<span class=\"pl-c1\">0.84</span>,<span class=\"pl-c1\">1.05</span>,<span class=\"pl-c1\">1.26</span>,<span class=\"pl-c1\">1.47</span>,<span class=\"pl-c1\">1.68</span>,<span class=\"pl-c1\">1.89</span>,<span class=\"pl-c1\">3.3</span>,<span class=\"pl-c1\">25</span>,<span class=\"pl-c1\">11</span>,<span class=\"pl-c1\">34</span>,<span class=\"pl-c1\">69</span>,<span class=\"pl-c1\">115</span>,<span class=\"pl-c1\">173</span>,<span class=\"pl-c1\">242</span>,<span class=\"pl-c1\">323</span>,<span class=\"pl-c1\">416</span>,<span class=\"pl-c1\">520</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">520</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">27</span>,<span class=\"pl-s\">\"主角刀1\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">16</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"慕容刀法\"</span>,<span class=\"pl-c1\">0.13</span>,<span class=\"pl-c1\">0.26</span>,<span class=\"pl-c1\">0.39</span>,<span class=\"pl-c1\">0.52</span>,<span class=\"pl-c1\">0.65</span>,<span class=\"pl-c1\">0.78</span>,<span class=\"pl-c1\">0.91</span>,<span class=\"pl-c1\">1.04</span>,<span class=\"pl-c1\">1.17</span>,<span class=\"pl-c1\">2.5</span>,<span class=\"pl-c1\">35</span>,<span class=\"pl-c1\">9</span>,<span class=\"pl-c1\">29</span>,<span class=\"pl-c1\">58</span>,<span class=\"pl-c1\">97</span>,<span class=\"pl-c1\">146</span>,<span class=\"pl-c1\">205</span>,<span class=\"pl-c1\">273</span>,<span class=\"pl-c1\">352</span>,<span class=\"pl-c1\">440</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">440</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">23</span>,<span class=\"pl-s\">\"主角刀2\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">17</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"奇门三才刀\"</span>,<span class=\"pl-c1\">0.19</span>,<span class=\"pl-c1\">0.38</span>,<span class=\"pl-c1\">0.57</span>,<span class=\"pl-c1\">0.76</span>,<span class=\"pl-c1\">0.95</span>,<span class=\"pl-c1\">1.14</span>,<span class=\"pl-c1\">1.33</span>,<span class=\"pl-c1\">1.52</span>,<span class=\"pl-c1\">1.71</span>,<span class=\"pl-c1\">2.2</span>,<span class=\"pl-c1\">55</span>,<span class=\"pl-c1\">9</span>,<span class=\"pl-c1\">29</span>,<span class=\"pl-c1\">58</span>,<span class=\"pl-c1\">97</span>,<span class=\"pl-c1\">146</span>,<span class=\"pl-c1\">205</span>,<span class=\"pl-c1\">273</span>,<span class=\"pl-c1\">352</span>,<span class=\"pl-c1\">440</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">440</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">18</span>,<span class=\"pl-s\">\"主角刀2\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">18</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"燃木刀法\"</span>,<span class=\"pl-c1\">0.24</span>,<span class=\"pl-c1\">0.48</span>,<span class=\"pl-c1\">0.72</span>,<span class=\"pl-c1\">0.96</span>,<span class=\"pl-c1\">1.2</span>,<span class=\"pl-c1\">1.44</span>,<span class=\"pl-c1\">1.68</span>,<span class=\"pl-c1\">1.92</span>,<span class=\"pl-c1\">2.16</span>,<span class=\"pl-c1\">2.7</span>,<span class=\"pl-c1\">50</span>,<span class=\"pl-c1\">14</span>,<span class=\"pl-c1\">42</span>,<span class=\"pl-c1\">84</span>,<span class=\"pl-c1\">140</span>,<span class=\"pl-c1\">210</span>,<span class=\"pl-c1\">294</span>,<span class=\"pl-c1\">392</span>,<span class=\"pl-c1\">504</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">37</span>,<span class=\"pl-s\">\"主角刀3\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">19</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"五虎断门刀\"</span>,<span class=\"pl-c1\">0.17</span>,<span class=\"pl-c1\">0.34</span>,<span class=\"pl-c1\">0.51</span>,<span class=\"pl-c1\">0.68</span>,<span class=\"pl-c1\">0.85</span>,<span class=\"pl-c1\">1.02</span>,<span class=\"pl-c1\">1.19</span>,<span class=\"pl-c1\">1.36</span>,<span class=\"pl-c1\">1.53</span>,<span class=\"pl-c1\">2.9</span>,<span class=\"pl-c1\">55</span>,<span class=\"pl-c1\">9</span>,<span class=\"pl-c1\">29</span>,<span class=\"pl-c1\">58</span>,<span class=\"pl-c1\">97</span>,<span class=\"pl-c1\">146</span>,<span class=\"pl-c1\">205</span>,<span class=\"pl-c1\">273</span>,<span class=\"pl-c1\">352</span>,<span class=\"pl-c1\">440</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">440</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">22</span>,<span class=\"pl-s\">\"主角刀3\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">20</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"修罗刀法\"</span>,<span class=\"pl-c1\">0.21</span>,<span class=\"pl-c1\">0.42</span>,<span class=\"pl-c1\">0.63</span>,<span class=\"pl-c1\">0.84</span>,<span class=\"pl-c1\">1.05</span>,<span class=\"pl-c1\">1.26</span>,<span class=\"pl-c1\">1.47</span>,<span class=\"pl-c1\">1.68</span>,<span class=\"pl-c1\">1.89</span>,<span class=\"pl-c1\">3.3</span>,<span class=\"pl-c1\">45</span>,<span class=\"pl-c1\">11</span>,<span class=\"pl-c1\">34</span>,<span class=\"pl-c1\">69</span>,<span class=\"pl-c1\">115</span>,<span class=\"pl-c1\">173</span>,<span class=\"pl-c1\">242</span>,<span class=\"pl-c1\">323</span>,<span class=\"pl-c1\">416</span>,<span class=\"pl-c1\">520</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">520</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">25</span>,<span class=\"pl-s\">\"主角刀1\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">21</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"玄虚刀法\"</span>,<span class=\"pl-c1\">0.24</span>,<span class=\"pl-c1\">0.48</span>,<span class=\"pl-c1\">0.72</span>,<span class=\"pl-c1\">0.96</span>,<span class=\"pl-c1\">1.2</span>,<span class=\"pl-c1\">1.44</span>,<span class=\"pl-c1\">1.68</span>,<span class=\"pl-c1\">1.92</span>,<span class=\"pl-c1\">2.16</span>,<span class=\"pl-c1\">3.7</span>,<span class=\"pl-c1\">65</span>,<span class=\"pl-c1\">14</span>,<span class=\"pl-c1\">42</span>,<span class=\"pl-c1\">84</span>,<span class=\"pl-c1\">140</span>,<span class=\"pl-c1\">210</span>,<span class=\"pl-c1\">294</span>,<span class=\"pl-c1\">392</span>,<span class=\"pl-c1\">504</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">30</span>,<span class=\"pl-s\">\"主角刀2\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">22</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"血刀刀法\"</span>,<span class=\"pl-c1\">0.28</span>,<span class=\"pl-c1\">0.56</span>,<span class=\"pl-c1\">0.84</span>,<span class=\"pl-c1\">1.12</span>,<span class=\"pl-c1\">1.4</span>,<span class=\"pl-c1\">1.68</span>,<span class=\"pl-c1\">1.96</span>,<span class=\"pl-c1\">2.14</span>,<span class=\"pl-c1\">2.42</span>,<span class=\"pl-c1\">4.1</span>,<span class=\"pl-c1\">40</span>,<span class=\"pl-c1\">16</span>,<span class=\"pl-c1\">50</span>,<span class=\"pl-c1\">100</span>,<span class=\"pl-c1\">166</span>,<span class=\"pl-c1\">250</span>,<span class=\"pl-c1\">350</span>,<span class=\"pl-c1\">466</span>,<span class=\"pl-c1\">600</span>,<span class=\"pl-c1\">750</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">750</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">38</span>,<span class=\"pl-s\">\"主角刀3\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">23</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"打狗棒法\"</span>,<span class=\"pl-c1\">0.3</span>,<span class=\"pl-c1\">0.6</span>,<span class=\"pl-c1\">0.9</span>,<span class=\"pl-c1\">1.2</span>,<span class=\"pl-c1\">1.5</span>,<span class=\"pl-c1\">1.8</span>,<span class=\"pl-c1\">2.1</span>,<span class=\"pl-c1\">2.4</span>,<span class=\"pl-c1\">3</span>,<span class=\"pl-c1\">4.9</span>,<span class=\"pl-c1\">65</span>,<span class=\"pl-c1\">18</span>,<span class=\"pl-c1\">56</span>,<span class=\"pl-c1\">113</span>,<span class=\"pl-c1\">188</span>,<span class=\"pl-c1\">283</span>,<span class=\"pl-c1\">396</span>,<span class=\"pl-c1\">528</span>,<span class=\"pl-c1\">680</span>,<span class=\"pl-c1\">850</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">850</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">42</span>,<span class=\"pl-s\">\"主角棍1\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">24</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"伏魔杖法\"</span>,<span class=\"pl-c1\">0.18</span>,<span class=\"pl-c1\">0.36</span>,<span class=\"pl-c1\">0.54</span>,<span class=\"pl-c1\">0.72</span>,<span class=\"pl-c1\">0.9</span>,<span class=\"pl-c1\">1.08</span>,<span class=\"pl-c1\">1.26</span>,<span class=\"pl-c1\">1.44</span>,<span class=\"pl-c1\">1.62</span>,<span class=\"pl-c1\">3</span>,<span class=\"pl-c1\">60</span>,<span class=\"pl-c1\">14</span>,<span class=\"pl-c1\">42</span>,<span class=\"pl-c1\">84</span>,<span class=\"pl-c1\">140</span>,<span class=\"pl-c1\">210</span>,<span class=\"pl-c1\">294</span>,<span class=\"pl-c1\">392</span>,<span class=\"pl-c1\">504</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">27</span>,<span class=\"pl-s\">\"主角棍2\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">25</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"基本棍法\"</span>,<span class=\"pl-c1\">0.1</span>,<span class=\"pl-c1\">0.2</span>,<span class=\"pl-c1\">0.3</span>,<span class=\"pl-c1\">0.4</span>,<span class=\"pl-c1\">0.5</span>,<span class=\"pl-c1\">0.6</span>,<span class=\"pl-c1\">0.7</span>,<span class=\"pl-c1\">0.8</span>,<span class=\"pl-c1\">0.9</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">35</span>,<span class=\"pl-c1\">6</span>,<span class=\"pl-c1\">18</span>,<span class=\"pl-c1\">37</span>,<span class=\"pl-c1\">62</span>,<span class=\"pl-c1\">93</span>,<span class=\"pl-c1\">130</span>,<span class=\"pl-c1\">174</span>,<span class=\"pl-c1\">224</span>,<span class=\"pl-c1\">280</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">280</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">12</span>,<span class=\"pl-s\">\"主角棍1\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">26</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"叫化棒法\"</span>,<span class=\"pl-c1\">0.16</span>,<span class=\"pl-c1\">0.32</span>,<span class=\"pl-c1\">0.48</span>,<span class=\"pl-c1\">0.64</span>,<span class=\"pl-c1\">0.8</span>,<span class=\"pl-c1\">0.96</span>,<span class=\"pl-c1\">1.12</span>,<span class=\"pl-c1\">1.28</span>,<span class=\"pl-c1\">1.44</span>,<span class=\"pl-c1\">2.8</span>,<span class=\"pl-c1\">40</span>,<span class=\"pl-c1\">9</span>,<span class=\"pl-c1\">29</span>,<span class=\"pl-c1\">58</span>,<span class=\"pl-c1\">97</span>,<span class=\"pl-c1\">146</span>,<span class=\"pl-c1\">205</span>,<span class=\"pl-c1\">273</span>,<span class=\"pl-c1\">352</span>,<span class=\"pl-c1\">440</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">440</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">20</span>,<span class=\"pl-s\">\"主角棍3\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">27</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"金刚降魔杵\"</span>,<span class=\"pl-c1\">0.21</span>,<span class=\"pl-c1\">0.42</span>,<span class=\"pl-c1\">0.63</span>,<span class=\"pl-c1\">0.84</span>,<span class=\"pl-c1\">1.05</span>,<span class=\"pl-c1\">1.36</span>,<span class=\"pl-c1\">1.57</span>,<span class=\"pl-c1\">1.78</span>,<span class=\"pl-c1\">1.99</span>,<span class=\"pl-c1\">3.4</span>,<span class=\"pl-c1\">55</span>,<span class=\"pl-c1\">14</span>,<span class=\"pl-c1\">42</span>,<span class=\"pl-c1\">84</span>,<span class=\"pl-c1\">140</span>,<span class=\"pl-c1\">210</span>,<span class=\"pl-c1\">294</span>,<span class=\"pl-c1\">392</span>,<span class=\"pl-c1\">504</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">28</span>,<span class=\"pl-s\">\"主角棍2\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">28</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"灵蛇杖法\"</span>,<span class=\"pl-c1\">0.27</span>,<span class=\"pl-c1\">0.54</span>,<span class=\"pl-c1\">0.81</span>,<span class=\"pl-c1\">1.08</span>,<span class=\"pl-c1\">1.35</span>,<span class=\"pl-c1\">1.62</span>,<span class=\"pl-c1\">1.89</span>,<span class=\"pl-c1\">2.16</span>,<span class=\"pl-c1\">2.43</span>,<span class=\"pl-c1\">4</span>,<span class=\"pl-c1\">40</span>,<span class=\"pl-c1\">11</span>,<span class=\"pl-c1\">34</span>,<span class=\"pl-c1\">69</span>,<span class=\"pl-c1\">115</span>,<span class=\"pl-c1\">173</span>,<span class=\"pl-c1\">242</span>,<span class=\"pl-c1\">323</span>,<span class=\"pl-c1\">416</span>,<span class=\"pl-c1\">520</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">520</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">30</span>,<span class=\"pl-s\">\"主角棍2\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">29</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"慕容棍法\"</span>,<span class=\"pl-c1\">0.13</span>,<span class=\"pl-c1\">0.26</span>,<span class=\"pl-c1\">0.39</span>,<span class=\"pl-c1\">0.52</span>,<span class=\"pl-c1\">0.65</span>,<span class=\"pl-c1\">0.78</span>,<span class=\"pl-c1\">0.91</span>,<span class=\"pl-c1\">1.04</span>,<span class=\"pl-c1\">1.17</span>,<span class=\"pl-c1\">2.5</span>,<span class=\"pl-c1\">35</span>,<span class=\"pl-c1\">9</span>,<span class=\"pl-c1\">29</span>,<span class=\"pl-c1\">58</span>,<span class=\"pl-c1\">97</span>,<span class=\"pl-c1\">146</span>,<span class=\"pl-c1\">205</span>,<span class=\"pl-c1\">273</span>,<span class=\"pl-c1\">352</span>,<span class=\"pl-c1\">440</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">440</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">23</span>,<span class=\"pl-s\">\"主角棍3\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">30</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"太祖棍\"</span>,<span class=\"pl-c1\">0.16</span>,<span class=\"pl-c1\">0.32</span>,<span class=\"pl-c1\">0.48</span>,<span class=\"pl-c1\">0.64</span>,<span class=\"pl-c1\">0.8</span>,<span class=\"pl-c1\">0.96</span>,<span class=\"pl-c1\">1.12</span>,<span class=\"pl-c1\">1.28</span>,<span class=\"pl-c1\">1.44</span>,<span class=\"pl-c1\">2.8</span>,<span class=\"pl-c1\">40</span>,<span class=\"pl-c1\">9</span>,<span class=\"pl-c1\">29</span>,<span class=\"pl-c1\">58</span>,<span class=\"pl-c1\">97</span>,<span class=\"pl-c1\">146</span>,<span class=\"pl-c1\">205</span>,<span class=\"pl-c1\">273</span>,<span class=\"pl-c1\">352</span>,<span class=\"pl-c1\">440</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">440</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">17</span>,<span class=\"pl-s\">\"主角棍2\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">31</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"韦陀杖法\"</span>,<span class=\"pl-c1\">0.21</span>,<span class=\"pl-c1\">0.42</span>,<span class=\"pl-c1\">0.63</span>,<span class=\"pl-c1\">0.84</span>,<span class=\"pl-c1\">1.05</span>,<span class=\"pl-c1\">1.36</span>,<span class=\"pl-c1\">1.57</span>,<span class=\"pl-c1\">1.78</span>,<span class=\"pl-c1\">1.99</span>,<span class=\"pl-c1\">3.4</span>,<span class=\"pl-c1\">40</span>,<span class=\"pl-c1\">11</span>,<span class=\"pl-c1\">34</span>,<span class=\"pl-c1\">69</span>,<span class=\"pl-c1\">115</span>,<span class=\"pl-c1\">173</span>,<span class=\"pl-c1\">242</span>,<span class=\"pl-c1\">323</span>,<span class=\"pl-c1\">416</span>,<span class=\"pl-c1\">520</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">520</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">18</span>,<span class=\"pl-s\">\"主角棍2\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">32</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"无上大力杵法\"</span>,<span class=\"pl-c1\">0.24</span>,<span class=\"pl-c1\">0.48</span>,<span class=\"pl-c1\">0.72</span>,<span class=\"pl-c1\">0.96</span>,<span class=\"pl-c1\">1.2</span>,<span class=\"pl-c1\">1.44</span>,<span class=\"pl-c1\">1.68</span>,<span class=\"pl-c1\">1.92</span>,<span class=\"pl-c1\">2.16</span>,<span class=\"pl-c1\">3.7</span>,<span class=\"pl-c1\">55</span>,<span class=\"pl-c1\">14</span>,<span class=\"pl-c1\">42</span>,<span class=\"pl-c1\">84</span>,<span class=\"pl-c1\">140</span>,<span class=\"pl-c1\">210</span>,<span class=\"pl-c1\">294</span>,<span class=\"pl-c1\">392</span>,<span class=\"pl-c1\">504</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">38</span>,<span class=\"pl-s\">\"主角棍3\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">33</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"百变千幻云雾十三剑\"</span>,<span class=\"pl-c1\">0.24</span>,<span class=\"pl-c1\">0.48</span>,<span class=\"pl-c1\">0.72</span>,<span class=\"pl-c1\">0.96</span>,<span class=\"pl-c1\">1.2</span>,<span class=\"pl-c1\">1.44</span>,<span class=\"pl-c1\">1.68</span>,<span class=\"pl-c1\">1.92</span>,<span class=\"pl-c1\">2.16</span>,<span class=\"pl-c1\">3.7</span>,<span class=\"pl-c1\">58</span>,<span class=\"pl-c1\">14</span>,<span class=\"pl-c1\">42</span>,<span class=\"pl-c1\">84</span>,<span class=\"pl-c1\">140</span>,<span class=\"pl-c1\">210</span>,<span class=\"pl-c1\">294</span>,<span class=\"pl-c1\">392</span>,<span class=\"pl-c1\">504</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">29</span>,<span class=\"pl-s\">\"主角剑1\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">34</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"辟邪剑法\"</span>,<span class=\"pl-c1\">0.28</span>,<span class=\"pl-c1\">0.56</span>,<span class=\"pl-c1\">0.84</span>,<span class=\"pl-c1\">1.12</span>,<span class=\"pl-c1\">1.4</span>,<span class=\"pl-c1\">1.68</span>,<span class=\"pl-c1\">1.96</span>,<span class=\"pl-c1\">2.14</span>,<span class=\"pl-c1\">2.42</span>,<span class=\"pl-c1\">4.1</span>,<span class=\"pl-c1\">20</span>,<span class=\"pl-c1\">18</span>,<span class=\"pl-c1\">56</span>,<span class=\"pl-c1\">113</span>,<span class=\"pl-c1\">188</span>,<span class=\"pl-c1\">283</span>,<span class=\"pl-c1\">396</span>,<span class=\"pl-c1\">528</span>,<span class=\"pl-c1\">680</span>,<span class=\"pl-c1\">850</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">850</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">48</span>,<span class=\"pl-s\">\"主角剑1\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">35</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"冰雪剑法\"</span>,<span class=\"pl-c1\">0.21</span>,<span class=\"pl-c1\">0.42</span>,<span class=\"pl-c1\">0.63</span>,<span class=\"pl-c1\">0.84</span>,<span class=\"pl-c1\">1.05</span>,<span class=\"pl-c1\">1.26</span>,<span class=\"pl-c1\">1.47</span>,<span class=\"pl-c1\">1.68</span>,<span class=\"pl-c1\">1.89</span>,<span class=\"pl-c1\">3.3</span>,<span class=\"pl-c1\">45</span>,<span class=\"pl-c1\">9</span>,<span class=\"pl-c1\">29</span>,<span class=\"pl-c1\">58</span>,<span class=\"pl-c1\">97</span>,<span class=\"pl-c1\">146</span>,<span class=\"pl-c1\">205</span>,<span class=\"pl-c1\">273</span>,<span class=\"pl-c1\">352</span>,<span class=\"pl-c1\">440</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">440</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">5</span>,<span class=\"pl-c1\">17</span>,<span class=\"pl-s\">\"主角剑2\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">36</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"达摩剑法\"</span>,<span class=\"pl-c1\">0.25</span>,<span class=\"pl-c1\">0.5</span>,<span class=\"pl-c1\">0.75</span>,<span class=\"pl-c1\">1</span>,<span class=\"pl-c1\">1.25</span>,<span class=\"pl-c1\">1.5</span>,<span class=\"pl-c1\">1.75</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">2.25</span>,<span class=\"pl-c1\">3.8</span>,<span class=\"pl-c1\">50</span>,<span class=\"pl-c1\">14</span>,<span class=\"pl-c1\">42</span>,<span class=\"pl-c1\">84</span>,<span class=\"pl-c1\">140</span>,<span class=\"pl-c1\">210</span>,<span class=\"pl-c1\">294</span>,<span class=\"pl-c1\">392</span>,<span class=\"pl-c1\">504</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">29</span>,<span class=\"pl-s\">\"主角剑1\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">37</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"独孤九剑\"</span>,<span class=\"pl-c1\">0.3</span>,<span class=\"pl-c1\">0.6</span>,<span class=\"pl-c1\">0.9</span>,<span class=\"pl-c1\">1.2</span>,<span class=\"pl-c1\">1.5</span>,<span class=\"pl-c1\">1.8</span>,<span class=\"pl-c1\">2.1</span>,<span class=\"pl-c1\">2.4</span>,<span class=\"pl-c1\">3.1</span>,<span class=\"pl-c1\">4</span>,<span class=\"pl-c1\">45</span>,<span class=\"pl-c1\">18</span>,<span class=\"pl-c1\">56</span>,<span class=\"pl-c1\">113</span>,<span class=\"pl-c1\">188</span>,<span class=\"pl-c1\">283</span>,<span class=\"pl-c1\">396</span>,<span class=\"pl-c1\">528</span>,<span class=\"pl-c1\">680</span>,<span class=\"pl-c1\">850</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">850</span>,<span class=\"pl-c1\">5</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">25</span>,<span class=\"pl-s\">\"主角剑1\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">38</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"段家剑法\"</span>,<span class=\"pl-c1\">0.13</span>,<span class=\"pl-c1\">0.26</span>,<span class=\"pl-c1\">0.39</span>,<span class=\"pl-c1\">0.52</span>,<span class=\"pl-c1\">0.65</span>,<span class=\"pl-c1\">0.78</span>,<span class=\"pl-c1\">0.91</span>,<span class=\"pl-c1\">1.04</span>,<span class=\"pl-c1\">1.17</span>,<span class=\"pl-c1\">2.5</span>,<span class=\"pl-c1\">35</span>,<span class=\"pl-c1\">9</span>,<span class=\"pl-c1\">29</span>,<span class=\"pl-c1\">58</span>,<span class=\"pl-c1\">97</span>,<span class=\"pl-c1\">146</span>,<span class=\"pl-c1\">205</span>,<span class=\"pl-c1\">273</span>,<span class=\"pl-c1\">352</span>,<span class=\"pl-c1\">440</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">440</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">18</span>,<span class=\"pl-s\">\"主角剑2\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">39</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"连环三仙剑\"</span>,<span class=\"pl-c1\">0.22</span>,<span class=\"pl-c1\">0.44</span>,<span class=\"pl-c1\">0.66</span>,<span class=\"pl-c1\">0.88</span>,<span class=\"pl-c1\">1.1</span>,<span class=\"pl-c1\">1.32</span>,<span class=\"pl-c1\">1.54</span>,<span class=\"pl-c1\">1.76</span>,<span class=\"pl-c1\">1.98</span>,<span class=\"pl-c1\">3.5</span>,<span class=\"pl-c1\">40</span>,<span class=\"pl-c1\">14</span>,<span class=\"pl-c1\">42</span>,<span class=\"pl-c1\">84</span>,<span class=\"pl-c1\">140</span>,<span class=\"pl-c1\">210</span>,<span class=\"pl-c1\">294</span>,<span class=\"pl-c1\">392</span>,<span class=\"pl-c1\">504</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">29</span>,<span class=\"pl-s\">\"主角剑3\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">40</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"华山剑法\"</span>,<span class=\"pl-c1\">0.13</span>,<span class=\"pl-c1\">0.26</span>,<span class=\"pl-c1\">0.39</span>,<span class=\"pl-c1\">0.52</span>,<span class=\"pl-c1\">0.65</span>,<span class=\"pl-c1\">0.78</span>,<span class=\"pl-c1\">0.91</span>,<span class=\"pl-c1\">1.04</span>,<span class=\"pl-c1\">1.17</span>,<span class=\"pl-c1\">2.5</span>,<span class=\"pl-c1\">35</span>,<span class=\"pl-c1\">9</span>,<span class=\"pl-c1\">29</span>,<span class=\"pl-c1\">58</span>,<span class=\"pl-c1\">97</span>,<span class=\"pl-c1\">146</span>,<span class=\"pl-c1\">205</span>,<span class=\"pl-c1\">273</span>,<span class=\"pl-c1\">352</span>,<span class=\"pl-c1\">440</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">440</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">17</span>,<span class=\"pl-s\">\"主角剑1\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">41</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"回风拂柳剑\"</span>,<span class=\"pl-c1\">0.21</span>,<span class=\"pl-c1\">0.42</span>,<span class=\"pl-c1\">0.63</span>,<span class=\"pl-c1\">0.84</span>,<span class=\"pl-c1\">1.05</span>,<span class=\"pl-c1\">1.36</span>,<span class=\"pl-c1\">1.57</span>,<span class=\"pl-c1\">1.78</span>,<span class=\"pl-c1\">1.99</span>,<span class=\"pl-c1\">3.4</span>,<span class=\"pl-c1\">45</span>,<span class=\"pl-c1\">9</span>,<span class=\"pl-c1\">29</span>,<span class=\"pl-c1\">58</span>,<span class=\"pl-c1\">97</span>,<span class=\"pl-c1\">146</span>,<span class=\"pl-c1\">205</span>,<span class=\"pl-c1\">273</span>,<span class=\"pl-c1\">352</span>,<span class=\"pl-c1\">440</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">440</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">25</span>,<span class=\"pl-s\">\"主角剑2\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">42</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"回风落雁剑\"</span>,<span class=\"pl-c1\">0.22</span>,<span class=\"pl-c1\">0.44</span>,<span class=\"pl-c1\">0.66</span>,<span class=\"pl-c1\">0.88</span>,<span class=\"pl-c1\">1.1</span>,<span class=\"pl-c1\">1.32</span>,<span class=\"pl-c1\">1.54</span>,<span class=\"pl-c1\">1.76</span>,<span class=\"pl-c1\">1.98</span>,<span class=\"pl-c1\">3.5</span>,<span class=\"pl-c1\">48</span>,<span class=\"pl-c1\">14</span>,<span class=\"pl-c1\">42</span>,<span class=\"pl-c1\">84</span>,<span class=\"pl-c1\">140</span>,<span class=\"pl-c1\">210</span>,<span class=\"pl-c1\">294</span>,<span class=\"pl-c1\">392</span>,<span class=\"pl-c1\">504</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">29</span>,<span class=\"pl-s\">\"主角剑3\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">43</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"基本剑法\"</span>,<span class=\"pl-c1\">0.1</span>,<span class=\"pl-c1\">0.2</span>,<span class=\"pl-c1\">0.3</span>,<span class=\"pl-c1\">0.4</span>,<span class=\"pl-c1\">0.5</span>,<span class=\"pl-c1\">0.6</span>,<span class=\"pl-c1\">0.7</span>,<span class=\"pl-c1\">0.8</span>,<span class=\"pl-c1\">0.9</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">35</span>,<span class=\"pl-c1\">6</span>,<span class=\"pl-c1\">18</span>,<span class=\"pl-c1\">37</span>,<span class=\"pl-c1\">62</span>,<span class=\"pl-c1\">93</span>,<span class=\"pl-c1\">130</span>,<span class=\"pl-c1\">174</span>,<span class=\"pl-c1\">224</span>,<span class=\"pl-c1\">280</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">280</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">12</span>,<span class=\"pl-s\">\"主角剑3\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">44</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"金蛇剑法\"</span>,<span class=\"pl-c1\">0.28</span>,<span class=\"pl-c1\">0.56</span>,<span class=\"pl-c1\">0.84</span>,<span class=\"pl-c1\">1.12</span>,<span class=\"pl-c1\">1.4</span>,<span class=\"pl-c1\">1.68</span>,<span class=\"pl-c1\">1.96</span>,<span class=\"pl-c1\">2.14</span>,<span class=\"pl-c1\">2.42</span>,<span class=\"pl-c1\">4.1</span>,<span class=\"pl-c1\">60</span>,<span class=\"pl-c1\">16</span>,<span class=\"pl-c1\">50</span>,<span class=\"pl-c1\">100</span>,<span class=\"pl-c1\">166</span>,<span class=\"pl-c1\">250</span>,<span class=\"pl-c1\">350</span>,<span class=\"pl-c1\">466</span>,<span class=\"pl-c1\">600</span>,<span class=\"pl-c1\">750</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">750</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">35</span>,<span class=\"pl-s\">\"主角剑2\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">45</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"快慢十七路\"</span>,<span class=\"pl-c1\">0.22</span>,<span class=\"pl-c1\">0.44</span>,<span class=\"pl-c1\">0.66</span>,<span class=\"pl-c1\">0.88</span>,<span class=\"pl-c1\">1.1</span>,<span class=\"pl-c1\">1.32</span>,<span class=\"pl-c1\">1.54</span>,<span class=\"pl-c1\">1.76</span>,<span class=\"pl-c1\">1.98</span>,<span class=\"pl-c1\">3.5</span>,<span class=\"pl-c1\">70</span>,<span class=\"pl-c1\">9</span>,<span class=\"pl-c1\">29</span>,<span class=\"pl-c1\">58</span>,<span class=\"pl-c1\">97</span>,<span class=\"pl-c1\">146</span>,<span class=\"pl-c1\">205</span>,<span class=\"pl-c1\">273</span>,<span class=\"pl-c1\">352</span>,<span class=\"pl-c1\">440</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">440</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">29</span>,<span class=\"pl-s\">\"主角剑1\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">46</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"狂风快剑\"</span>,<span class=\"pl-c1\">0.23</span>,<span class=\"pl-c1\">0.46</span>,<span class=\"pl-c1\">0.69</span>,<span class=\"pl-c1\">0.92</span>,<span class=\"pl-c1\">1.15</span>,<span class=\"pl-c1\">1.38</span>,<span class=\"pl-c1\">1.61</span>,<span class=\"pl-c1\">1.84</span>,<span class=\"pl-c1\">2.07</span>,<span class=\"pl-c1\">3.6</span>,<span class=\"pl-c1\">30</span>,<span class=\"pl-c1\">9</span>,<span class=\"pl-c1\">29</span>,<span class=\"pl-c1\">58</span>,<span class=\"pl-c1\">97</span>,<span class=\"pl-c1\">146</span>,<span class=\"pl-c1\">205</span>,<span class=\"pl-c1\">273</span>,<span class=\"pl-c1\">352</span>,<span class=\"pl-c1\">440</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">440</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">32</span>,<span class=\"pl-s\">\"主角剑1\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">47</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"苗家剑法\"</span>,<span class=\"pl-c1\">0.27</span>,<span class=\"pl-c1\">0.54</span>,<span class=\"pl-c1\">0.81</span>,<span class=\"pl-c1\">1.08</span>,<span class=\"pl-c1\">1.35</span>,<span class=\"pl-c1\">1.62</span>,<span class=\"pl-c1\">1.89</span>,<span class=\"pl-c1\">2.16</span>,<span class=\"pl-c1\">2.43</span>,<span class=\"pl-c1\">4</span>,<span class=\"pl-c1\">55</span>,<span class=\"pl-c1\">16</span>,<span class=\"pl-c1\">50</span>,<span class=\"pl-c1\">100</span>,<span class=\"pl-c1\">166</span>,<span class=\"pl-c1\">250</span>,<span class=\"pl-c1\">350</span>,<span class=\"pl-c1\">466</span>,<span class=\"pl-c1\">600</span>,<span class=\"pl-c1\">750</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">750</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">40</span>,<span class=\"pl-s\">\"主角剑2\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">48</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"灭绝剑法\"</span>,<span class=\"pl-c1\">0.22</span>,<span class=\"pl-c1\">0.44</span>,<span class=\"pl-c1\">0.66</span>,<span class=\"pl-c1\">0.88</span>,<span class=\"pl-c1\">1.1</span>,<span class=\"pl-c1\">1.32</span>,<span class=\"pl-c1\">1.54</span>,<span class=\"pl-c1\">1.76</span>,<span class=\"pl-c1\">1.98</span>,<span class=\"pl-c1\">3.5</span>,<span class=\"pl-c1\">50</span>,<span class=\"pl-c1\">14</span>,<span class=\"pl-c1\">42</span>,<span class=\"pl-c1\">84</span>,<span class=\"pl-c1\">140</span>,<span class=\"pl-c1\">210</span>,<span class=\"pl-c1\">294</span>,<span class=\"pl-c1\">392</span>,<span class=\"pl-c1\">504</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">33</span>,<span class=\"pl-s\">\"主角剑3\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">49</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"慕容剑法\"</span>,<span class=\"pl-c1\">0.11</span>,<span class=\"pl-c1\">0.22</span>,<span class=\"pl-c1\">0.33</span>,<span class=\"pl-c1\">0.44</span>,<span class=\"pl-c1\">0.55</span>,<span class=\"pl-c1\">0.66</span>,<span class=\"pl-c1\">0.77</span>,<span class=\"pl-c1\">0.88</span>,<span class=\"pl-c1\">0.99</span>,<span class=\"pl-c1\">2.3</span>,<span class=\"pl-c1\">35</span>,<span class=\"pl-c1\">9</span>,<span class=\"pl-c1\">29</span>,<span class=\"pl-c1\">58</span>,<span class=\"pl-c1\">97</span>,<span class=\"pl-c1\">146</span>,<span class=\"pl-c1\">205</span>,<span class=\"pl-c1\">273</span>,<span class=\"pl-c1\">352</span>,<span class=\"pl-c1\">440</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">440</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">23</span>,<span class=\"pl-s\">\"主角剑3\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">50</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"宁氏一剑\"</span>,<span class=\"pl-c1\">0.18</span>,<span class=\"pl-c1\">0.36</span>,<span class=\"pl-c1\">0.54</span>,<span class=\"pl-c1\">0.72</span>,<span class=\"pl-c1\">0.9</span>,<span class=\"pl-c1\">1.08</span>,<span class=\"pl-c1\">1.26</span>,<span class=\"pl-c1\">1.44</span>,<span class=\"pl-c1\">1.62</span>,<span class=\"pl-c1\">3</span>,<span class=\"pl-c1\">45</span>,<span class=\"pl-c1\">9</span>,<span class=\"pl-c1\">29</span>,<span class=\"pl-c1\">58</span>,<span class=\"pl-c1\">97</span>,<span class=\"pl-c1\">146</span>,<span class=\"pl-c1\">205</span>,<span class=\"pl-c1\">273</span>,<span class=\"pl-c1\">352</span>,<span class=\"pl-c1\">440</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">440</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">4</span>,<span class=\"pl-c1\">27</span>,<span class=\"pl-s\">\"主角剑2\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">51</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"全真剑法\"</span>,<span class=\"pl-c1\">0.1</span>,<span class=\"pl-c1\">0.2</span>,<span class=\"pl-c1\">0.3</span>,<span class=\"pl-c1\">0.4</span>,<span class=\"pl-c1\">0.5</span>,<span class=\"pl-c1\">0.6</span>,<span class=\"pl-c1\">0.7</span>,<span class=\"pl-c1\">0.8</span>,<span class=\"pl-c1\">0.9</span>,<span class=\"pl-c1\">2.1</span>,<span class=\"pl-c1\">65</span>,<span class=\"pl-c1\">9</span>,<span class=\"pl-c1\">29</span>,<span class=\"pl-c1\">58</span>,<span class=\"pl-c1\">97</span>,<span class=\"pl-c1\">146</span>,<span class=\"pl-c1\">205</span>,<span class=\"pl-c1\">273</span>,<span class=\"pl-c1\">352</span>,<span class=\"pl-c1\">440</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">440</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">22</span>,<span class=\"pl-s\">\"主角剑2\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">52</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"绕指柔剑\"</span>,<span class=\"pl-c1\">0.16</span>,<span class=\"pl-c1\">0.32</span>,<span class=\"pl-c1\">0.48</span>,<span class=\"pl-c1\">0.64</span>,<span class=\"pl-c1\">0.8</span>,<span class=\"pl-c1\">0.96</span>,<span class=\"pl-c1\">1.12</span>,<span class=\"pl-c1\">1.28</span>,<span class=\"pl-c1\">1.44</span>,<span class=\"pl-c1\">2.8</span>,<span class=\"pl-c1\">70</span>,<span class=\"pl-c1\">11</span>,<span class=\"pl-c1\">34</span>,<span class=\"pl-c1\">69</span>,<span class=\"pl-c1\">115</span>,<span class=\"pl-c1\">173</span>,<span class=\"pl-c1\">242</span>,<span class=\"pl-c1\">323</span>,<span class=\"pl-c1\">416</span>,<span class=\"pl-c1\">520</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">520</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">26</span>,<span class=\"pl-s\">\"主角剑1\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">53</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"神门十三剑\"</span>,<span class=\"pl-c1\">0.21</span>,<span class=\"pl-c1\">0.42</span>,<span class=\"pl-c1\">0.63</span>,<span class=\"pl-c1\">0.84</span>,<span class=\"pl-c1\">1.05</span>,<span class=\"pl-c1\">1.36</span>,<span class=\"pl-c1\">1.57</span>,<span class=\"pl-c1\">1.78</span>,<span class=\"pl-c1\">1.99</span>,<span class=\"pl-c1\">3.4</span>,<span class=\"pl-c1\">65</span>,<span class=\"pl-c1\">14</span>,<span class=\"pl-c1\">42</span>,<span class=\"pl-c1\">84</span>,<span class=\"pl-c1\">140</span>,<span class=\"pl-c1\">210</span>,<span class=\"pl-c1\">294</span>,<span class=\"pl-c1\">392</span>,<span class=\"pl-c1\">504</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">32</span>,<span class=\"pl-s\">\"主角剑1\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">54</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"松风剑法\"</span>,<span class=\"pl-c1\">0.16</span>,<span class=\"pl-c1\">0.32</span>,<span class=\"pl-c1\">0.48</span>,<span class=\"pl-c1\">0.64</span>,<span class=\"pl-c1\">0.8</span>,<span class=\"pl-c1\">0.96</span>,<span class=\"pl-c1\">1.12</span>,<span class=\"pl-c1\">1.28</span>,<span class=\"pl-c1\">1.44</span>,<span class=\"pl-c1\">2.8</span>,<span class=\"pl-c1\">55</span>,<span class=\"pl-c1\">9</span>,<span class=\"pl-c1\">29</span>,<span class=\"pl-c1\">58</span>,<span class=\"pl-c1\">97</span>,<span class=\"pl-c1\">146</span>,<span class=\"pl-c1\">205</span>,<span class=\"pl-c1\">273</span>,<span class=\"pl-c1\">352</span>,<span class=\"pl-c1\">440</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">440</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">21</span>,<span class=\"pl-s\">\"主角剑2\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">55</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"太极剑\"</span>,<span class=\"pl-c1\">0.3</span>,<span class=\"pl-c1\">0.6</span>,<span class=\"pl-c1\">0.9</span>,<span class=\"pl-c1\">1.2</span>,<span class=\"pl-c1\">1.5</span>,<span class=\"pl-c1\">1.8</span>,<span class=\"pl-c1\">2.1</span>,<span class=\"pl-c1\">2.4</span>,<span class=\"pl-c1\">2.7</span>,<span class=\"pl-c1\">4.5</span>,<span class=\"pl-c1\">75</span>,<span class=\"pl-c1\">16</span>,<span class=\"pl-c1\">50</span>,<span class=\"pl-c1\">100</span>,<span class=\"pl-c1\">166</span>,<span class=\"pl-c1\">250</span>,<span class=\"pl-c1\">350</span>,<span class=\"pl-c1\">466</span>,<span class=\"pl-c1\">600</span>,<span class=\"pl-c1\">750</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">750</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">22</span>,<span class=\"pl-s\">\"主角剑2\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">56</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"太岳三青峰\"</span>,<span class=\"pl-c1\">0.22</span>,<span class=\"pl-c1\">0.44</span>,<span class=\"pl-c1\">0.66</span>,<span class=\"pl-c1\">0.88</span>,<span class=\"pl-c1\">1.1</span>,<span class=\"pl-c1\">1.32</span>,<span class=\"pl-c1\">1.54</span>,<span class=\"pl-c1\">1.76</span>,<span class=\"pl-c1\">1.98</span>,<span class=\"pl-c1\">3.5</span>,<span class=\"pl-c1\">50</span>,<span class=\"pl-c1\">9</span>,<span class=\"pl-c1\">29</span>,<span class=\"pl-c1\">58</span>,<span class=\"pl-c1\">97</span>,<span class=\"pl-c1\">146</span>,<span class=\"pl-c1\">205</span>,<span class=\"pl-c1\">273</span>,<span class=\"pl-c1\">352</span>,<span class=\"pl-c1\">440</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">440</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">34</span>,<span class=\"pl-s\">\"主角剑1\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">57</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"躺尸剑法\"</span>,<span class=\"pl-c1\">0.14</span>,<span class=\"pl-c1\">0.28</span>,<span class=\"pl-c1\">0.42</span>,<span class=\"pl-c1\">0.56</span>,<span class=\"pl-c1\">0.7</span>,<span class=\"pl-c1\">0.84</span>,<span class=\"pl-c1\">0.98</span>,<span class=\"pl-c1\">1.12</span>,<span class=\"pl-c1\">1.36</span>,<span class=\"pl-c1\">2.6</span>,<span class=\"pl-c1\">60</span>,<span class=\"pl-c1\">9</span>,<span class=\"pl-c1\">29</span>,<span class=\"pl-c1\">58</span>,<span class=\"pl-c1\">97</span>,<span class=\"pl-c1\">146</span>,<span class=\"pl-c1\">205</span>,<span class=\"pl-c1\">273</span>,<span class=\"pl-c1\">352</span>,<span class=\"pl-c1\">440</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">440</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">22</span>,<span class=\"pl-s\">\"主角剑3\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">58</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"万花剑法\"</span>,<span class=\"pl-c1\">0.21</span>,<span class=\"pl-c1\">0.42</span>,<span class=\"pl-c1\">0.63</span>,<span class=\"pl-c1\">0.84</span>,<span class=\"pl-c1\">1.05</span>,<span class=\"pl-c1\">1.26</span>,<span class=\"pl-c1\">1.47</span>,<span class=\"pl-c1\">1.68</span>,<span class=\"pl-c1\">1.89</span>,<span class=\"pl-c1\">3.3</span>,<span class=\"pl-c1\">58</span>,<span class=\"pl-c1\">14</span>,<span class=\"pl-c1\">42</span>,<span class=\"pl-c1\">84</span>,<span class=\"pl-c1\">140</span>,<span class=\"pl-c1\">210</span>,<span class=\"pl-c1\">294</span>,<span class=\"pl-c1\">392</span>,<span class=\"pl-c1\">504</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">33</span>,<span class=\"pl-s\">\"主角剑2\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">59</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"五大夫剑\"</span>,<span class=\"pl-c1\">0.22</span>,<span class=\"pl-c1\">0.44</span>,<span class=\"pl-c1\">0.66</span>,<span class=\"pl-c1\">0.88</span>,<span class=\"pl-c1\">1.1</span>,<span class=\"pl-c1\">1.32</span>,<span class=\"pl-c1\">1.54</span>,<span class=\"pl-c1\">1.76</span>,<span class=\"pl-c1\">1.98</span>,<span class=\"pl-c1\">3.5</span>,<span class=\"pl-c1\">70</span>,<span class=\"pl-c1\">14</span>,<span class=\"pl-c1\">42</span>,<span class=\"pl-c1\">84</span>,<span class=\"pl-c1\">140</span>,<span class=\"pl-c1\">210</span>,<span class=\"pl-c1\">294</span>,<span class=\"pl-c1\">392</span>,<span class=\"pl-c1\">504</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">33</span>,<span class=\"pl-s\">\"主角剑1\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">60</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"五岳剑法\"</span>,<span class=\"pl-c1\">0.26</span>,<span class=\"pl-c1\">0.52</span>,<span class=\"pl-c1\">0.78</span>,<span class=\"pl-c1\">1.04</span>,<span class=\"pl-c1\">1.3</span>,<span class=\"pl-c1\">1.56</span>,<span class=\"pl-c1\">1.82</span>,<span class=\"pl-c1\">2.08</span>,<span class=\"pl-c1\">2.34</span>,<span class=\"pl-c1\">3.9</span>,<span class=\"pl-c1\">60</span>,<span class=\"pl-c1\">16</span>,<span class=\"pl-c1\">50</span>,<span class=\"pl-c1\">100</span>,<span class=\"pl-c1\">166</span>,<span class=\"pl-c1\">250</span>,<span class=\"pl-c1\">350</span>,<span class=\"pl-c1\">466</span>,<span class=\"pl-c1\">600</span>,<span class=\"pl-c1\">750</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">750</span>,<span class=\"pl-c1\">3</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">36</span>,<span class=\"pl-s\">\"主角剑3\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">61</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"玄铁剑法\"</span>,<span class=\"pl-c1\">0.31</span>,<span class=\"pl-c1\">0.62</span>,<span class=\"pl-c1\">0.93</span>,<span class=\"pl-c1\">1.24</span>,<span class=\"pl-c1\">1.55</span>,<span class=\"pl-c1\">1.86</span>,<span class=\"pl-c1\">2.17</span>,<span class=\"pl-c1\">2.48</span>,<span class=\"pl-c1\">2.79</span>,<span class=\"pl-c1\">4.5</span>,<span class=\"pl-c1\">65</span>,<span class=\"pl-c1\">18</span>,<span class=\"pl-c1\">56</span>,<span class=\"pl-c1\">113</span>,<span class=\"pl-c1\">188</span>,<span class=\"pl-c1\">283</span>,<span class=\"pl-c1\">396</span>,<span class=\"pl-c1\">528</span>,<span class=\"pl-c1\">680</span>,<span class=\"pl-c1\">850</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">850</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">4</span>,<span class=\"pl-c1\">45</span>,<span class=\"pl-s\">\"主角剑1\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">62</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"玉女剑法\"</span>,<span class=\"pl-c1\">0.12</span>,<span class=\"pl-c1\">0.24</span>,<span class=\"pl-c1\">0.36</span>,<span class=\"pl-c1\">0.48</span>,<span class=\"pl-c1\">0.6</span>,<span class=\"pl-c1\">0.72</span>,<span class=\"pl-c1\">0.84</span>,<span class=\"pl-c1\">0.96</span>,<span class=\"pl-c1\">1.08</span>,<span class=\"pl-c1\">2.4</span>,<span class=\"pl-c1\">55</span>,<span class=\"pl-c1\">11</span>,<span class=\"pl-c1\">34</span>,<span class=\"pl-c1\">69</span>,<span class=\"pl-c1\">115</span>,<span class=\"pl-c1\">173</span>,<span class=\"pl-c1\">242</span>,<span class=\"pl-c1\">323</span>,<span class=\"pl-c1\">416</span>,<span class=\"pl-c1\">520</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">520</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">24</span>,<span class=\"pl-s\">\"主角剑2\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">63</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"玉女素心剑\"</span>,<span class=\"pl-c1\">0.29</span>,<span class=\"pl-c1\">0.58</span>,<span class=\"pl-c1\">0.87</span>,<span class=\"pl-c1\">1.16</span>,<span class=\"pl-c1\">1.45</span>,<span class=\"pl-c1\">1.74</span>,<span class=\"pl-c1\">2.13</span>,<span class=\"pl-c1\">2.42</span>,<span class=\"pl-c1\">2.71</span>,<span class=\"pl-c1\">4.2</span>,<span class=\"pl-c1\">65</span>,<span class=\"pl-c1\">14</span>,<span class=\"pl-c1\">42</span>,<span class=\"pl-c1\">84</span>,<span class=\"pl-c1\">140</span>,<span class=\"pl-c1\">210</span>,<span class=\"pl-c1\">294</span>,<span class=\"pl-c1\">392</span>,<span class=\"pl-c1\">504</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">38</span>,<span class=\"pl-s\">\"主角剑1\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">64</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"玉箫剑法\"</span>,<span class=\"pl-c1\">0.14</span>,<span class=\"pl-c1\">0.28</span>,<span class=\"pl-c1\">0.42</span>,<span class=\"pl-c1\">0.56</span>,<span class=\"pl-c1\">0.7</span>,<span class=\"pl-c1\">0.84</span>,<span class=\"pl-c1\">0.98</span>,<span class=\"pl-c1\">1.12</span>,<span class=\"pl-c1\">1.36</span>,<span class=\"pl-c1\">2.6</span>,<span class=\"pl-c1\">45</span>,<span class=\"pl-c1\">11</span>,<span class=\"pl-c1\">34</span>,<span class=\"pl-c1\">69</span>,<span class=\"pl-c1\">115</span>,<span class=\"pl-c1\">173</span>,<span class=\"pl-c1\">242</span>,<span class=\"pl-c1\">323</span>,<span class=\"pl-c1\">416</span>,<span class=\"pl-c1\">520</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">520</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">28</span>,<span class=\"pl-s\">\"主角剑2\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">65</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"越女剑法\"</span>,<span class=\"pl-c1\">0.26</span>,<span class=\"pl-c1\">0.42</span>,<span class=\"pl-c1\">0.63</span>,<span class=\"pl-c1\">0.84</span>,<span class=\"pl-c1\">1.05</span>,<span class=\"pl-c1\">1.26</span>,<span class=\"pl-c1\">1.47</span>,<span class=\"pl-c1\">1.68</span>,<span class=\"pl-c1\">1.89</span>,<span class=\"pl-c1\">3.3</span>,<span class=\"pl-c1\">40</span>,<span class=\"pl-c1\">11</span>,<span class=\"pl-c1\">34</span>,<span class=\"pl-c1\">69</span>,<span class=\"pl-c1\">115</span>,<span class=\"pl-c1\">173</span>,<span class=\"pl-c1\">242</span>,<span class=\"pl-c1\">323</span>,<span class=\"pl-c1\">416</span>,<span class=\"pl-c1\">520</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">520</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">33</span>,<span class=\"pl-s\">\"主角剑3\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">66</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"黯然销魂掌\"</span>,<span class=\"pl-c1\">1.54</span>,<span class=\"pl-c1\">3.08</span>,<span class=\"pl-c1\">4.62</span>,<span class=\"pl-c1\">6.16</span>,<span class=\"pl-c1\">7.8</span>,<span class=\"pl-c1\">9.34</span>,<span class=\"pl-c1\">10.88</span>,<span class=\"pl-c1\">12.42</span>,<span class=\"pl-c1\">13.96</span>,<span class=\"pl-c1\">18</span>,<span class=\"pl-c1\">55</span>,<span class=\"pl-c1\">16</span>,<span class=\"pl-c1\">50</span>,<span class=\"pl-c1\">100</span>,<span class=\"pl-c1\">166</span>,<span class=\"pl-c1\">250</span>,<span class=\"pl-c1\">350</span>,<span class=\"pl-c1\">466</span>,<span class=\"pl-c1\">600</span>,<span class=\"pl-c1\">750</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">750</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">43</span>,<span class=\"pl-s\">\"主角拳掌3\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">67</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"白虹掌\"</span>,<span class=\"pl-c1\">1.54</span>,<span class=\"pl-c1\">3.08</span>,<span class=\"pl-c1\">4.62</span>,<span class=\"pl-c1\">6.16</span>,<span class=\"pl-c1\">7.8</span>,<span class=\"pl-c1\">9.34</span>,<span class=\"pl-c1\">10.88</span>,<span class=\"pl-c1\">12.42</span>,<span class=\"pl-c1\">13.96</span>,<span class=\"pl-c1\">17</span>,<span class=\"pl-c1\">50</span>,<span class=\"pl-c1\">11</span>,<span class=\"pl-c1\">34</span>,<span class=\"pl-c1\">69</span>,<span class=\"pl-c1\">115</span>,<span class=\"pl-c1\">173</span>,<span class=\"pl-c1\">242</span>,<span class=\"pl-c1\">323</span>,<span class=\"pl-c1\">416</span>,<span class=\"pl-c1\">520</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">520</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">37</span>,<span class=\"pl-s\">\"主角拳掌2\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">68</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"白驼雪山掌\"</span>,<span class=\"pl-c1\">1.23</span>,<span class=\"pl-c1\">2.46</span>,<span class=\"pl-c1\">3.69</span>,<span class=\"pl-c1\">4.92</span>,<span class=\"pl-c1\">6.15</span>,<span class=\"pl-c1\">7.38</span>,<span class=\"pl-c1\">8.61</span>,<span class=\"pl-c1\">9.84</span>,<span class=\"pl-c1\">11.07</span>,<span class=\"pl-c1\">13.6</span>,<span class=\"pl-c1\">65</span>,<span class=\"pl-c1\">14</span>,<span class=\"pl-c1\">42</span>,<span class=\"pl-c1\">84</span>,<span class=\"pl-c1\">140</span>,<span class=\"pl-c1\">210</span>,<span class=\"pl-c1\">294</span>,<span class=\"pl-c1\">392</span>,<span class=\"pl-c1\">504</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">26</span>,<span class=\"pl-s\">\"主角拳掌4\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">69</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"般若掌\"</span>,<span class=\"pl-c1\">0.89</span>,<span class=\"pl-c1\">1.78</span>,<span class=\"pl-c1\">2.67</span>,<span class=\"pl-c1\">3.56</span>,<span class=\"pl-c1\">4.45</span>,<span class=\"pl-c1\">5.34</span>,<span class=\"pl-c1\">6.23</span>,<span class=\"pl-c1\">7.12</span>,<span class=\"pl-c1\">8.01</span>,<span class=\"pl-c1\">10.8</span>,<span class=\"pl-c1\">30</span>,<span class=\"pl-c1\">8</span>,<span class=\"pl-c1\">26</span>,<span class=\"pl-c1\">52</span>,<span class=\"pl-c1\">86</span>,<span class=\"pl-c1\">130</span>,<span class=\"pl-c1\">182</span>,<span class=\"pl-c1\">242</span>,<span class=\"pl-c1\">312</span>,<span class=\"pl-c1\">390</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">390</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">17</span>,<span class=\"pl-s\">\"主角拳掌2\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">70</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"碧波清掌\"</span>,<span class=\"pl-c1\">1.41</span>,<span class=\"pl-c1\">2.82</span>,<span class=\"pl-c1\">4.23</span>,<span class=\"pl-c1\">5.64</span>,<span class=\"pl-c1\">7.05</span>,<span class=\"pl-c1\">8.46</span>,<span class=\"pl-c1\">9.87</span>,<span class=\"pl-c1\">11.28</span>,<span class=\"pl-c1\">12.69</span>,<span class=\"pl-c1\">15.6</span>,<span class=\"pl-c1\">50</span>,<span class=\"pl-c1\">14</span>,<span class=\"pl-c1\">42</span>,<span class=\"pl-c1\">84</span>,<span class=\"pl-c1\">140</span>,<span class=\"pl-c1\">210</span>,<span class=\"pl-c1\">294</span>,<span class=\"pl-c1\">392</span>,<span class=\"pl-c1\">504</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">32</span>,<span class=\"pl-s\">\"主角拳掌3\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">71</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"冰蚕神掌\"</span>,<span class=\"pl-c1\">1.57</span>,<span class=\"pl-c1\">3.14</span>,<span class=\"pl-c1\">4.71</span>,<span class=\"pl-c1\">6.28</span>,<span class=\"pl-c1\">7.85</span>,<span class=\"pl-c1\">9.42</span>,<span class=\"pl-c1\">10.99</span>,<span class=\"pl-c1\">12.56</span>,<span class=\"pl-c1\">14.13</span>,<span class=\"pl-c1\">17.3</span>,<span class=\"pl-c1\">60</span>,<span class=\"pl-c1\">14</span>,<span class=\"pl-c1\">42</span>,<span class=\"pl-c1\">84</span>,<span class=\"pl-c1\">140</span>,<span class=\"pl-c1\">210</span>,<span class=\"pl-c1\">294</span>,<span class=\"pl-c1\">392</span>,<span class=\"pl-c1\">504</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">5</span>,<span class=\"pl-c1\">35</span>,<span class=\"pl-s\">\"主角拳掌4\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">72</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"长拳\"</span>,<span class=\"pl-c1\">0.8</span>,<span class=\"pl-c1\">1.6</span>,<span class=\"pl-c1\">2.4</span>,<span class=\"pl-c1\">3.2</span>,<span class=\"pl-c1\">4</span>,<span class=\"pl-c1\">4.8</span>,<span class=\"pl-c1\">5.6</span>,<span class=\"pl-c1\">6.4</span>,<span class=\"pl-c1\">7.2</span>,<span class=\"pl-c1\">8.8</span>,<span class=\"pl-c1\">35</span>,<span class=\"pl-c1\">6</span>,<span class=\"pl-c1\">20</span>,<span class=\"pl-c1\">41</span>,<span class=\"pl-c1\">68</span>,<span class=\"pl-c1\">103</span>,<span class=\"pl-c1\">144</span>,<span class=\"pl-c1\">192</span>,<span class=\"pl-c1\">248</span>,<span class=\"pl-c1\">310</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">310</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">17</span>,<span class=\"pl-s\">\"主角拳掌3\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">73</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"长拳\"</span>,<span class=\"pl-c1\">0.8</span>,<span class=\"pl-c1\">1.6</span>,<span class=\"pl-c1\">2.4</span>,<span class=\"pl-c1\">3.2</span>,<span class=\"pl-c1\">4</span>,<span class=\"pl-c1\">4.8</span>,<span class=\"pl-c1\">5.6</span>,<span class=\"pl-c1\">6.4</span>,<span class=\"pl-c1\">7.2</span>,<span class=\"pl-c1\">8.8</span>,<span class=\"pl-c1\">35</span>,<span class=\"pl-c1\">6</span>,<span class=\"pl-c1\">20</span>,<span class=\"pl-c1\">41</span>,<span class=\"pl-c1\">68</span>,<span class=\"pl-c1\">103</span>,<span class=\"pl-c1\">144</span>,<span class=\"pl-c1\">192</span>,<span class=\"pl-c1\">248</span>,<span class=\"pl-c1\">310</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">310</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">17</span>,<span class=\"pl-s\">\"主角拳掌3\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">74</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"长拳\"</span>,<span class=\"pl-c1\">0.8</span>,<span class=\"pl-c1\">1.6</span>,<span class=\"pl-c1\">2.4</span>,<span class=\"pl-c1\">3.2</span>,<span class=\"pl-c1\">4</span>,<span class=\"pl-c1\">4.8</span>,<span class=\"pl-c1\">5.6</span>,<span class=\"pl-c1\">6.4</span>,<span class=\"pl-c1\">7.2</span>,<span class=\"pl-c1\">8.8</span>,<span class=\"pl-c1\">35</span>,<span class=\"pl-c1\">6</span>,<span class=\"pl-c1\">20</span>,<span class=\"pl-c1\">41</span>,<span class=\"pl-c1\">68</span>,<span class=\"pl-c1\">103</span>,<span class=\"pl-c1\">144</span>,<span class=\"pl-c1\">192</span>,<span class=\"pl-c1\">248</span>,<span class=\"pl-c1\">310</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">310</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">17</span>,<span class=\"pl-s\">\"主角拳掌3\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">75</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"长拳\"</span>,<span class=\"pl-c1\">0.8</span>,<span class=\"pl-c1\">1.6</span>,<span class=\"pl-c1\">2.4</span>,<span class=\"pl-c1\">3.2</span>,<span class=\"pl-c1\">4</span>,<span class=\"pl-c1\">4.8</span>,<span class=\"pl-c1\">5.6</span>,<span class=\"pl-c1\">6.4</span>,<span class=\"pl-c1\">7.2</span>,<span class=\"pl-c1\">8.8</span>,<span class=\"pl-c1\">35</span>,<span class=\"pl-c1\">6</span>,<span class=\"pl-c1\">20</span>,<span class=\"pl-c1\">41</span>,<span class=\"pl-c1\">68</span>,<span class=\"pl-c1\">103</span>,<span class=\"pl-c1\">144</span>,<span class=\"pl-c1\">192</span>,<span class=\"pl-c1\">248</span>,<span class=\"pl-c1\">310</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">310</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">17</span>,<span class=\"pl-s\">\"主角拳掌3\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">76</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"赤炼神掌\"</span>,<span class=\"pl-c1\">1.25</span>,<span class=\"pl-c1\">2.5</span>,<span class=\"pl-c1\">3.75</span>,<span class=\"pl-c1\">5</span>,<span class=\"pl-c1\">6.25</span>,<span class=\"pl-c1\">7.5</span>,<span class=\"pl-c1\">8.75</span>,<span class=\"pl-c1\">10</span>,<span class=\"pl-c1\">11.25</span>,<span class=\"pl-c1\">13.8</span>,<span class=\"pl-c1\">55</span>,<span class=\"pl-c1\">14</span>,<span class=\"pl-c1\">42</span>,<span class=\"pl-c1\">84</span>,<span class=\"pl-c1\">140</span>,<span class=\"pl-c1\">210</span>,<span class=\"pl-c1\">294</span>,<span class=\"pl-c1\">392</span>,<span class=\"pl-c1\">504</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">26</span>,<span class=\"pl-s\">\"主角拳掌4\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">77</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"抽髓掌\"</span>,<span class=\"pl-c1\">0.95</span>,<span class=\"pl-c1\">1.9</span>,<span class=\"pl-c1\">2.85</span>,<span class=\"pl-c1\">3.8</span>,<span class=\"pl-c1\">4.75</span>,<span class=\"pl-c1\">5.7</span>,<span class=\"pl-c1\">6.65</span>,<span class=\"pl-c1\">7.7</span>,<span class=\"pl-c1\">8.65</span>,<span class=\"pl-c1\">10.5</span>,<span class=\"pl-c1\">55</span>,<span class=\"pl-c1\">11</span>,<span class=\"pl-c1\">34</span>,<span class=\"pl-c1\">69</span>,<span class=\"pl-c1\">115</span>,<span class=\"pl-c1\">173</span>,<span class=\"pl-c1\">242</span>,<span class=\"pl-c1\">323</span>,<span class=\"pl-c1\">416</span>,<span class=\"pl-c1\">520</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">520</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">20</span>,<span class=\"pl-s\">\"主角拳掌2\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">78</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"春蚕掌法\"</span>,<span class=\"pl-c1\">1.02</span>,<span class=\"pl-c1\">2.04</span>,<span class=\"pl-c1\">3.06</span>,<span class=\"pl-c1\">4.08</span>,<span class=\"pl-c1\">5.1</span>,<span class=\"pl-c1\">6.12</span>,<span class=\"pl-c1\">7.14</span>,<span class=\"pl-c1\">8.16</span>,<span class=\"pl-c1\">9.18</span>,<span class=\"pl-c1\">11.3</span>,<span class=\"pl-c1\">65</span>,<span class=\"pl-c1\">11</span>,<span class=\"pl-c1\">34</span>,<span class=\"pl-c1\">69</span>,<span class=\"pl-c1\">115</span>,<span class=\"pl-c1\">173</span>,<span class=\"pl-c1\">242</span>,<span class=\"pl-c1\">323</span>,<span class=\"pl-c1\">416</span>,<span class=\"pl-c1\">520</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">520</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">32</span>,<span class=\"pl-s\">\"主角拳掌2\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">79</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"摧心掌\"</span>,<span class=\"pl-c1\">1.21</span>,<span class=\"pl-c1\">2.42</span>,<span class=\"pl-c1\">3.63</span>,<span class=\"pl-c1\">4.84</span>,<span class=\"pl-c1\">6.05</span>,<span class=\"pl-c1\">7.26</span>,<span class=\"pl-c1\">8.47</span>,<span class=\"pl-c1\">9.68</span>,<span class=\"pl-c1\">10.89</span>,<span class=\"pl-c1\">13.4</span>,<span class=\"pl-c1\">40</span>,<span class=\"pl-c1\">14</span>,<span class=\"pl-c1\">42</span>,<span class=\"pl-c1\">84</span>,<span class=\"pl-c1\">140</span>,<span class=\"pl-c1\">210</span>,<span class=\"pl-c1\">294</span>,<span class=\"pl-c1\">392</span>,<span class=\"pl-c1\">504</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">28</span>,<span class=\"pl-s\">\"主角拳掌3\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">80</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"大力金刚掌\"</span>,<span class=\"pl-c1\">1.45</span>,<span class=\"pl-c1\">2.9</span>,<span class=\"pl-c1\">4.35</span>,<span class=\"pl-c1\">5.8</span>,<span class=\"pl-c1\">7.25</span>,<span class=\"pl-c1\">8.7</span>,<span class=\"pl-c1\">10.15</span>,<span class=\"pl-c1\">11.6</span>,<span class=\"pl-c1\">13.05</span>,<span class=\"pl-c1\">16</span>,<span class=\"pl-c1\">55</span>,<span class=\"pl-c1\">14</span>,<span class=\"pl-c1\">42</span>,<span class=\"pl-c1\">84</span>,<span class=\"pl-c1\">140</span>,<span class=\"pl-c1\">210</span>,<span class=\"pl-c1\">294</span>,<span class=\"pl-c1\">392</span>,<span class=\"pl-c1\">504</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">4</span>,<span class=\"pl-c1\">38</span>,<span class=\"pl-s\">\"主角拳掌1\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">81</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"寒冰绵掌\"</span>,<span class=\"pl-c1\">1.31</span>,<span class=\"pl-c1\">2.62</span>,<span class=\"pl-c1\">3.93</span>,<span class=\"pl-c1\">5.24</span>,<span class=\"pl-c1\">6.55</span>,<span class=\"pl-c1\">7.86</span>,<span class=\"pl-c1\">9.17</span>,<span class=\"pl-c1\">10.48</span>,<span class=\"pl-c1\">11.79</span>,<span class=\"pl-c1\">14.5</span>,<span class=\"pl-c1\">60</span>,<span class=\"pl-c1\">11</span>,<span class=\"pl-c1\">34</span>,<span class=\"pl-c1\">69</span>,<span class=\"pl-c1\">115</span>,<span class=\"pl-c1\">173</span>,<span class=\"pl-c1\">242</span>,<span class=\"pl-c1\">323</span>,<span class=\"pl-c1\">416</span>,<span class=\"pl-c1\">520</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">520</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">5</span>,<span class=\"pl-c1\">33</span>,<span class=\"pl-s\">\"主角拳掌3\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">82</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"化骨绵掌\"</span>,<span class=\"pl-c1\">1.31</span>,<span class=\"pl-c1\">2.62</span>,<span class=\"pl-c1\">3.93</span>,<span class=\"pl-c1\">5.24</span>,<span class=\"pl-c1\">6.55</span>,<span class=\"pl-c1\">7.86</span>,<span class=\"pl-c1\">9.17</span>,<span class=\"pl-c1\">10.48</span>,<span class=\"pl-c1\">11.79</span>,<span class=\"pl-c1\">14.5</span>,<span class=\"pl-c1\">65</span>,<span class=\"pl-c1\">11</span>,<span class=\"pl-c1\">34</span>,<span class=\"pl-c1\">69</span>,<span class=\"pl-c1\">115</span>,<span class=\"pl-c1\">173</span>,<span class=\"pl-c1\">242</span>,<span class=\"pl-c1\">323</span>,<span class=\"pl-c1\">416</span>,<span class=\"pl-c1\">520</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">520</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">31</span>,<span class=\"pl-s\">\"主角拳掌2\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">83</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"无\"</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">3</span>,<span class=\"pl-c1\">10</span>,<span class=\"pl-c1\">20</span>,<span class=\"pl-c1\">33</span>,<span class=\"pl-c1\">50</span>,<span class=\"pl-c1\">70</span>,<span class=\"pl-c1\">93</span>,<span class=\"pl-c1\">120</span>,<span class=\"pl-c1\">150</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">150</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">1</span>,<span class=\"pl-s\">\"主角拳掌3\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">84</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"基本拳掌\"</span>,<span class=\"pl-c1\">0.57</span>,<span class=\"pl-c1\">1.14</span>,<span class=\"pl-c1\">1.71</span>,<span class=\"pl-c1\">2.28</span>,<span class=\"pl-c1\">2.85</span>,<span class=\"pl-c1\">3.42</span>,<span class=\"pl-c1\">3.99</span>,<span class=\"pl-c1\">4.56</span>,<span class=\"pl-c1\">5.13</span>,<span class=\"pl-c1\">6.3</span>,<span class=\"pl-c1\">35</span>,<span class=\"pl-c1\">6</span>,<span class=\"pl-c1\">18</span>,<span class=\"pl-c1\">37</span>,<span class=\"pl-c1\">62</span>,<span class=\"pl-c1\">93</span>,<span class=\"pl-c1\">130</span>,<span class=\"pl-c1\">174</span>,<span class=\"pl-c1\">224</span>,<span class=\"pl-c1\">280</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">280</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">12</span>,<span class=\"pl-s\">\"主角拳掌3\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">85</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"降龙十八掌\"</span>,<span class=\"pl-c1\">1.74</span>,<span class=\"pl-c1\">3.48</span>,<span class=\"pl-c1\">5.22</span>,<span class=\"pl-c1\">6.96</span>,<span class=\"pl-c1\">8.7</span>,<span class=\"pl-c1\">10.44</span>,<span class=\"pl-c1\">12.18</span>,<span class=\"pl-c1\">13.92</span>,<span class=\"pl-c1\">15.66</span>,<span class=\"pl-c1\">19.5</span>,<span class=\"pl-c1\">65</span>,<span class=\"pl-c1\">18</span>,<span class=\"pl-c1\">56</span>,<span class=\"pl-c1\">113</span>,<span class=\"pl-c1\">188</span>,<span class=\"pl-c1\">283</span>,<span class=\"pl-c1\">396</span>,<span class=\"pl-c1\">528</span>,<span class=\"pl-c1\">680</span>,<span class=\"pl-c1\">850</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">850</span>,<span class=\"pl-c1\">5</span>,<span class=\"pl-c1\">4</span>,<span class=\"pl-c1\">49</span>,<span class=\"pl-s\">\"主角拳掌3\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">86</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"金蛇游身掌\"</span>,<span class=\"pl-c1\">1.33</span>,<span class=\"pl-c1\">2.66</span>,<span class=\"pl-c1\">3.99</span>,<span class=\"pl-c1\">5.32</span>,<span class=\"pl-c1\">6.65</span>,<span class=\"pl-c1\">7.98</span>,<span class=\"pl-c1\">9.31</span>,<span class=\"pl-c1\">10.64</span>,<span class=\"pl-c1\">11.97</span>,<span class=\"pl-c1\">14.7</span>,<span class=\"pl-c1\">60</span>,<span class=\"pl-c1\">14</span>,<span class=\"pl-c1\">42</span>,<span class=\"pl-c1\">84</span>,<span class=\"pl-c1\">140</span>,<span class=\"pl-c1\">210</span>,<span class=\"pl-c1\">294</span>,<span class=\"pl-c1\">392</span>,<span class=\"pl-c1\">504</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">31</span>,<span class=\"pl-s\">\"主角拳掌2\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">87</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"空明拳\"</span>,<span class=\"pl-c1\">1.52</span>,<span class=\"pl-c1\">3.04</span>,<span class=\"pl-c1\">4.56</span>,<span class=\"pl-c1\">6.08</span>,<span class=\"pl-c1\">7.6</span>,<span class=\"pl-c1\">9.12</span>,<span class=\"pl-c1\">10.63</span>,<span class=\"pl-c1\">12.15</span>,<span class=\"pl-c1\">13.67</span>,<span class=\"pl-c1\">16.8</span>,<span class=\"pl-c1\">50</span>,<span class=\"pl-c1\">14</span>,<span class=\"pl-c1\">42</span>,<span class=\"pl-c1\">84</span>,<span class=\"pl-c1\">140</span>,<span class=\"pl-c1\">210</span>,<span class=\"pl-c1\">294</span>,<span class=\"pl-c1\">392</span>,<span class=\"pl-c1\">504</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">35</span>,<span class=\"pl-s\">\"主角拳掌2\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">88</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"灵蛇拳\"</span>,<span class=\"pl-c1\">1.25</span>,<span class=\"pl-c1\">2.5</span>,<span class=\"pl-c1\">3.75</span>,<span class=\"pl-c1\">5</span>,<span class=\"pl-c1\">6.25</span>,<span class=\"pl-c1\">7.5</span>,<span class=\"pl-c1\">8.75</span>,<span class=\"pl-c1\">10</span>,<span class=\"pl-c1\">11.25</span>,<span class=\"pl-c1\">13.8</span>,<span class=\"pl-c1\">55</span>,<span class=\"pl-c1\">11</span>,<span class=\"pl-c1\">34</span>,<span class=\"pl-c1\">69</span>,<span class=\"pl-c1\">115</span>,<span class=\"pl-c1\">173</span>,<span class=\"pl-c1\">242</span>,<span class=\"pl-c1\">323</span>,<span class=\"pl-c1\">416</span>,<span class=\"pl-c1\">520</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">520</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">24</span>,<span class=\"pl-s\">\"主角拳掌3\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">89</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"罗汉拳\"</span>,<span class=\"pl-c1\">0.63</span>,<span class=\"pl-c1\">1.79</span>,<span class=\"pl-c1\">2.59</span>,<span class=\"pl-c1\">3.39</span>,<span class=\"pl-c1\">4.19</span>,<span class=\"pl-c1\">4.99</span>,<span class=\"pl-c1\">5.79</span>,<span class=\"pl-c1\">6.59</span>,<span class=\"pl-c1\">7.39</span>,<span class=\"pl-c1\">9.2</span>,<span class=\"pl-c1\">30</span>,<span class=\"pl-c1\">8</span>,<span class=\"pl-c1\">24</span>,<span class=\"pl-c1\">48</span>,<span class=\"pl-c1\">80</span>,<span class=\"pl-c1\">120</span>,<span class=\"pl-c1\">168</span>,<span class=\"pl-c1\">224</span>,<span class=\"pl-c1\">288</span>,<span class=\"pl-c1\">360</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">360</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">22</span>,<span class=\"pl-s\">\"主角拳掌2\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">90</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"落英神剑掌\"</span>,<span class=\"pl-c1\">1.27</span>,<span class=\"pl-c1\">2.54</span>,<span class=\"pl-c1\">3.81</span>,<span class=\"pl-c1\">5.08</span>,<span class=\"pl-c1\">6.35</span>,<span class=\"pl-c1\">7.62</span>,<span class=\"pl-c1\">8.89</span>,<span class=\"pl-c1\">10.16</span>,<span class=\"pl-c1\">11.43</span>,<span class=\"pl-c1\">14</span>,<span class=\"pl-c1\">40</span>,<span class=\"pl-c1\">11</span>,<span class=\"pl-c1\">34</span>,<span class=\"pl-c1\">69</span>,<span class=\"pl-c1\">115</span>,<span class=\"pl-c1\">173</span>,<span class=\"pl-c1\">242</span>,<span class=\"pl-c1\">323</span>,<span class=\"pl-c1\">416</span>,<span class=\"pl-c1\">520</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">520</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">28</span>,<span class=\"pl-s\">\"主角拳掌2\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">91</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"美女拳法\"</span>,<span class=\"pl-c1\">1.16</span>,<span class=\"pl-c1\">2.32</span>,<span class=\"pl-c1\">3.48</span>,<span class=\"pl-c1\">4.64</span>,<span class=\"pl-c1\">5.8</span>,<span class=\"pl-c1\">6.96</span>,<span class=\"pl-c1\">8.12</span>,<span class=\"pl-c1\">9.28</span>,<span class=\"pl-c1\">10.44</span>,<span class=\"pl-c1\">12.8</span>,<span class=\"pl-c1\">50</span>,<span class=\"pl-c1\">11</span>,<span class=\"pl-c1\">34</span>,<span class=\"pl-c1\">69</span>,<span class=\"pl-c1\">115</span>,<span class=\"pl-c1\">173</span>,<span class=\"pl-c1\">242</span>,<span class=\"pl-c1\">323</span>,<span class=\"pl-c1\">416</span>,<span class=\"pl-c1\">520</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">520</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">23</span>,<span class=\"pl-s\">\"主角拳掌2\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">92</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"美女三招\"</span>,<span class=\"pl-c1\">1.02</span>,<span class=\"pl-c1\">2.04</span>,<span class=\"pl-c1\">3.06</span>,<span class=\"pl-c1\">4.08</span>,<span class=\"pl-c1\">5.1</span>,<span class=\"pl-c1\">6.12</span>,<span class=\"pl-c1\">7.14</span>,<span class=\"pl-c1\">8.16</span>,<span class=\"pl-c1\">9.18</span>,<span class=\"pl-c1\">11.3</span>,<span class=\"pl-c1\">50</span>,<span class=\"pl-c1\">11</span>,<span class=\"pl-c1\">34</span>,<span class=\"pl-c1\">69</span>,<span class=\"pl-c1\">115</span>,<span class=\"pl-c1\">173</span>,<span class=\"pl-c1\">242</span>,<span class=\"pl-c1\">323</span>,<span class=\"pl-c1\">416</span>,<span class=\"pl-c1\">520</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">520</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">26</span>,<span class=\"pl-s\">\"主角拳掌2\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">93</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"绵掌\"</span>,<span class=\"pl-c1\">1.2</span>,<span class=\"pl-c1\">2.4</span>,<span class=\"pl-c1\">3.6</span>,<span class=\"pl-c1\">4.8</span>,<span class=\"pl-c1\">6</span>,<span class=\"pl-c1\">7.2</span>,<span class=\"pl-c1\">8.4</span>,<span class=\"pl-c1\">9.6</span>,<span class=\"pl-c1\">10.8</span>,<span class=\"pl-c1\">13.2</span>,<span class=\"pl-c1\">50</span>,<span class=\"pl-c1\">11</span>,<span class=\"pl-c1\">34</span>,<span class=\"pl-c1\">69</span>,<span class=\"pl-c1\">115</span>,<span class=\"pl-c1\">173</span>,<span class=\"pl-c1\">242</span>,<span class=\"pl-c1\">323</span>,<span class=\"pl-c1\">416</span>,<span class=\"pl-c1\">520</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">520</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">27</span>,<span class=\"pl-s\">\"主角拳掌2\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">94</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"南山掌法\"</span>,<span class=\"pl-c1\">0.81</span>,<span class=\"pl-c1\">1.62</span>,<span class=\"pl-c1\">2.43</span>,<span class=\"pl-c1\">3.24</span>,<span class=\"pl-c1\">4.05</span>,<span class=\"pl-c1\">4.86</span>,<span class=\"pl-c1\">5.67</span>,<span class=\"pl-c1\">6.48</span>,<span class=\"pl-c1\">7.29</span>,<span class=\"pl-c1\">10</span>,<span class=\"pl-c1\">40</span>,<span class=\"pl-c1\">8</span>,<span class=\"pl-c1\">26</span>,<span class=\"pl-c1\">52</span>,<span class=\"pl-c1\">86</span>,<span class=\"pl-c1\">130</span>,<span class=\"pl-c1\">182</span>,<span class=\"pl-c1\">242</span>,<span class=\"pl-c1\">312</span>,<span class=\"pl-c1\">390</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">390</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">17</span>,<span class=\"pl-s\">\"主角拳掌3\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">95</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"劈空掌\"</span>,<span class=\"pl-c1\">1</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">3</span>,<span class=\"pl-c1\">4</span>,<span class=\"pl-c1\">5</span>,<span class=\"pl-c1\">6</span>,<span class=\"pl-c1\">7</span>,<span class=\"pl-c1\">8</span>,<span class=\"pl-c1\">9</span>,<span class=\"pl-c1\">11</span>,<span class=\"pl-c1\">55</span>,<span class=\"pl-c1\">9</span>,<span class=\"pl-c1\">29</span>,<span class=\"pl-c1\">58</span>,<span class=\"pl-c1\">97</span>,<span class=\"pl-c1\">146</span>,<span class=\"pl-c1\">205</span>,<span class=\"pl-c1\">273</span>,<span class=\"pl-c1\">352</span>,<span class=\"pl-c1\">440</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">440</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">23</span>,<span class=\"pl-s\">\"主角拳掌4\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">96</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"七伤拳\"</span>,<span class=\"pl-c1\">1.57</span>,<span class=\"pl-c1\">3.14</span>,<span class=\"pl-c1\">4.71</span>,<span class=\"pl-c1\">6.28</span>,<span class=\"pl-c1\">7.85</span>,<span class=\"pl-c1\">9.42</span>,<span class=\"pl-c1\">10.99</span>,<span class=\"pl-c1\">12.56</span>,<span class=\"pl-c1\">14.13</span>,<span class=\"pl-c1\">17.3</span>,<span class=\"pl-c1\">65</span>,<span class=\"pl-c1\">16</span>,<span class=\"pl-c1\">50</span>,<span class=\"pl-c1\">100</span>,<span class=\"pl-c1\">166</span>,<span class=\"pl-c1\">250</span>,<span class=\"pl-c1\">350</span>,<span class=\"pl-c1\">466</span>,<span class=\"pl-c1\">600</span>,<span class=\"pl-c1\">750</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">750</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">38</span>,<span class=\"pl-s\">\"主角拳掌3\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">97</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"如来千叶手\"</span>,<span class=\"pl-c1\">1.36</span>,<span class=\"pl-c1\">2.72</span>,<span class=\"pl-c1\">4.08</span>,<span class=\"pl-c1\">5.44</span>,<span class=\"pl-c1\">6.8</span>,<span class=\"pl-c1\">8.16</span>,<span class=\"pl-c1\">9.52</span>,<span class=\"pl-c1\">10.88</span>,<span class=\"pl-c1\">12.24</span>,<span class=\"pl-c1\">15</span>,<span class=\"pl-c1\">60</span>,<span class=\"pl-c1\">14</span>,<span class=\"pl-c1\">42</span>,<span class=\"pl-c1\">84</span>,<span class=\"pl-c1\">140</span>,<span class=\"pl-c1\">210</span>,<span class=\"pl-c1\">294</span>,<span class=\"pl-c1\">392</span>,<span class=\"pl-c1\">504</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">5</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">39</span>,<span class=\"pl-s\">\"主角拳掌1\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">98</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"三花聚顶掌\"</span>,<span class=\"pl-c1\">1.5</span>,<span class=\"pl-c1\">3</span>,<span class=\"pl-c1\">4.5</span>,<span class=\"pl-c1\">6</span>,<span class=\"pl-c1\">7.5</span>,<span class=\"pl-c1\">9</span>,<span class=\"pl-c1\">10.5</span>,<span class=\"pl-c1\">12</span>,<span class=\"pl-c1\">13.5</span>,<span class=\"pl-c1\">16.5</span>,<span class=\"pl-c1\">55</span>,<span class=\"pl-c1\">11</span>,<span class=\"pl-c1\">34</span>,<span class=\"pl-c1\">69</span>,<span class=\"pl-c1\">115</span>,<span class=\"pl-c1\">173</span>,<span class=\"pl-c1\">242</span>,<span class=\"pl-c1\">323</span>,<span class=\"pl-c1\">416</span>,<span class=\"pl-c1\">520</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">520</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">33</span>,<span class=\"pl-s\">\"主角拳掌3\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">99</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"太极拳\"</span>,<span class=\"pl-c1\">1.8</span>,<span class=\"pl-c1\">3.6</span>,<span class=\"pl-c1\">5.4</span>,<span class=\"pl-c1\">7.2</span>,<span class=\"pl-c1\">9</span>,<span class=\"pl-c1\">10.8</span>,<span class=\"pl-c1\">12.6</span>,<span class=\"pl-c1\">14.4</span>,<span class=\"pl-c1\">16.2</span>,<span class=\"pl-c1\">21.9</span>,<span class=\"pl-c1\">75</span>,<span class=\"pl-c1\">16</span>,<span class=\"pl-c1\">50</span>,<span class=\"pl-c1\">100</span>,<span class=\"pl-c1\">166</span>,<span class=\"pl-c1\">250</span>,<span class=\"pl-c1\">350</span>,<span class=\"pl-c1\">466</span>,<span class=\"pl-c1\">600</span>,<span class=\"pl-c1\">750</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">750</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">22</span>,<span class=\"pl-s\">\"主角拳掌2\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">100</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"天长掌法\"</span>,<span class=\"pl-c1\">0.87</span>,<span class=\"pl-c1\">1.74</span>,<span class=\"pl-c1\">2.61</span>,<span class=\"pl-c1\">3.48</span>,<span class=\"pl-c1\">4.35</span>,<span class=\"pl-c1\">5.22</span>,<span class=\"pl-c1\">6.09</span>,<span class=\"pl-c1\">6.96</span>,<span class=\"pl-c1\">7.83</span>,<span class=\"pl-c1\">9.6</span>,<span class=\"pl-c1\">45</span>,<span class=\"pl-c1\">11</span>,<span class=\"pl-c1\">34</span>,<span class=\"pl-c1\">69</span>,<span class=\"pl-c1\">115</span>,<span class=\"pl-c1\">173</span>,<span class=\"pl-c1\">242</span>,<span class=\"pl-c1\">323</span>,<span class=\"pl-c1\">416</span>,<span class=\"pl-c1\">520</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">520</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">26</span>,<span class=\"pl-s\">\"主角拳掌4\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">101</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"天罗地网掌\"</span>,<span class=\"pl-c1\">0.89</span>,<span class=\"pl-c1\">1.78</span>,<span class=\"pl-c1\">2.67</span>,<span class=\"pl-c1\">3.56</span>,<span class=\"pl-c1\">4.45</span>,<span class=\"pl-c1\">5.34</span>,<span class=\"pl-c1\">6.23</span>,<span class=\"pl-c1\">7.12</span>,<span class=\"pl-c1\">8.01</span>,<span class=\"pl-c1\">9.8</span>,<span class=\"pl-c1\">45</span>,<span class=\"pl-c1\">9</span>,<span class=\"pl-c1\">29</span>,<span class=\"pl-c1\">58</span>,<span class=\"pl-c1\">97</span>,<span class=\"pl-c1\">146</span>,<span class=\"pl-c1\">205</span>,<span class=\"pl-c1\">273</span>,<span class=\"pl-c1\">352</span>,<span class=\"pl-c1\">440</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">440</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">22</span>,<span class=\"pl-s\">\"主角拳掌2\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">102</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"天山六阳掌\"</span>,<span class=\"pl-c1\">1.69</span>,<span class=\"pl-c1\">3.38</span>,<span class=\"pl-c1\">5.07</span>,<span class=\"pl-c1\">6.76</span>,<span class=\"pl-c1\">8.45</span>,<span class=\"pl-c1\">10.14</span>,<span class=\"pl-c1\">11.83</span>,<span class=\"pl-c1\">13.52</span>,<span class=\"pl-c1\">16.21</span>,<span class=\"pl-c1\">18.6</span>,<span class=\"pl-c1\">50</span>,<span class=\"pl-c1\">14</span>,<span class=\"pl-c1\">42</span>,<span class=\"pl-c1\">84</span>,<span class=\"pl-c1\">140</span>,<span class=\"pl-c1\">210</span>,<span class=\"pl-c1\">294</span>,<span class=\"pl-c1\">392</span>,<span class=\"pl-c1\">504</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">36</span>,<span class=\"pl-s\">\"主角拳掌4\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">103</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"天山折梅手\"</span>,<span class=\"pl-c1\">1.31</span>,<span class=\"pl-c1\">2.62</span>,<span class=\"pl-c1\">3.93</span>,<span class=\"pl-c1\">5.24</span>,<span class=\"pl-c1\">6.55</span>,<span class=\"pl-c1\">7.86</span>,<span class=\"pl-c1\">9.17</span>,<span class=\"pl-c1\">10.48</span>,<span class=\"pl-c1\">11.79</span>,<span class=\"pl-c1\">14.5</span>,<span class=\"pl-c1\">50</span>,<span class=\"pl-c1\">11</span>,<span class=\"pl-c1\">34</span>,<span class=\"pl-c1\">69</span>,<span class=\"pl-c1\">115</span>,<span class=\"pl-c1\">173</span>,<span class=\"pl-c1\">242</span>,<span class=\"pl-c1\">323</span>,<span class=\"pl-c1\">416</span>,<span class=\"pl-c1\">520</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">520</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">27</span>,<span class=\"pl-s\">\"主角拳掌4\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">104</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"铁掌\"</span>,<span class=\"pl-c1\">1.2</span>,<span class=\"pl-c1\">2.4</span>,<span class=\"pl-c1\">3.6</span>,<span class=\"pl-c1\">4.8</span>,<span class=\"pl-c1\">6</span>,<span class=\"pl-c1\">7.2</span>,<span class=\"pl-c1\">8.4</span>,<span class=\"pl-c1\">9.6</span>,<span class=\"pl-c1\">10.8</span>,<span class=\"pl-c1\">13.2</span>,<span class=\"pl-c1\">40</span>,<span class=\"pl-c1\">9</span>,<span class=\"pl-c1\">29</span>,<span class=\"pl-c1\">58</span>,<span class=\"pl-c1\">97</span>,<span class=\"pl-c1\">146</span>,<span class=\"pl-c1\">205</span>,<span class=\"pl-c1\">273</span>,<span class=\"pl-c1\">352</span>,<span class=\"pl-c1\">440</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">440</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">29</span>,<span class=\"pl-s\">\"主角拳掌3\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">105</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"铜锤手\"</span>,<span class=\"pl-c1\">1.01</span>,<span class=\"pl-c1\">2.02</span>,<span class=\"pl-c1\">3.03</span>,<span class=\"pl-c1\">4.04</span>,<span class=\"pl-c1\">5.05</span>,<span class=\"pl-c1\">6.06</span>,<span class=\"pl-c1\">7.07</span>,<span class=\"pl-c1\">8.08</span>,<span class=\"pl-c1\">9.09</span>,<span class=\"pl-c1\">11.2</span>,<span class=\"pl-c1\">45</span>,<span class=\"pl-c1\">8</span>,<span class=\"pl-c1\">26</span>,<span class=\"pl-c1\">52</span>,<span class=\"pl-c1\">86</span>,<span class=\"pl-c1\">130</span>,<span class=\"pl-c1\">182</span>,<span class=\"pl-c1\">242</span>,<span class=\"pl-c1\">312</span>,<span class=\"pl-c1\">390</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">390</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">17</span>,<span class=\"pl-s\">\"主角拳掌4\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">106</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"五罗轻烟掌\"</span>,<span class=\"pl-c1\">0.83</span>,<span class=\"pl-c1\">1.66</span>,<span class=\"pl-c1\">2.49</span>,<span class=\"pl-c1\">3.32</span>,<span class=\"pl-c1\">4.15</span>,<span class=\"pl-c1\">4.98</span>,<span class=\"pl-c1\">5.81</span>,<span class=\"pl-c1\">6.64</span>,<span class=\"pl-c1\">7.47</span>,<span class=\"pl-c1\">9.2</span>,<span class=\"pl-c1\">45</span>,<span class=\"pl-c1\">11</span>,<span class=\"pl-c1\">34</span>,<span class=\"pl-c1\">69</span>,<span class=\"pl-c1\">115</span>,<span class=\"pl-c1\">173</span>,<span class=\"pl-c1\">242</span>,<span class=\"pl-c1\">323</span>,<span class=\"pl-c1\">416</span>,<span class=\"pl-c1\">520</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">520</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">23</span>,<span class=\"pl-s\">\"主角拳掌2\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">107</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"五行六合掌\"</span>,<span class=\"pl-c1\">1.01</span>,<span class=\"pl-c1\">2.02</span>,<span class=\"pl-c1\">3.03</span>,<span class=\"pl-c1\">4.04</span>,<span class=\"pl-c1\">5.05</span>,<span class=\"pl-c1\">6.06</span>,<span class=\"pl-c1\">7.07</span>,<span class=\"pl-c1\">8.08</span>,<span class=\"pl-c1\">9.09</span>,<span class=\"pl-c1\">11.2</span>,<span class=\"pl-c1\">55</span>,<span class=\"pl-c1\">14</span>,<span class=\"pl-c1\">42</span>,<span class=\"pl-c1\">84</span>,<span class=\"pl-c1\">140</span>,<span class=\"pl-c1\">210</span>,<span class=\"pl-c1\">294</span>,<span class=\"pl-c1\">392</span>,<span class=\"pl-c1\">504</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">33</span>,<span class=\"pl-s\">\"主角拳掌3\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">108</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"逍遥游\"</span>,<span class=\"pl-c1\">1.2</span>,<span class=\"pl-c1\">2.4</span>,<span class=\"pl-c1\">3.6</span>,<span class=\"pl-c1\">4.8</span>,<span class=\"pl-c1\">6</span>,<span class=\"pl-c1\">7.2</span>,<span class=\"pl-c1\">8.4</span>,<span class=\"pl-c1\">9.6</span>,<span class=\"pl-c1\">10.8</span>,<span class=\"pl-c1\">13.3</span>,<span class=\"pl-c1\">35</span>,<span class=\"pl-c1\">6</span>,<span class=\"pl-c1\">20</span>,<span class=\"pl-c1\">40</span>,<span class=\"pl-c1\">66</span>,<span class=\"pl-c1\">100</span>,<span class=\"pl-c1\">140</span>,<span class=\"pl-c1\">186</span>,<span class=\"pl-c1\">240</span>,<span class=\"pl-c1\">300</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">300</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">21</span>,<span class=\"pl-s\">\"主角拳掌3\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">109</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"须弥山掌\"</span>,<span class=\"pl-c1\">1.32</span>,<span class=\"pl-c1\">2.64</span>,<span class=\"pl-c1\">3.96</span>,<span class=\"pl-c1\">5.28</span>,<span class=\"pl-c1\">6.6</span>,<span class=\"pl-c1\">7.92</span>,<span class=\"pl-c1\">9.24</span>,<span class=\"pl-c1\">10.56</span>,<span class=\"pl-c1\">11.88</span>,<span class=\"pl-c1\">14.6</span>,<span class=\"pl-c1\">45</span>,<span class=\"pl-c1\">11</span>,<span class=\"pl-c1\">34</span>,<span class=\"pl-c1\">69</span>,<span class=\"pl-c1\">115</span>,<span class=\"pl-c1\">173</span>,<span class=\"pl-c1\">242</span>,<span class=\"pl-c1\">323</span>,<span class=\"pl-c1\">416</span>,<span class=\"pl-c1\">520</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">520</span>,<span class=\"pl-c1\">3</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">25</span>,<span class=\"pl-s\">\"主角拳掌1\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">110</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"野狐拳法\"</span>,<span class=\"pl-c1\">0.74</span>,<span class=\"pl-c1\">1.48</span>,<span class=\"pl-c1\">2.22</span>,<span class=\"pl-c1\">2.96</span>,<span class=\"pl-c1\">3.7</span>,<span class=\"pl-c1\">4.44</span>,<span class=\"pl-c1\">5.18</span>,<span class=\"pl-c1\">5.92</span>,<span class=\"pl-c1\">6.66</span>,<span class=\"pl-c1\">8.2</span>,<span class=\"pl-c1\">40</span>,<span class=\"pl-c1\">9</span>,<span class=\"pl-c1\">29</span>,<span class=\"pl-c1\">58</span>,<span class=\"pl-c1\">97</span>,<span class=\"pl-c1\">146</span>,<span class=\"pl-c1\">205</span>,<span class=\"pl-c1\">273</span>,<span class=\"pl-c1\">352</span>,<span class=\"pl-c1\">440</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">440</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">23</span>,<span class=\"pl-s\">\"主角拳掌2\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">111</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"英雄三招\"</span>,<span class=\"pl-c1\">1.01</span>,<span class=\"pl-c1\">2.02</span>,<span class=\"pl-c1\">3.03</span>,<span class=\"pl-c1\">4.04</span>,<span class=\"pl-c1\">5.05</span>,<span class=\"pl-c1\">6.06</span>,<span class=\"pl-c1\">7.07</span>,<span class=\"pl-c1\">8.08</span>,<span class=\"pl-c1\">9.09</span>,<span class=\"pl-c1\">11.3</span>,<span class=\"pl-c1\">50</span>,<span class=\"pl-c1\">11</span>,<span class=\"pl-c1\">34</span>,<span class=\"pl-c1\">69</span>,<span class=\"pl-c1\">115</span>,<span class=\"pl-c1\">173</span>,<span class=\"pl-c1\">242</span>,<span class=\"pl-c1\">323</span>,<span class=\"pl-c1\">416</span>,<span class=\"pl-c1\">520</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">520</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">28</span>,<span class=\"pl-s\">\"主角拳掌4\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">112</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"震山铁掌\"</span>,<span class=\"pl-c1\">0.89</span>,<span class=\"pl-c1\">1.78</span>,<span class=\"pl-c1\">2.67</span>,<span class=\"pl-c1\">3.56</span>,<span class=\"pl-c1\">4.45</span>,<span class=\"pl-c1\">5.34</span>,<span class=\"pl-c1\">6.23</span>,<span class=\"pl-c1\">7.12</span>,<span class=\"pl-c1\">8.01</span>,<span class=\"pl-c1\">9.8</span>,<span class=\"pl-c1\">30</span>,<span class=\"pl-c1\">9</span>,<span class=\"pl-c1\">29</span>,<span class=\"pl-c1\">58</span>,<span class=\"pl-c1\">97</span>,<span class=\"pl-c1\">146</span>,<span class=\"pl-c1\">205</span>,<span class=\"pl-c1\">273</span>,<span class=\"pl-c1\">352</span>,<span class=\"pl-c1\">440</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">440</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">24</span>,<span class=\"pl-s\">\"主角拳掌3\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">113</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"重阳神掌\"</span>,<span class=\"pl-c1\">1.68</span>,<span class=\"pl-c1\">3.36</span>,<span class=\"pl-c1\">5.04</span>,<span class=\"pl-c1\">6.72</span>,<span class=\"pl-c1\">8.4</span>,<span class=\"pl-c1\">10.08</span>,<span class=\"pl-c1\">11.76</span>,<span class=\"pl-c1\">13.44</span>,<span class=\"pl-c1\">15.12</span>,<span class=\"pl-c1\">18.5</span>,<span class=\"pl-c1\">55</span>,<span class=\"pl-c1\">16</span>,<span class=\"pl-c1\">50</span>,<span class=\"pl-c1\">100</span>,<span class=\"pl-c1\">166</span>,<span class=\"pl-c1\">250</span>,<span class=\"pl-c1\">350</span>,<span class=\"pl-c1\">466</span>,<span class=\"pl-c1\">600</span>,<span class=\"pl-c1\">750</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">750</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">37</span>,<span class=\"pl-s\">\"主角拳掌2\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">114</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"参合指\"</span>,<span class=\"pl-c1\">1.32</span>,<span class=\"pl-c1\">2.64</span>,<span class=\"pl-c1\">3.96</span>,<span class=\"pl-c1\">5.28</span>,<span class=\"pl-c1\">6.6</span>,<span class=\"pl-c1\">7.92</span>,<span class=\"pl-c1\">9.24</span>,<span class=\"pl-c1\">10.56</span>,<span class=\"pl-c1\">11.88</span>,<span class=\"pl-c1\">14.6</span>,<span class=\"pl-c1\">65</span>,<span class=\"pl-c1\">14</span>,<span class=\"pl-c1\">42</span>,<span class=\"pl-c1\">84</span>,<span class=\"pl-c1\">140</span>,<span class=\"pl-c1\">210</span>,<span class=\"pl-c1\">294</span>,<span class=\"pl-c1\">392</span>,<span class=\"pl-c1\">504</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">32</span>,<span class=\"pl-s\">\"主角指1\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">115</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"大力金刚指\"</span>,<span class=\"pl-c1\">1.43</span>,<span class=\"pl-c1\">2.86</span>,<span class=\"pl-c1\">4.29</span>,<span class=\"pl-c1\">5.72</span>,<span class=\"pl-c1\">7.15</span>,<span class=\"pl-c1\">8.58</span>,<span class=\"pl-c1\">10.01</span>,<span class=\"pl-c1\">11.44</span>,<span class=\"pl-c1\">12.87</span>,<span class=\"pl-c1\">15.8</span>,<span class=\"pl-c1\">55</span>,<span class=\"pl-c1\">14</span>,<span class=\"pl-c1\">42</span>,<span class=\"pl-c1\">84</span>,<span class=\"pl-c1\">140</span>,<span class=\"pl-c1\">210</span>,<span class=\"pl-c1\">294</span>,<span class=\"pl-c1\">392</span>,<span class=\"pl-c1\">504</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">35</span>,<span class=\"pl-s\">\"主角指1\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">116</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"分筋错骨手\"</span>,<span class=\"pl-c1\">0.89</span>,<span class=\"pl-c1\">1.78</span>,<span class=\"pl-c1\">2.67</span>,<span class=\"pl-c1\">3.56</span>,<span class=\"pl-c1\">4.45</span>,<span class=\"pl-c1\">5.34</span>,<span class=\"pl-c1\">6.23</span>,<span class=\"pl-c1\">7.12</span>,<span class=\"pl-c1\">8.01</span>,<span class=\"pl-c1\">9.8</span>,<span class=\"pl-c1\">45</span>,<span class=\"pl-c1\">11</span>,<span class=\"pl-c1\">34</span>,<span class=\"pl-c1\">69</span>,<span class=\"pl-c1\">115</span>,<span class=\"pl-c1\">173</span>,<span class=\"pl-c1\">242</span>,<span class=\"pl-c1\">323</span>,<span class=\"pl-c1\">416</span>,<span class=\"pl-c1\">520</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">520</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">22</span>,<span class=\"pl-s\">\"主角指1\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">117</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"虎爪绝户手\"</span>,<span class=\"pl-c1\">1.2</span>,<span class=\"pl-c1\">2.4</span>,<span class=\"pl-c1\">3.6</span>,<span class=\"pl-c1\">4.8</span>,<span class=\"pl-c1\">6</span>,<span class=\"pl-c1\">7.2</span>,<span class=\"pl-c1\">8.4</span>,<span class=\"pl-c1\">9.6</span>,<span class=\"pl-c1\">10.8</span>,<span class=\"pl-c1\">13.2</span>,<span class=\"pl-c1\">45</span>,<span class=\"pl-c1\">11</span>,<span class=\"pl-c1\">34</span>,<span class=\"pl-c1\">69</span>,<span class=\"pl-c1\">115</span>,<span class=\"pl-c1\">173</span>,<span class=\"pl-c1\">242</span>,<span class=\"pl-c1\">323</span>,<span class=\"pl-c1\">416</span>,<span class=\"pl-c1\">520</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">520</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">27</span>,<span class=\"pl-s\">\"主角指1\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">118</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"基本指法\"</span>,<span class=\"pl-c1\">0.57</span>,<span class=\"pl-c1\">1.14</span>,<span class=\"pl-c1\">1.71</span>,<span class=\"pl-c1\">2.28</span>,<span class=\"pl-c1\">2.85</span>,<span class=\"pl-c1\">3.42</span>,<span class=\"pl-c1\">3.99</span>,<span class=\"pl-c1\">4.56</span>,<span class=\"pl-c1\">5.13</span>,<span class=\"pl-c1\">6.3</span>,<span class=\"pl-c1\">35</span>,<span class=\"pl-c1\">6</span>,<span class=\"pl-c1\">18</span>,<span class=\"pl-c1\">37</span>,<span class=\"pl-c1\">62</span>,<span class=\"pl-c1\">93</span>,<span class=\"pl-c1\">130</span>,<span class=\"pl-c1\">174</span>,<span class=\"pl-c1\">224</span>,<span class=\"pl-c1\">280</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">280</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">12</span>,<span class=\"pl-s\">\"主角指1\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">119</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"九阴白骨爪\"</span>,<span class=\"pl-c1\">1.39</span>,<span class=\"pl-c1\">2.78</span>,<span class=\"pl-c1\">4.17</span>,<span class=\"pl-c1\">5.56</span>,<span class=\"pl-c1\">6.95</span>,<span class=\"pl-c1\">8.34</span>,<span class=\"pl-c1\">9.73</span>,<span class=\"pl-c1\">11.12</span>,<span class=\"pl-c1\">12.51</span>,<span class=\"pl-c1\">15.3</span>,<span class=\"pl-c1\">50</span>,<span class=\"pl-c1\">16</span>,<span class=\"pl-c1\">50</span>,<span class=\"pl-c1\">100</span>,<span class=\"pl-c1\">166</span>,<span class=\"pl-c1\">250</span>,<span class=\"pl-c1\">350</span>,<span class=\"pl-c1\">466</span>,<span class=\"pl-c1\">600</span>,<span class=\"pl-c1\">750</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">750</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">26</span>,<span class=\"pl-s\">\"主角指1\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">120</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"兰花拂穴手\"</span>,<span class=\"pl-c1\">1.25</span>,<span class=\"pl-c1\">2.5</span>,<span class=\"pl-c1\">3.75</span>,<span class=\"pl-c1\">5</span>,<span class=\"pl-c1\">6.25</span>,<span class=\"pl-c1\">7.5</span>,<span class=\"pl-c1\">8.75</span>,<span class=\"pl-c1\">10</span>,<span class=\"pl-c1\">11.25</span>,<span class=\"pl-c1\">13.8</span>,<span class=\"pl-c1\">40</span>,<span class=\"pl-c1\">14</span>,<span class=\"pl-c1\">42</span>,<span class=\"pl-c1\">84</span>,<span class=\"pl-c1\">140</span>,<span class=\"pl-c1\">210</span>,<span class=\"pl-c1\">294</span>,<span class=\"pl-c1\">392</span>,<span class=\"pl-c1\">504</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">22</span>,<span class=\"pl-s\">\"主角指1\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">121</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"六脉神剑\"</span>,<span class=\"pl-c1\">1.81</span>,<span class=\"pl-c1\">3.62</span>,<span class=\"pl-c1\">5.43</span>,<span class=\"pl-c1\">7.24</span>,<span class=\"pl-c1\">9.05</span>,<span class=\"pl-c1\">10.86</span>,<span class=\"pl-c1\">12.66</span>,<span class=\"pl-c1\">14.47</span>,<span class=\"pl-c1\">16.28</span>,<span class=\"pl-c1\">20</span>,<span class=\"pl-c1\">70</span>,<span class=\"pl-c1\">18</span>,<span class=\"pl-c1\">56</span>,<span class=\"pl-c1\">113</span>,<span class=\"pl-c1\">188</span>,<span class=\"pl-c1\">283</span>,<span class=\"pl-c1\">396</span>,<span class=\"pl-c1\">528</span>,<span class=\"pl-c1\">680</span>,<span class=\"pl-c1\">850</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">150</span>,<span class=\"pl-c1\">5</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">47</span>,<span class=\"pl-s\">\"主角指1\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">122</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"龙爪手\"</span>,<span class=\"pl-c1\">1.34</span>,<span class=\"pl-c1\">2.68</span>,<span class=\"pl-c1\">4.02</span>,<span class=\"pl-c1\">5.35</span>,<span class=\"pl-c1\">6.89</span>,<span class=\"pl-c1\">8.23</span>,<span class=\"pl-c1\">9.57</span>,<span class=\"pl-c1\">10.91</span>,<span class=\"pl-c1\">12.25</span>,<span class=\"pl-c1\">14.8</span>,<span class=\"pl-c1\">40</span>,<span class=\"pl-c1\">14</span>,<span class=\"pl-c1\">42</span>,<span class=\"pl-c1\">84</span>,<span class=\"pl-c1\">140</span>,<span class=\"pl-c1\">210</span>,<span class=\"pl-c1\">294</span>,<span class=\"pl-c1\">392</span>,<span class=\"pl-c1\">504</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">32</span>,<span class=\"pl-s\">\"主角指1\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">123</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"拈花指\"</span>,<span class=\"pl-c1\">1.11</span>,<span class=\"pl-c1\">2.22</span>,<span class=\"pl-c1\">3.33</span>,<span class=\"pl-c1\">4.44</span>,<span class=\"pl-c1\">5.55</span>,<span class=\"pl-c1\">6.66</span>,<span class=\"pl-c1\">7.77</span>,<span class=\"pl-c1\">8.88</span>,<span class=\"pl-c1\">9.99</span>,<span class=\"pl-c1\">12.3</span>,<span class=\"pl-c1\">65</span>,<span class=\"pl-c1\">14</span>,<span class=\"pl-c1\">42</span>,<span class=\"pl-c1\">84</span>,<span class=\"pl-c1\">140</span>,<span class=\"pl-c1\">210</span>,<span class=\"pl-c1\">294</span>,<span class=\"pl-c1\">392</span>,<span class=\"pl-c1\">504</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">36</span>,<span class=\"pl-s\">\"主角指1\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">124</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"凝血神抓\"</span>,<span class=\"pl-c1\">0.9</span>,<span class=\"pl-c1\">1.8</span>,<span class=\"pl-c1\">2.7</span>,<span class=\"pl-c1\">3.6</span>,<span class=\"pl-c1\">4.5</span>,<span class=\"pl-c1\">5.4</span>,<span class=\"pl-c1\">6.3</span>,<span class=\"pl-c1\">7.2</span>,<span class=\"pl-c1\">8.9</span>,<span class=\"pl-c1\">12</span>,<span class=\"pl-c1\">55</span>,<span class=\"pl-c1\">11</span>,<span class=\"pl-c1\">34</span>,<span class=\"pl-c1\">69</span>,<span class=\"pl-c1\">115</span>,<span class=\"pl-c1\">173</span>,<span class=\"pl-c1\">242</span>,<span class=\"pl-c1\">323</span>,<span class=\"pl-c1\">416</span>,<span class=\"pl-c1\">520</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">520</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">28</span>,<span class=\"pl-s\">\"主角指1\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">125</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"千蛛万毒手\"</span>,<span class=\"pl-c1\">1</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">3</span>,<span class=\"pl-c1\">4</span>,<span class=\"pl-c1\">5</span>,<span class=\"pl-c1\">6</span>,<span class=\"pl-c1\">7</span>,<span class=\"pl-c1\">8</span>,<span class=\"pl-c1\">9</span>,<span class=\"pl-c1\">11</span>,<span class=\"pl-c1\">50</span>,<span class=\"pl-c1\">11</span>,<span class=\"pl-c1\">34</span>,<span class=\"pl-c1\">69</span>,<span class=\"pl-c1\">115</span>,<span class=\"pl-c1\">173</span>,<span class=\"pl-c1\">242</span>,<span class=\"pl-c1\">323</span>,<span class=\"pl-c1\">416</span>,<span class=\"pl-c1\">520</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">520</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">21</span>,<span class=\"pl-s\">\"主角指1\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">126</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"三阴蜈蚣爪\"</span>,<span class=\"pl-c1\">0.63</span>,<span class=\"pl-c1\">1.26</span>,<span class=\"pl-c1\">1.89</span>,<span class=\"pl-c1\">2.52</span>,<span class=\"pl-c1\">3.15</span>,<span class=\"pl-c1\">3.78</span>,<span class=\"pl-c1\">4.41</span>,<span class=\"pl-c1\">5.04</span>,<span class=\"pl-c1\">6.67</span>,<span class=\"pl-c1\">8.9</span>,<span class=\"pl-c1\">65</span>,<span class=\"pl-c1\">11</span>,<span class=\"pl-c1\">34</span>,<span class=\"pl-c1\">69</span>,<span class=\"pl-c1\">115</span>,<span class=\"pl-c1\">173</span>,<span class=\"pl-c1\">242</span>,<span class=\"pl-c1\">323</span>,<span class=\"pl-c1\">416</span>,<span class=\"pl-c1\">520</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">520</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">25</span>,<span class=\"pl-s\">\"主角指1\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">127</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"锁喉擒拿手\"</span>,<span class=\"pl-c1\">0.77</span>,<span class=\"pl-c1\">1.54</span>,<span class=\"pl-c1\">2.32</span>,<span class=\"pl-c1\">3.09</span>,<span class=\"pl-c1\">3.86</span>,<span class=\"pl-c1\">4.63</span>,<span class=\"pl-c1\">5.4</span>,<span class=\"pl-c1\">6.17</span>,<span class=\"pl-c1\">7.94</span>,<span class=\"pl-c1\">9.5</span>,<span class=\"pl-c1\">50</span>,<span class=\"pl-c1\">11</span>,<span class=\"pl-c1\">34</span>,<span class=\"pl-c1\">69</span>,<span class=\"pl-c1\">115</span>,<span class=\"pl-c1\">173</span>,<span class=\"pl-c1\">242</span>,<span class=\"pl-c1\">323</span>,<span class=\"pl-c1\">416</span>,<span class=\"pl-c1\">520</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">520</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">22</span>,<span class=\"pl-s\">\"主角指1\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">128</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"无相劫指\"</span>,<span class=\"pl-c1\">1.18</span>,<span class=\"pl-c1\">2.36</span>,<span class=\"pl-c1\">3.54</span>,<span class=\"pl-c1\">4.72</span>,<span class=\"pl-c1\">5.9</span>,<span class=\"pl-c1\">7.08</span>,<span class=\"pl-c1\">8.26</span>,<span class=\"pl-c1\">9.44</span>,<span class=\"pl-c1\">10.62</span>,<span class=\"pl-c1\">13</span>,<span class=\"pl-c1\">55</span>,<span class=\"pl-c1\">14</span>,<span class=\"pl-c1\">42</span>,<span class=\"pl-c1\">84</span>,<span class=\"pl-c1\">140</span>,<span class=\"pl-c1\">210</span>,<span class=\"pl-c1\">294</span>,<span class=\"pl-c1\">392</span>,<span class=\"pl-c1\">504</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">33</span>,<span class=\"pl-s\">\"主角指1\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">129</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"一阳指\"</span>,<span class=\"pl-c1\">1.22</span>,<span class=\"pl-c1\">2.44</span>,<span class=\"pl-c1\">3.66</span>,<span class=\"pl-c1\">4.88</span>,<span class=\"pl-c1\">6.1</span>,<span class=\"pl-c1\">7.32</span>,<span class=\"pl-c1\">8.54</span>,<span class=\"pl-c1\">9.76</span>,<span class=\"pl-c1\">10.98</span>,<span class=\"pl-c1\">13.5</span>,<span class=\"pl-c1\">65</span>,<span class=\"pl-c1\">14</span>,<span class=\"pl-c1\">42</span>,<span class=\"pl-c1\">84</span>,<span class=\"pl-c1\">140</span>,<span class=\"pl-c1\">210</span>,<span class=\"pl-c1\">294</span>,<span class=\"pl-c1\">392</span>,<span class=\"pl-c1\">504</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">28</span>,<span class=\"pl-s\">\"主角指1\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">130</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"鹰爪擒拿手\"</span>,<span class=\"pl-c1\">0.72</span>,<span class=\"pl-c1\">1.44</span>,<span class=\"pl-c1\">2.16</span>,<span class=\"pl-c1\">2.88</span>,<span class=\"pl-c1\">3.6</span>,<span class=\"pl-c1\">4.32</span>,<span class=\"pl-c1\">5.04</span>,<span class=\"pl-c1\">5.76</span>,<span class=\"pl-c1\">6.48</span>,<span class=\"pl-c1\">8</span>,<span class=\"pl-c1\">55</span>,<span class=\"pl-c1\">14</span>,<span class=\"pl-c1\">42</span>,<span class=\"pl-c1\">84</span>,<span class=\"pl-c1\">140</span>,<span class=\"pl-c1\">210</span>,<span class=\"pl-c1\">294</span>,<span class=\"pl-c1\">392</span>,<span class=\"pl-c1\">504</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">33</span>,<span class=\"pl-s\">\"主角指1\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">131</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"八荒六合唯我独尊功\"</span>,<span class=\"pl-c1\">3.5</span>,<span class=\"pl-c1\">3.8</span>,<span class=\"pl-c1\">4.1</span>,<span class=\"pl-c1\">4.4</span>,<span class=\"pl-c1\">4.8</span>,<span class=\"pl-c1\">5.2</span>,<span class=\"pl-c1\">5.6</span>,<span class=\"pl-c1\">6.1</span>,<span class=\"pl-c1\">6.7</span>,<span class=\"pl-c1\">17.5</span>,<span class=\"pl-c1\">75</span>,<span class=\"pl-c1\">18</span>,<span class=\"pl-c1\">56</span>,<span class=\"pl-c1\">113</span>,<span class=\"pl-c1\">188</span>,<span class=\"pl-c1\">283</span>,<span class=\"pl-c1\">396</span>,<span class=\"pl-c1\">528</span>,<span class=\"pl-c1\">680</span>,<span class=\"pl-c1\">850</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">850</span>,<span class=\"pl-c1\">5</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">86</span>,<span class=\"pl-s\">\"主角内功\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">132</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"北冥神功\"</span>,<span class=\"pl-c1\">1.77</span>,<span class=\"pl-c1\">2.54</span>,<span class=\"pl-c1\">3.32</span>,<span class=\"pl-c1\">4.09</span>,<span class=\"pl-c1\">5.86</span>,<span class=\"pl-c1\">6.63</span>,<span class=\"pl-c1\">7.4</span>,<span class=\"pl-c1\">8.17</span>,<span class=\"pl-c1\">9.94</span>,<span class=\"pl-c1\">12.8</span>,<span class=\"pl-c1\">50</span>,<span class=\"pl-c1\">14</span>,<span class=\"pl-c1\">42</span>,<span class=\"pl-c1\">84</span>,<span class=\"pl-c1\">140</span>,<span class=\"pl-c1\">210</span>,<span class=\"pl-c1\">294</span>,<span class=\"pl-c1\">392</span>,<span class=\"pl-c1\">504</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-s\">\"主角内功\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">133</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"蛤蟆功\"</span>,<span class=\"pl-c1\">1.57</span>,<span class=\"pl-c1\">3.14</span>,<span class=\"pl-c1\">4.71</span>,<span class=\"pl-c1\">6.28</span>,<span class=\"pl-c1\">7.85</span>,<span class=\"pl-c1\">9.42</span>,<span class=\"pl-c1\">10.99</span>,<span class=\"pl-c1\">11.56</span>,<span class=\"pl-c1\">12.53</span>,<span class=\"pl-c1\">16.3</span>,<span class=\"pl-c1\">60</span>,<span class=\"pl-c1\">16</span>,<span class=\"pl-c1\">50</span>,<span class=\"pl-c1\">100</span>,<span class=\"pl-c1\">166</span>,<span class=\"pl-c1\">250</span>,<span class=\"pl-c1\">350</span>,<span class=\"pl-c1\">466</span>,<span class=\"pl-c1\">600</span>,<span class=\"pl-c1\">750</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">750</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">74</span>,<span class=\"pl-s\">\"主角内功\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">134</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"龟息功\"</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">60</span>,<span class=\"pl-c1\">14</span>,<span class=\"pl-c1\">42</span>,<span class=\"pl-c1\">84</span>,<span class=\"pl-c1\">140</span>,<span class=\"pl-c1\">210</span>,<span class=\"pl-c1\">294</span>,<span class=\"pl-c1\">392</span>,<span class=\"pl-c1\">504</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">1</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">31</span>,<span class=\"pl-s\">\"主角内功\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">135</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"化功大法\"</span>,<span class=\"pl-c1\">0.93</span>,<span class=\"pl-c1\">2.26</span>,<span class=\"pl-c1\">2.89</span>,<span class=\"pl-c1\">3.52</span>,<span class=\"pl-c1\">4.15</span>,<span class=\"pl-c1\">5.78</span>,<span class=\"pl-c1\">6.41</span>,<span class=\"pl-c1\">7.04</span>,<span class=\"pl-c1\">7.67</span>,<span class=\"pl-c1\">8.9</span>,<span class=\"pl-c1\">65</span>,<span class=\"pl-c1\">14</span>,<span class=\"pl-c1\">42</span>,<span class=\"pl-c1\">84</span>,<span class=\"pl-c1\">140</span>,<span class=\"pl-c1\">210</span>,<span class=\"pl-c1\">294</span>,<span class=\"pl-c1\">392</span>,<span class=\"pl-c1\">504</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">22</span>,<span class=\"pl-s\">\"主角内功\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">136</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"混元功\"</span>,<span class=\"pl-c1\">1.18</span>,<span class=\"pl-c1\">2.36</span>,<span class=\"pl-c1\">3.54</span>,<span class=\"pl-c1\">4.72</span>,<span class=\"pl-c1\">5.9</span>,<span class=\"pl-c1\">7.08</span>,<span class=\"pl-c1\">8.26</span>,<span class=\"pl-c1\">9.44</span>,<span class=\"pl-c1\">10.62</span>,<span class=\"pl-c1\">13</span>,<span class=\"pl-c1\">60</span>,<span class=\"pl-c1\">16</span>,<span class=\"pl-c1\">50</span>,<span class=\"pl-c1\">100</span>,<span class=\"pl-c1\">166</span>,<span class=\"pl-c1\">250</span>,<span class=\"pl-c1\">350</span>,<span class=\"pl-c1\">466</span>,<span class=\"pl-c1\">600</span>,<span class=\"pl-c1\">750</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">750</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">72</span>,<span class=\"pl-s\">\"主角内功\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">137</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"金刚不坏神功\"</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">50</span>,<span class=\"pl-c1\">14</span>,<span class=\"pl-c1\">42</span>,<span class=\"pl-c1\">84</span>,<span class=\"pl-c1\">140</span>,<span class=\"pl-c1\">210</span>,<span class=\"pl-c1\">294</span>,<span class=\"pl-c1\">392</span>,<span class=\"pl-c1\">504</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">27</span>,<span class=\"pl-s\">\"主角内功\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">138</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"九阳神功\"</span>,<span class=\"pl-c1\">1.43</span>,<span class=\"pl-c1\">2.86</span>,<span class=\"pl-c1\">4.29</span>,<span class=\"pl-c1\">5.72</span>,<span class=\"pl-c1\">7.15</span>,<span class=\"pl-c1\">8.58</span>,<span class=\"pl-c1\">10.01</span>,<span class=\"pl-c1\">11.44</span>,<span class=\"pl-c1\">12.87</span>,<span class=\"pl-c1\">16.8</span>,<span class=\"pl-c1\">70</span>,<span class=\"pl-c1\">14</span>,<span class=\"pl-c1\">42</span>,<span class=\"pl-c1\">84</span>,<span class=\"pl-c1\">140</span>,<span class=\"pl-c1\">210</span>,<span class=\"pl-c1\">294</span>,<span class=\"pl-c1\">392</span>,<span class=\"pl-c1\">504</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">3</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">94</span>,<span class=\"pl-s\">\"主角内功\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">139</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"绝世武功\"</span>,<span class=\"pl-c1\">1.63</span>,<span class=\"pl-c1\">3.26</span>,<span class=\"pl-c1\">4.89</span>,<span class=\"pl-c1\">6.52</span>,<span class=\"pl-c1\">8.15</span>,<span class=\"pl-c1\">9.78</span>,<span class=\"pl-c1\">11.41</span>,<span class=\"pl-c1\">13.04</span>,<span class=\"pl-c1\">14.67</span>,<span class=\"pl-c1\">18</span>,<span class=\"pl-c1\">40</span>,<span class=\"pl-c1\">18</span>,<span class=\"pl-c1\">56</span>,<span class=\"pl-c1\">113</span>,<span class=\"pl-c1\">188</span>,<span class=\"pl-c1\">283</span>,<span class=\"pl-c1\">396</span>,<span class=\"pl-c1\">528</span>,<span class=\"pl-c1\">680</span>,<span class=\"pl-c1\">850</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">850</span>,<span class=\"pl-c1\">5</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">120</span>,<span class=\"pl-s\">\"主角绝招\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">140</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"葵花神功\"</span>,<span class=\"pl-c1\">1.4</span>,<span class=\"pl-c1\">2.8</span>,<span class=\"pl-c1\">4.2</span>,<span class=\"pl-c1\">5.6</span>,<span class=\"pl-c1\">7</span>,<span class=\"pl-c1\">8.4</span>,<span class=\"pl-c1\">9.8</span>,<span class=\"pl-c1\">11.2</span>,<span class=\"pl-c1\">12.6</span>,<span class=\"pl-c1\">15</span>,<span class=\"pl-c1\">35</span>,<span class=\"pl-c1\">18</span>,<span class=\"pl-c1\">56</span>,<span class=\"pl-c1\">113</span>,<span class=\"pl-c1\">188</span>,<span class=\"pl-c1\">283</span>,<span class=\"pl-c1\">396</span>,<span class=\"pl-c1\">528</span>,<span class=\"pl-c1\">680</span>,<span class=\"pl-c1\">850</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">850</span>,<span class=\"pl-c1\">5</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">116</span>,<span class=\"pl-s\">\"主角内功\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">141</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"龙象般若功\"</span>,<span class=\"pl-c1\">1.81</span>,<span class=\"pl-c1\">3.62</span>,<span class=\"pl-c1\">5.43</span>,<span class=\"pl-c1\">7.24</span>,<span class=\"pl-c1\">9.05</span>,<span class=\"pl-c1\">10.86</span>,<span class=\"pl-c1\">12.66</span>,<span class=\"pl-c1\">14.47</span>,<span class=\"pl-c1\">16.28</span>,<span class=\"pl-c1\">17.2</span>,<span class=\"pl-c1\">65</span>,<span class=\"pl-c1\">50</span>,<span class=\"pl-c1\">150</span>,<span class=\"pl-c1\">300</span>,<span class=\"pl-c1\">500</span>,<span class=\"pl-c1\">750</span>,<span class=\"pl-c1\">1050</span>,<span class=\"pl-c1\">1400</span>,<span class=\"pl-c1\">1800</span>,<span class=\"pl-c1\">2750</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">750</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">84</span>,<span class=\"pl-s\">\"主角内功\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">142</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"乾坤大挪移\"</span>,<span class=\"pl-c1\">1.45</span>,<span class=\"pl-c1\">2.9</span>,<span class=\"pl-c1\">4.35</span>,<span class=\"pl-c1\">5.8</span>,<span class=\"pl-c1\">7.25</span>,<span class=\"pl-c1\">8.7</span>,<span class=\"pl-c1\">10.15</span>,<span class=\"pl-c1\">11.6</span>,<span class=\"pl-c1\">13.05</span>,<span class=\"pl-c1\">16</span>,<span class=\"pl-c1\">55</span>,<span class=\"pl-c1\">16</span>,<span class=\"pl-c1\">50</span>,<span class=\"pl-c1\">100</span>,<span class=\"pl-c1\">166</span>,<span class=\"pl-c1\">250</span>,<span class=\"pl-c1\">350</span>,<span class=\"pl-c1\">466</span>,<span class=\"pl-c1\">600</span>,<span class=\"pl-c1\">750</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">750</span>,<span class=\"pl-c1\">5</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">72</span>,<span class=\"pl-s\">\"主角内功\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">143</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"神龙心法\"</span>,<span class=\"pl-c1\">1.01</span>,<span class=\"pl-c1\">2.02</span>,<span class=\"pl-c1\">3.03</span>,<span class=\"pl-c1\">4.04</span>,<span class=\"pl-c1\">5.05</span>,<span class=\"pl-c1\">6.06</span>,<span class=\"pl-c1\">7.07</span>,<span class=\"pl-c1\">8.08</span>,<span class=\"pl-c1\">9.09</span>,<span class=\"pl-c1\">11.2</span>,<span class=\"pl-c1\">60</span>,<span class=\"pl-c1\">14</span>,<span class=\"pl-c1\">42</span>,<span class=\"pl-c1\">84</span>,<span class=\"pl-c1\">140</span>,<span class=\"pl-c1\">210</span>,<span class=\"pl-c1\">294</span>,<span class=\"pl-c1\">392</span>,<span class=\"pl-c1\">504</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">3</span>,<span class=\"pl-c1\">38</span>,<span class=\"pl-s\">\"主角内功\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">144</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"神照功\"</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">75</span>,<span class=\"pl-c1\">16</span>,<span class=\"pl-c1\">50</span>,<span class=\"pl-c1\">100</span>,<span class=\"pl-c1\">166</span>,<span class=\"pl-c1\">250</span>,<span class=\"pl-c1\">350</span>,<span class=\"pl-c1\">466</span>,<span class=\"pl-c1\">600</span>,<span class=\"pl-c1\">750</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">750</span>,<span class=\"pl-c1\">1</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">74</span>,<span class=\"pl-s\">\"主角内功\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">145</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"狮吼功\"</span>,<span class=\"pl-c1\">1.22</span>,<span class=\"pl-c1\">2.44</span>,<span class=\"pl-c1\">3.66</span>,<span class=\"pl-c1\">4.88</span>,<span class=\"pl-c1\">6.1</span>,<span class=\"pl-c1\">7.32</span>,<span class=\"pl-c1\">8.54</span>,<span class=\"pl-c1\">9.76</span>,<span class=\"pl-c1\">10.98</span>,<span class=\"pl-c1\">13.5</span>,<span class=\"pl-c1\">60</span>,<span class=\"pl-c1\">16</span>,<span class=\"pl-c1\">50</span>,<span class=\"pl-c1\">100</span>,<span class=\"pl-c1\">166</span>,<span class=\"pl-c1\">250</span>,<span class=\"pl-c1\">350</span>,<span class=\"pl-c1\">466</span>,<span class=\"pl-c1\">600</span>,<span class=\"pl-c1\">750</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">750</span>,<span class=\"pl-c1\">5</span>,<span class=\"pl-c1\">3</span>,<span class=\"pl-c1\">98</span>,<span class=\"pl-s\">\"主角内功\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">146</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"太玄经\"</span>,<span class=\"pl-c1\">1.74</span>,<span class=\"pl-c1\">3.48</span>,<span class=\"pl-c1\">5.22</span>,<span class=\"pl-c1\">6.96</span>,<span class=\"pl-c1\">8.7</span>,<span class=\"pl-c1\">10.44</span>,<span class=\"pl-c1\">12.18</span>,<span class=\"pl-c1\">13.92</span>,<span class=\"pl-c1\">15.66</span>,<span class=\"pl-c1\">19.5</span>,<span class=\"pl-c1\">80</span>,<span class=\"pl-c1\">18</span>,<span class=\"pl-c1\">56</span>,<span class=\"pl-c1\">113</span>,<span class=\"pl-c1\">188</span>,<span class=\"pl-c1\">283</span>,<span class=\"pl-c1\">396</span>,<span class=\"pl-c1\">528</span>,<span class=\"pl-c1\">680</span>,<span class=\"pl-c1\">850</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">850</span>,<span class=\"pl-c1\">5</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">56</span>,<span class=\"pl-s\">\"主角内功\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">147</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"吸星大法\"</span>,<span class=\"pl-c1\">1.63</span>,<span class=\"pl-c1\">2.26</span>,<span class=\"pl-c1\">3.89</span>,<span class=\"pl-c1\">4.52</span>,<span class=\"pl-c1\">5.15</span>,<span class=\"pl-c1\">6.78</span>,<span class=\"pl-c1\">7.41</span>,<span class=\"pl-c1\">8.04</span>,<span class=\"pl-c1\">9.67</span>,<span class=\"pl-c1\">11</span>,<span class=\"pl-c1\">60</span>,<span class=\"pl-c1\">14</span>,<span class=\"pl-c1\">42</span>,<span class=\"pl-c1\">84</span>,<span class=\"pl-c1\">140</span>,<span class=\"pl-c1\">210</span>,<span class=\"pl-c1\">294</span>,<span class=\"pl-c1\">392</span>,<span class=\"pl-c1\">504</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-s\">\"主角内功\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">148</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"小无相功\"</span>,<span class=\"pl-c1\">1.63</span>,<span class=\"pl-c1\">3.26</span>,<span class=\"pl-c1\">4.89</span>,<span class=\"pl-c1\">6.52</span>,<span class=\"pl-c1\">8.15</span>,<span class=\"pl-c1\">9.78</span>,<span class=\"pl-c1\">11.41</span>,<span class=\"pl-c1\">13.04</span>,<span class=\"pl-c1\">14.67</span>,<span class=\"pl-c1\">18</span>,<span class=\"pl-c1\">60</span>,<span class=\"pl-c1\">16</span>,<span class=\"pl-c1\">50</span>,<span class=\"pl-c1\">100</span>,<span class=\"pl-c1\">166</span>,<span class=\"pl-c1\">250</span>,<span class=\"pl-c1\">350</span>,<span class=\"pl-c1\">466</span>,<span class=\"pl-c1\">600</span>,<span class=\"pl-c1\">750</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">750</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">62</span>,<span class=\"pl-s\">\"主角内功\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">149</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"紫霞神功\"</span>,<span class=\"pl-c1\">1.22</span>,<span class=\"pl-c1\">2.44</span>,<span class=\"pl-c1\">3.66</span>,<span class=\"pl-c1\">4.88</span>,<span class=\"pl-c1\">6.1</span>,<span class=\"pl-c1\">7.32</span>,<span class=\"pl-c1\">8.54</span>,<span class=\"pl-c1\">9.76</span>,<span class=\"pl-c1\">10.98</span>,<span class=\"pl-c1\">13.5</span>,<span class=\"pl-c1\">60</span>,<span class=\"pl-c1\">14</span>,<span class=\"pl-c1\">42</span>,<span class=\"pl-c1\">84</span>,<span class=\"pl-c1\">140</span>,<span class=\"pl-c1\">210</span>,<span class=\"pl-c1\">294</span>,<span class=\"pl-c1\">392</span>,<span class=\"pl-c1\">504</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">58</span>,<span class=\"pl-s\">\"主角内功\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">159</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"罗汉伏魔功\"</span>,<span class=\"pl-c1\">1.36</span>,<span class=\"pl-c1\">2.72</span>,<span class=\"pl-c1\">4.08</span>,<span class=\"pl-c1\">5.44</span>,<span class=\"pl-c1\">6.8</span>,<span class=\"pl-c1\">8.16</span>,<span class=\"pl-c1\">9.52</span>,<span class=\"pl-c1\">10.88</span>,<span class=\"pl-c1\">12.24</span>,<span class=\"pl-c1\">15</span>,<span class=\"pl-c1\">70</span>,<span class=\"pl-c1\">14</span>,<span class=\"pl-c1\">42</span>,<span class=\"pl-c1\">84</span>,<span class=\"pl-c1\">140</span>,<span class=\"pl-c1\">210</span>,<span class=\"pl-c1\">294</span>,<span class=\"pl-c1\">392</span>,<span class=\"pl-c1\">504</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">64</span>,<span class=\"pl-s\">\"主角内功\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">166</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"先天功\"</span>,<span class=\"pl-c1\">2.38</span>,<span class=\"pl-c1\">4.73</span>,<span class=\"pl-c1\">6.1</span>,<span class=\"pl-c1\">8.54</span>,<span class=\"pl-c1\">10.85</span>,<span class=\"pl-c1\">12.56</span>,<span class=\"pl-c1\">14.58</span>,<span class=\"pl-c1\">16.88</span>,<span class=\"pl-c1\">17.54</span>,<span class=\"pl-c1\">19.5</span>,<span class=\"pl-c1\">60</span>,<span class=\"pl-c1\">14</span>,<span class=\"pl-c1\">42</span>,<span class=\"pl-c1\">84</span>,<span class=\"pl-c1\">140</span>,<span class=\"pl-c1\">210</span>,<span class=\"pl-c1\">294</span>,<span class=\"pl-c1\">392</span>,<span class=\"pl-c1\">504</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">64</span>,<span class=\"pl-s\">\"主角内功\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">167</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"易筋经\"</span>,<span class=\"pl-c1\">1.63</span>,<span class=\"pl-c1\">3.26</span>,<span class=\"pl-c1\">4.89</span>,<span class=\"pl-c1\">6.52</span>,<span class=\"pl-c1\">8.15</span>,<span class=\"pl-c1\">9.78</span>,<span class=\"pl-c1\">11.41</span>,<span class=\"pl-c1\">13.04</span>,<span class=\"pl-c1\">14.67</span>,<span class=\"pl-c1\">17</span>,<span class=\"pl-c1\">80</span>,<span class=\"pl-c1\">18</span>,<span class=\"pl-c1\">56</span>,<span class=\"pl-c1\">113</span>,<span class=\"pl-c1\">188</span>,<span class=\"pl-c1\">283</span>,<span class=\"pl-c1\">396</span>,<span class=\"pl-c1\">528</span>,<span class=\"pl-c1\">680</span>,<span class=\"pl-c1\">850</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">850</span>,<span class=\"pl-c1\">5</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">76</span>,<span class=\"pl-s\">\"主角内功\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">187</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"毒雾\"</span>,<span class=\"pl-c1\">0.59</span>,<span class=\"pl-c1\">1.18</span>,<span class=\"pl-c1\">1.77</span>,<span class=\"pl-c1\">2.36</span>,<span class=\"pl-c1\">2.95</span>,<span class=\"pl-c1\">3.54</span>,<span class=\"pl-c1\">4.13</span>,<span class=\"pl-c1\">4.72</span>,<span class=\"pl-c1\">5.3</span>,<span class=\"pl-c1\">12.5</span>,<span class=\"pl-c1\">65</span>,<span class=\"pl-c1\">14</span>,<span class=\"pl-c1\">42</span>,<span class=\"pl-c1\">84</span>,<span class=\"pl-c1\">140</span>,<span class=\"pl-c1\">210</span>,<span class=\"pl-c1\">294</span>,<span class=\"pl-c1\">392</span>,<span class=\"pl-c1\">504</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">3</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">36</span>,<span class=\"pl-s\">\"主角内功\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">188</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"驱蜂术\"</span>,<span class=\"pl-c1\">0.77</span>,<span class=\"pl-c1\">1.54</span>,<span class=\"pl-c1\">2.32</span>,<span class=\"pl-c1\">3.09</span>,<span class=\"pl-c1\">3.86</span>,<span class=\"pl-c1\">4.63</span>,<span class=\"pl-c1\">5.4</span>,<span class=\"pl-c1\">6.17</span>,<span class=\"pl-c1\">6.94</span>,<span class=\"pl-c1\">8.5</span>,<span class=\"pl-c1\">65</span>,<span class=\"pl-c1\">14</span>,<span class=\"pl-c1\">42</span>,<span class=\"pl-c1\">84</span>,<span class=\"pl-c1\">140</span>,<span class=\"pl-c1\">210</span>,<span class=\"pl-c1\">294</span>,<span class=\"pl-c1\">392</span>,<span class=\"pl-c1\">504</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">5</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">20</span>,<span class=\"pl-s\">\"主角内功\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">189</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"星宿解毒术\"</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">60</span>,<span class=\"pl-c1\">14</span>,<span class=\"pl-c1\">42</span>,<span class=\"pl-c1\">84</span>,<span class=\"pl-c1\">140</span>,<span class=\"pl-c1\">210</span>,<span class=\"pl-c1\">294</span>,<span class=\"pl-c1\">392</span>,<span class=\"pl-c1\">504</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">1</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">42</span>,<span class=\"pl-s\">\"主角内功\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">191</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"普通攻击\"</span>,<span class=\"pl-c1\">0.51</span>,<span class=\"pl-c1\">1.02</span>,<span class=\"pl-c1\">1.53</span>,<span class=\"pl-c1\">2.04</span>,<span class=\"pl-c1\">2.55</span>,<span class=\"pl-c1\">3.06</span>,<span class=\"pl-c1\">3.57</span>,<span class=\"pl-c1\">4.08</span>,<span class=\"pl-c1\">4.9</span>,<span class=\"pl-c1\">10</span>,<span class=\"pl-c1\">20</span>,<span class=\"pl-c1\">9</span>,<span class=\"pl-c1\">29</span>,<span class=\"pl-c1\">58</span>,<span class=\"pl-c1\">97</span>,<span class=\"pl-c1\">146</span>,<span class=\"pl-c1\">205</span>,<span class=\"pl-c1\">273</span>,<span class=\"pl-c1\">352</span>,<span class=\"pl-c1\">440</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">100</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">5</span>,<span class=\"pl-s\">\"拳掌\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">192</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"火枪术\"</span>,<span class=\"pl-c1\">1.81</span>,<span class=\"pl-c1\">3.62</span>,<span class=\"pl-c1\">5.43</span>,<span class=\"pl-c1\">7.24</span>,<span class=\"pl-c1\">9.05</span>,<span class=\"pl-c1\">10.86</span>,<span class=\"pl-c1\">12.66</span>,<span class=\"pl-c1\">14.47</span>,<span class=\"pl-c1\">16.28</span>,<span class=\"pl-c1\">20</span>,<span class=\"pl-c1\">95</span>,<span class=\"pl-c1\">14</span>,<span class=\"pl-c1\">42</span>,<span class=\"pl-c1\">84</span>,<span class=\"pl-c1\">140</span>,<span class=\"pl-c1\">210</span>,<span class=\"pl-c1\">294</span>,<span class=\"pl-c1\">392</span>,<span class=\"pl-c1\">504</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">1</span>,<span class=\"pl-s\">\"拳掌\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">193</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"混元掌\"</span>,<span class=\"pl-c1\">1.13</span>,<span class=\"pl-c1\">2.26</span>,<span class=\"pl-c1\">3.39</span>,<span class=\"pl-c1\">4.52</span>,<span class=\"pl-c1\">5.65</span>,<span class=\"pl-c1\">6.78</span>,<span class=\"pl-c1\">7.91</span>,<span class=\"pl-c1\">9.04</span>,<span class=\"pl-c1\">10.17</span>,<span class=\"pl-c1\">15.5</span>,<span class=\"pl-c1\">55</span>,<span class=\"pl-c1\">14</span>,<span class=\"pl-c1\">42</span>,<span class=\"pl-c1\">84</span>,<span class=\"pl-c1\">140</span>,<span class=\"pl-c1\">210</span>,<span class=\"pl-c1\">294</span>,<span class=\"pl-c1\">392</span>,<span class=\"pl-c1\">504</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">33</span>,<span class=\"pl-s\">\"拳掌\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">194</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"玄冥神掌\"</span>,<span class=\"pl-c1\">1.13</span>,<span class=\"pl-c1\">2.26</span>,<span class=\"pl-c1\">3.39</span>,<span class=\"pl-c1\">4.52</span>,<span class=\"pl-c1\">5.65</span>,<span class=\"pl-c1\">6.78</span>,<span class=\"pl-c1\">7.91</span>,<span class=\"pl-c1\">9.04</span>,<span class=\"pl-c1\">10.17</span>,<span class=\"pl-c1\">18.5</span>,<span class=\"pl-c1\">60</span>,<span class=\"pl-c1\">14</span>,<span class=\"pl-c1\">42</span>,<span class=\"pl-c1\">84</span>,<span class=\"pl-c1\">140</span>,<span class=\"pl-c1\">210</span>,<span class=\"pl-c1\">294</span>,<span class=\"pl-c1\">392</span>,<span class=\"pl-c1\">504</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">630</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">38</span>,<span class=\"pl-s\">\"拳掌\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">195</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"五轮大法\"</span>,<span class=\"pl-c1\">1.25</span>,<span class=\"pl-c1\">2.5</span>,<span class=\"pl-c1\">3.75</span>,<span class=\"pl-c1\">5</span>,<span class=\"pl-c1\">6.25</span>,<span class=\"pl-c1\">7.5</span>,<span class=\"pl-c1\">8.75</span>,<span class=\"pl-c1\">10</span>,<span class=\"pl-c1\">11.25</span>,<span class=\"pl-c1\">13.8</span>,<span class=\"pl-c1\">50</span>,<span class=\"pl-c1\">16</span>,<span class=\"pl-c1\">50</span>,<span class=\"pl-c1\">100</span>,<span class=\"pl-c1\">166</span>,<span class=\"pl-c1\">250</span>,<span class=\"pl-c1\">350</span>,<span class=\"pl-c1\">466</span>,<span class=\"pl-c1\">600</span>,<span class=\"pl-c1\">750</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">750</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">41</span>,<span class=\"pl-s\">\"拳掌\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">196</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"阴阳捣乱刃\"</span>,<span class=\"pl-c1\">1.18</span>,<span class=\"pl-c1\">2.36</span>,<span class=\"pl-c1\">3.54</span>,<span class=\"pl-c1\">4.72</span>,<span class=\"pl-c1\">5.9</span>,<span class=\"pl-c1\">7.08</span>,<span class=\"pl-c1\">8.26</span>,<span class=\"pl-c1\">9.44</span>,<span class=\"pl-c1\">10.62</span>,<span class=\"pl-c1\">13</span>,<span class=\"pl-c1\">60</span>,<span class=\"pl-c1\">16</span>,<span class=\"pl-c1\">50</span>,<span class=\"pl-c1\">100</span>,<span class=\"pl-c1\">166</span>,<span class=\"pl-c1\">250</span>,<span class=\"pl-c1\">350</span>,<span class=\"pl-c1\">466</span>,<span class=\"pl-c1\">600</span>,<span class=\"pl-c1\">750</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">750</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">29</span>,<span class=\"pl-s\">\"拳掌\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">197</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"三僧鞭法\"</span>,<span class=\"pl-c1\">1.5</span>,<span class=\"pl-c1\">3</span>,<span class=\"pl-c1\">4.5</span>,<span class=\"pl-c1\">6</span>,<span class=\"pl-c1\">7.5</span>,<span class=\"pl-c1\">9</span>,<span class=\"pl-c1\">10.5</span>,<span class=\"pl-c1\">12</span>,<span class=\"pl-c1\">13.5</span>,<span class=\"pl-c1\">16.5</span>,<span class=\"pl-c1\">65</span>,<span class=\"pl-c1\">16</span>,<span class=\"pl-c1\">50</span>,<span class=\"pl-c1\">100</span>,<span class=\"pl-c1\">166</span>,<span class=\"pl-c1\">250</span>,<span class=\"pl-c1\">350</span>,<span class=\"pl-c1\">466</span>,<span class=\"pl-c1\">600</span>,<span class=\"pl-c1\">750</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">750</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">32</span>,<span class=\"pl-s\">\"拳掌\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">198</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"芷若鞭法\"</span>,<span class=\"pl-c1\">1.09</span>,<span class=\"pl-c1\">2.18</span>,<span class=\"pl-c1\">3.27</span>,<span class=\"pl-c1\">4.36</span>,<span class=\"pl-c1\">5.45</span>,<span class=\"pl-c1\">6.54</span>,<span class=\"pl-c1\">7.63</span>,<span class=\"pl-c1\">8.72</span>,<span class=\"pl-c1\">9.81</span>,<span class=\"pl-c1\">15</span>,<span class=\"pl-c1\">45</span>,<span class=\"pl-c1\">16</span>,<span class=\"pl-c1\">50</span>,<span class=\"pl-c1\">100</span>,<span class=\"pl-c1\">166</span>,<span class=\"pl-c1\">250</span>,<span class=\"pl-c1\">350</span>,<span class=\"pl-c1\">466</span>,<span class=\"pl-c1\">600</span>,<span class=\"pl-c1\">750</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">750</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">23</span>,<span class=\"pl-s\">\"拳掌\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\nSkills<span class=\"pl-k\">[</span><span class=\"pl-c1\">199</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">new</span> Skill(<span class=\"pl-s\">\"易筋神功\"</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">4</span>,<span class=\"pl-c1\">6</span>,<span class=\"pl-c1\">8</span>,<span class=\"pl-c1\">10</span>,<span class=\"pl-c1\">12</span>,<span class=\"pl-c1\">14.01</span>,<span class=\"pl-c1\">16</span>,<span class=\"pl-c1\">18</span>,<span class=\"pl-c1\">23</span>,<span class=\"pl-c1\">45</span>,<span class=\"pl-c1\">9</span>,<span class=\"pl-c1\">29</span>,<span class=\"pl-c1\">58</span>,<span class=\"pl-c1\">97</span>,<span class=\"pl-c1\">146</span>,<span class=\"pl-c1\">205</span>,<span class=\"pl-c1\">273</span>,<span class=\"pl-c1\">352</span>,<span class=\"pl-c1\">440</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">440</span>,<span class=\"pl-c1\">2</span>,<span class=\"pl-c1\">0</span>,<span class=\"pl-c1\">44</span>,<span class=\"pl-s\">\"拳掌\"</span>,<span class=\"pl-s\">\"攻击\"</span>)<span class=\"pl-k\">;</span>\n</code></pre>\n<p>注意：内功、武器对招式的加成作用不同。</p>\n<p>以下是某些武功最佳配套武器：</p>\n<pre><code class=\"language-actionscript\">    <span class=\"pl-k\">if</span>(<span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span>Skills<span class=\"pl-k\">[</span><span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span><span class=\"pl-c1\">body</span><span class=\"pl-k\">[</span><span class=\"pl-c1\">96</span><span class=\"pl-k\">]].</span>m_sName <span class=\"pl-k\">==</span> <span class=\"pl-s\">\"辟邪剑法\"</span> <span class=\"pl-k\">&#x26;&#x26;</span> <span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span><span class=\"pl-c1\">ZB</span><span class=\"pl-k\">[</span><span class=\"pl-c1\">2</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">==</span> <span class=\"pl-c1\">29</span>)\n    {\n      hurt = int(2 * hurt);\n    }\n    <span class=\"pl-k\">if</span>(<span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span>Skills<span class=\"pl-k\">[</span><span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span><span class=\"pl-c1\">body</span><span class=\"pl-k\">[</span><span class=\"pl-c1\">96</span><span class=\"pl-k\">]].</span>m_sName <span class=\"pl-k\">==</span> <span class=\"pl-s\">\"冰雪剑法\"</span> <span class=\"pl-k\">&#x26;&#x26;</span> <span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span><span class=\"pl-c1\">ZB</span><span class=\"pl-k\">[</span><span class=\"pl-c1\">2</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">==</span> <span class=\"pl-c1\">10</span>)\n    {\n      hurt = int(1.3 * hurt);\n    }\n    <span class=\"pl-k\">if</span>(<span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span>Skills<span class=\"pl-k\">[</span><span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span><span class=\"pl-c1\">body</span><span class=\"pl-k\">[</span><span class=\"pl-c1\">96</span><span class=\"pl-k\">]].</span>m_sName <span class=\"pl-k\">==</span> <span class=\"pl-s\">\"独孤九剑\"</span> <span class=\"pl-k\">&#x26;&#x26;</span> <span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span><span class=\"pl-c1\">ZB</span><span class=\"pl-k\">[</span><span class=\"pl-c1\">2</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">==</span> <span class=\"pl-c1\">29</span>)\n    {\n      hurt = int(1.7 * hurt);\n    }\n    <span class=\"pl-k\">if</span>(<span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span>Skills<span class=\"pl-k\">[</span><span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span><span class=\"pl-c1\">body</span><span class=\"pl-k\">[</span><span class=\"pl-c1\">96</span><span class=\"pl-k\">]].</span>m_sName <span class=\"pl-k\">==</span> <span class=\"pl-s\">\"金蛇剑法\"</span> <span class=\"pl-k\">&#x26;&#x26;</span> <span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span><span class=\"pl-c1\">ZB</span><span class=\"pl-k\">[</span><span class=\"pl-c1\">2</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">==</span> <span class=\"pl-c1\">22</span>)\n    {\n      hurt = int(1.6 * hurt);\n    }\n    <span class=\"pl-k\">if</span>(<span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span>Skills<span class=\"pl-k\">[</span><span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span><span class=\"pl-c1\">body</span><span class=\"pl-k\">[</span><span class=\"pl-c1\">96</span><span class=\"pl-k\">]].</span>m_sName <span class=\"pl-k\">==</span> <span class=\"pl-s\">\"灭绝剑法\"</span> <span class=\"pl-k\">&#x26;&#x26;</span> <span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span><span class=\"pl-c1\">ZB</span><span class=\"pl-k\">[</span><span class=\"pl-c1\">2</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">==</span> <span class=\"pl-c1\">29</span>)\n    {\n      hurt = int(1.6 * hurt);\n    }\n    <span class=\"pl-k\">if</span>(<span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span>Skills<span class=\"pl-k\">[</span><span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span><span class=\"pl-c1\">body</span><span class=\"pl-k\">[</span><span class=\"pl-c1\">96</span><span class=\"pl-k\">]].</span>m_sName <span class=\"pl-k\">==</span> <span class=\"pl-s\">\"绕指柔剑\"</span> <span class=\"pl-k\">&#x26;&#x26;</span> <span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span><span class=\"pl-c1\">ZB</span><span class=\"pl-k\">[</span><span class=\"pl-c1\">2</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">==</span> <span class=\"pl-c1\">14</span>)\n    {\n      hurt = int(1.6 * hurt);\n    }\n    <span class=\"pl-k\">if</span>(<span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span>Skills<span class=\"pl-k\">[</span><span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span><span class=\"pl-c1\">body</span><span class=\"pl-k\">[</span><span class=\"pl-c1\">96</span><span class=\"pl-k\">]].</span>m_sName <span class=\"pl-k\">==</span> <span class=\"pl-s\">\"太极剑\"</span> <span class=\"pl-k\">&#x26;&#x26;</span> <span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span><span class=\"pl-c1\">ZB</span><span class=\"pl-k\">[</span><span class=\"pl-c1\">2</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">==</span> <span class=\"pl-c1\">25</span>)\n    {\n      hurt = int(2 * hurt);\n    }\n    <span class=\"pl-k\">if</span>(<span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span>Skills<span class=\"pl-k\">[</span><span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span><span class=\"pl-c1\">body</span><span class=\"pl-k\">[</span><span class=\"pl-c1\">96</span><span class=\"pl-k\">]].</span>m_sName <span class=\"pl-k\">==</span> <span class=\"pl-s\">\"玉箫剑法\"</span> <span class=\"pl-k\">&#x26;&#x26;</span> <span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span><span class=\"pl-c1\">ZB</span><span class=\"pl-k\">[</span><span class=\"pl-c1\">2</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">==</span> <span class=\"pl-c1\">4</span>)\n    {\n      hurt = int(1.4 * hurt);\n    }\n    <span class=\"pl-k\">if</span>(<span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span>Skills<span class=\"pl-k\">[</span><span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span><span class=\"pl-c1\">body</span><span class=\"pl-k\">[</span><span class=\"pl-c1\">96</span><span class=\"pl-k\">]].</span>m_sName <span class=\"pl-k\">==</span> <span class=\"pl-s\">\"玄铁剑法\"</span> <span class=\"pl-k\">&#x26;&#x26;</span> <span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span><span class=\"pl-c1\">ZB</span><span class=\"pl-k\">[</span><span class=\"pl-c1\">2</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">==</span> <span class=\"pl-c1\">28</span>)\n    {\n      hurt = int(1.7 * hurt);\n    }\n</code></pre>\n<p>可以看到，倚天对辟邪、独孤，及真武对太极加成最大。</p>\n<p>某些刀法和配套的宝刀：</p>\n<pre><code class=\"language-actionscript\">    <span class=\"pl-k\">if</span>(<span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span>Skills<span class=\"pl-k\">[</span><span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span><span class=\"pl-c1\">body</span><span class=\"pl-k\">[</span><span class=\"pl-c1\">96</span><span class=\"pl-k\">]].</span>m_sName <span class=\"pl-k\">==</span> <span class=\"pl-s\">\"柴刀十八路\"</span> <span class=\"pl-k\">&#x26;&#x26;</span> <span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span><span class=\"pl-c1\">ZB</span><span class=\"pl-k\">[</span><span class=\"pl-c1\">2</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">==</span> <span class=\"pl-c1\">31</span>)\n    {\n      hurt = int(1.4 * hurt);\n    }\n    <span class=\"pl-k\">if</span>(<span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span>Skills<span class=\"pl-k\">[</span><span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span><span class=\"pl-c1\">body</span><span class=\"pl-k\">[</span><span class=\"pl-c1\">96</span><span class=\"pl-k\">]].</span>m_sName <span class=\"pl-k\">==</span> <span class=\"pl-s\">\"胡家刀法\"</span> <span class=\"pl-k\">&#x26;&#x26;</span> <span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span><span class=\"pl-c1\">ZB</span><span class=\"pl-k\">[</span><span class=\"pl-c1\">2</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">==</span> <span class=\"pl-c1\">54</span>)\n    {\n      hurt = int(1.7 * hurt);\n    }\n    <span class=\"pl-k\">if</span>(<span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span>Skills<span class=\"pl-k\">[</span><span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span><span class=\"pl-c1\">body</span><span class=\"pl-k\">[</span><span class=\"pl-c1\">96</span><span class=\"pl-k\">]].</span>m_sName <span class=\"pl-k\">==</span> <span class=\"pl-s\">\"基本刀法\"</span> <span class=\"pl-k\">&#x26;&#x26;</span> <span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span><span class=\"pl-c1\">ZB</span><span class=\"pl-k\">[</span><span class=\"pl-c1\">2</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">==</span> <span class=\"pl-c1\">32</span>)\n    {\n      hurt = int(1.3 * hurt);\n    }\n    <span class=\"pl-k\">if</span>(<span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span>Skills<span class=\"pl-k\">[</span><span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span><span class=\"pl-c1\">body</span><span class=\"pl-k\">[</span><span class=\"pl-c1\">96</span><span class=\"pl-k\">]].</span>m_sName <span class=\"pl-k\">==</span> <span class=\"pl-s\">\"狂风刀法\"</span> <span class=\"pl-k\">&#x26;&#x26;</span> <span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span><span class=\"pl-c1\">ZB</span><span class=\"pl-k\">[</span><span class=\"pl-c1\">2</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">==</span> <span class=\"pl-c1\">30</span>)\n    {\n      hurt = int(1.5 * hurt);\n    }\n    <span class=\"pl-k\">if</span>(<span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span>Skills<span class=\"pl-k\">[</span><span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span><span class=\"pl-c1\">body</span><span class=\"pl-k\">[</span><span class=\"pl-c1\">96</span><span class=\"pl-k\">]].</span>m_sName <span class=\"pl-k\">==</span> <span class=\"pl-s\">\"血刀刀法\"</span> <span class=\"pl-k\">&#x26;&#x26;</span> <span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span><span class=\"pl-c1\">ZB</span><span class=\"pl-k\">[</span><span class=\"pl-c1\">2</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">==</span> <span class=\"pl-c1\">47</span>)\n    {\n      hurt = int(1.6 * hurt);\n    }\n</code></pre>\n<p>最佳搭配是胡家刀法配冷月宝刀，然而加成也不过等于玄铁剑对玄铁剑法的加成，在剑里面只能算第二梯队。</p>\n<p>棍法的数据</p>\n<pre><code class=\"language-actionscript\"><span class=\"pl-k\">if</span>(<span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span>Skills<span class=\"pl-k\">[</span><span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span><span class=\"pl-c1\">body</span><span class=\"pl-k\">[</span><span class=\"pl-c1\">96</span><span class=\"pl-k\">]].</span>m_sName <span class=\"pl-k\">==</span> <span class=\"pl-s\">\"打狗棒法\"</span> <span class=\"pl-k\">&#x26;&#x26;</span> <span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span><span class=\"pl-c1\">ZB</span><span class=\"pl-k\">[</span><span class=\"pl-c1\">2</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">==</span> <span class=\"pl-c1\">59</span>)\n{\n  hurt = int(1.8 * hurt);\n}\n<span class=\"pl-k\">if</span>(<span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span>Skills<span class=\"pl-k\">[</span><span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span><span class=\"pl-c1\">body</span><span class=\"pl-k\">[</span><span class=\"pl-c1\">96</span><span class=\"pl-k\">]].</span>m_sName <span class=\"pl-k\">==</span> <span class=\"pl-s\">\"伏魔杖法\"</span> <span class=\"pl-k\">&#x26;&#x26;</span> <span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span><span class=\"pl-c1\">ZB</span><span class=\"pl-k\">[</span><span class=\"pl-c1\">2</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">==</span> <span class=\"pl-c1\">57</span>)\n{\n  hurt = int(1.5 * hurt);\n}\n<span class=\"pl-k\">if</span>(<span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span>Skills<span class=\"pl-k\">[</span><span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span><span class=\"pl-c1\">body</span><span class=\"pl-k\">[</span><span class=\"pl-c1\">96</span><span class=\"pl-k\">]].</span>m_sName <span class=\"pl-k\">==</span> <span class=\"pl-s\">\"基本棍法\"</span> <span class=\"pl-k\">&#x26;&#x26;</span> <span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span><span class=\"pl-c1\">ZB</span><span class=\"pl-k\">[</span><span class=\"pl-c1\">2</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">==</span> <span class=\"pl-c1\">56</span>)\n{\n  hurt = int(1.3 * hurt);\n}\n<span class=\"pl-k\">if</span>(<span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span>Skills<span class=\"pl-k\">[</span><span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span><span class=\"pl-c1\">body</span><span class=\"pl-k\">[</span><span class=\"pl-c1\">96</span><span class=\"pl-k\">]].</span>m_sName <span class=\"pl-k\">==</span> <span class=\"pl-s\">\"叫花棒法\"</span> <span class=\"pl-k\">&#x26;&#x26;</span> <span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span><span class=\"pl-c1\">ZB</span><span class=\"pl-k\">[</span><span class=\"pl-c1\">2</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">==</span> <span class=\"pl-c1\">59</span>)\n{\n  hurt = int(1.4 * hurt);\n}\n<span class=\"pl-k\">if</span>(<span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span>Skills<span class=\"pl-k\">[</span><span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span><span class=\"pl-c1\">body</span><span class=\"pl-k\">[</span><span class=\"pl-c1\">96</span><span class=\"pl-k\">]].</span>m_sName <span class=\"pl-k\">==</span> <span class=\"pl-s\">\"金刚降魔杵\"</span> <span class=\"pl-k\">&#x26;&#x26;</span> <span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span><span class=\"pl-c1\">ZB</span><span class=\"pl-k\">[</span><span class=\"pl-c1\">2</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">==</span> <span class=\"pl-c1\">60</span>)\n{\n  hurt = int(1.6 * hurt);\n}\n<span class=\"pl-k\">if</span>(<span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span>Skills<span class=\"pl-k\">[</span><span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span><span class=\"pl-c1\">body</span><span class=\"pl-k\">[</span><span class=\"pl-c1\">96</span><span class=\"pl-k\">]].</span>m_sName <span class=\"pl-k\">==</span> <span class=\"pl-s\">\"灵蛇杖法\"</span> <span class=\"pl-k\">&#x26;&#x26;</span> <span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span><span class=\"pl-c1\">ZB</span><span class=\"pl-k\">[</span><span class=\"pl-c1\">2</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">==</span> <span class=\"pl-c1\">61</span>)\n{\n  hurt = int(1.7 * hurt);\n}\n<span class=\"pl-k\">if</span>(<span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span>Skills<span class=\"pl-k\">[</span><span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span><span class=\"pl-c1\">body</span><span class=\"pl-k\">[</span><span class=\"pl-c1\">96</span><span class=\"pl-k\">]].</span>m_sName <span class=\"pl-k\">==</span> <span class=\"pl-s\">\"太祖棍\"</span> <span class=\"pl-k\">&#x26;&#x26;</span> <span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span><span class=\"pl-c1\">ZB</span><span class=\"pl-k\">[</span><span class=\"pl-c1\">2</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">==</span> <span class=\"pl-c1\">58</span>)\n{\n  hurt = int(1.5 * hurt);\n}\n<span class=\"pl-k\">if</span>(<span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span>Skills<span class=\"pl-k\">[</span><span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span><span class=\"pl-c1\">body</span><span class=\"pl-k\">[</span><span class=\"pl-c1\">96</span><span class=\"pl-k\">]].</span>m_sName <span class=\"pl-k\">==</span> <span class=\"pl-s\">\"无上大力杵法\"</span> <span class=\"pl-k\">&#x26;&#x26;</span> <span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span><span class=\"pl-c1\">ZB</span><span class=\"pl-k\">[</span><span class=\"pl-c1\">2</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">==</span> <span class=\"pl-c1\">60</span>)\n{\n  hurt = int(1.5 * hurt);\n}\n</code></pre>\n<p>最佳搭配是打狗棒法配打狗棒，加成 1.8，稍好于胡家刀法配冷月宝刀，次于最佳剑法宝剑组合。</p>\n<p>内功对某些拳掌的加成：</p>\n<pre><code class=\"language-actionscript\">    <span class=\"pl-k\">if</span>(<span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span>Skills<span class=\"pl-k\">[</span><span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span><span class=\"pl-c1\">body</span><span class=\"pl-k\">[</span><span class=\"pl-c1\">96</span><span class=\"pl-k\">]].</span>m_sName <span class=\"pl-k\">==</span> <span class=\"pl-s\">\"冰蚕神掌\"</span> <span class=\"pl-k\">&#x26;&#x26;</span> <span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span><span class=\"pl-c1\">ZB</span><span class=\"pl-k\">[</span><span class=\"pl-c1\">4</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">==</span> <span class=\"pl-c1\">167</span>)\n    {\n      hurt = int(1.5 * hurt);\n    }\n    <span class=\"pl-k\">if</span>(<span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span>Skills<span class=\"pl-k\">[</span><span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span><span class=\"pl-c1\">body</span><span class=\"pl-k\">[</span><span class=\"pl-c1\">96</span><span class=\"pl-k\">]].</span>m_sName <span class=\"pl-k\">==</span> <span class=\"pl-s\">\"黯然销魂掌\"</span> <span class=\"pl-k\">&#x26;&#x26;</span> <span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span><span class=\"pl-c1\">ZB</span><span class=\"pl-k\">[</span><span class=\"pl-c1\">4</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">==</span> <span class=\"pl-c1\">158</span>)\n    {\n      hurt = int(1.6 * hurt);\n    }\n    <span class=\"pl-k\">if</span>(<span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span>Skills<span class=\"pl-k\">[</span><span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span><span class=\"pl-c1\">body</span><span class=\"pl-k\">[</span><span class=\"pl-c1\">96</span><span class=\"pl-k\">]].</span>m_sName <span class=\"pl-k\">==</span> <span class=\"pl-s\">\"般若掌\"</span> <span class=\"pl-k\">&#x26;&#x26;</span> <span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span><span class=\"pl-c1\">ZB</span><span class=\"pl-k\">[</span><span class=\"pl-c1\">4</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">==</span> <span class=\"pl-c1\">162</span>)\n    {\n      hurt = int(1.7 * hurt);\n    }\n    <span class=\"pl-k\">if</span>(<span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span>Skills<span class=\"pl-k\">[</span><span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span><span class=\"pl-c1\">body</span><span class=\"pl-k\">[</span><span class=\"pl-c1\">96</span><span class=\"pl-k\">]].</span>m_sName <span class=\"pl-k\">==</span> <span class=\"pl-s\">\"大力金刚掌\"</span> <span class=\"pl-k\">&#x26;&#x26;</span> <span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span><span class=\"pl-c1\">ZB</span><span class=\"pl-k\">[</span><span class=\"pl-c1\">4</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">==</span> <span class=\"pl-c1\">162</span>)\n    {\n      hurt = int(1.6 * hurt);\n    }\n    <span class=\"pl-k\">if</span>(<span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span>Skills<span class=\"pl-k\">[</span><span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span><span class=\"pl-c1\">body</span><span class=\"pl-k\">[</span><span class=\"pl-c1\">96</span><span class=\"pl-k\">]].</span>m_sName <span class=\"pl-k\">==</span> <span class=\"pl-s\">\"降龙十八掌\"</span> <span class=\"pl-k\">&#x26;&#x26;</span> <span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span><span class=\"pl-c1\">ZB</span><span class=\"pl-k\">[</span><span class=\"pl-c1\">4</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">==</span> <span class=\"pl-c1\">138</span>)\n    {\n      hurt = int(1.9 * hurt);\n    }\n    <span class=\"pl-k\">if</span>(<span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span>Skills<span class=\"pl-k\">[</span><span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span><span class=\"pl-c1\">body</span><span class=\"pl-k\">[</span><span class=\"pl-c1\">96</span><span class=\"pl-k\">]].</span>m_sName <span class=\"pl-k\">==</span> <span class=\"pl-s\">\"落英神剑掌\"</span> <span class=\"pl-k\">&#x26;&#x26;</span> <span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span><span class=\"pl-c1\">ZB</span><span class=\"pl-k\">[</span><span class=\"pl-c1\">4</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">==</span> <span class=\"pl-c1\">164</span>)\n    {\n      hurt = int(1.6 * hurt);\n    }\n    <span class=\"pl-k\">if</span>(<span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span>Skills<span class=\"pl-k\">[</span><span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span><span class=\"pl-c1\">body</span><span class=\"pl-k\">[</span><span class=\"pl-c1\">96</span><span class=\"pl-k\">]].</span>m_sName <span class=\"pl-k\">==</span> <span class=\"pl-s\">\"劈空掌\"</span> <span class=\"pl-k\">&#x26;&#x26;</span> <span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span><span class=\"pl-c1\">ZB</span><span class=\"pl-k\">[</span><span class=\"pl-c1\">4</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">==</span> <span class=\"pl-c1\">164</span>)\n    {\n      hurt = int(1.5 * hurt);\n    }\n    <span class=\"pl-k\">if</span>(<span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span>Skills<span class=\"pl-k\">[</span><span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span><span class=\"pl-c1\">body</span><span class=\"pl-k\">[</span><span class=\"pl-c1\">96</span><span class=\"pl-k\">]].</span>m_sName <span class=\"pl-k\">==</span> <span class=\"pl-s\">\"兰花拂穴手\"</span> <span class=\"pl-k\">&#x26;&#x26;</span> <span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span><span class=\"pl-c1\">ZB</span><span class=\"pl-k\">[</span><span class=\"pl-c1\">4</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">==</span> <span class=\"pl-c1\">164</span>)\n    {\n      hurt = int(1.5 * hurt);\n    }\n    <span class=\"pl-k\">if</span>(<span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span>Skills<span class=\"pl-k\">[</span><span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span><span class=\"pl-c1\">body</span><span class=\"pl-k\">[</span><span class=\"pl-c1\">96</span><span class=\"pl-k\">]].</span>m_sName <span class=\"pl-k\">==</span> <span class=\"pl-s\">\"七伤拳\"</span> <span class=\"pl-k\">&#x26;&#x26;</span> <span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span><span class=\"pl-c1\">ZB</span><span class=\"pl-k\">[</span><span class=\"pl-c1\">4</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">==</span> <span class=\"pl-c1\">138</span>)\n    {\n      hurt = int(1.6 * hurt);\n    }\n    <span class=\"pl-k\">if</span>(<span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span>Skills<span class=\"pl-k\">[</span><span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span><span class=\"pl-c1\">body</span><span class=\"pl-k\">[</span><span class=\"pl-c1\">96</span><span class=\"pl-k\">]].</span>m_sName <span class=\"pl-k\">==</span> <span class=\"pl-s\">\"太极拳\"</span> <span class=\"pl-k\">&#x26;&#x26;</span> <span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span><span class=\"pl-c1\">ZB</span><span class=\"pl-k\">[</span><span class=\"pl-c1\">4</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">==</span> <span class=\"pl-c1\">163</span>)\n    {\n      hurt = int(1.7 * hurt);\n    }\n    <span class=\"pl-k\">if</span>(<span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span>Skills<span class=\"pl-k\">[</span><span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span><span class=\"pl-c1\">body</span><span class=\"pl-k\">[</span><span class=\"pl-c1\">96</span><span class=\"pl-k\">]].</span>m_sName <span class=\"pl-k\">==</span> <span class=\"pl-s\">\"参合指\"</span> <span class=\"pl-k\">&#x26;&#x26;</span> <span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span><span class=\"pl-c1\">ZB</span><span class=\"pl-k\">[</span><span class=\"pl-c1\">4</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">==</span> <span class=\"pl-c1\">169</span>)\n    {\n      hurt = int(1.6 * hurt);\n    }\n    <span class=\"pl-k\">if</span>(<span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span>Skills<span class=\"pl-k\">[</span><span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span><span class=\"pl-c1\">body</span><span class=\"pl-k\">[</span><span class=\"pl-c1\">96</span><span class=\"pl-k\">]].</span>m_sName <span class=\"pl-k\">==</span> <span class=\"pl-s\">\"九阴白骨爪\"</span> <span class=\"pl-k\">&#x26;&#x26;</span> <span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span><span class=\"pl-c1\">ZB</span><span class=\"pl-k\">[</span><span class=\"pl-c1\">4</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">==</span> <span class=\"pl-c1\">158</span>)\n    {\n      hurt = int(1.6 * hurt);\n    }\n    <span class=\"pl-k\">if</span>(<span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span>Skills<span class=\"pl-k\">[</span><span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span><span class=\"pl-c1\">body</span><span class=\"pl-k\">[</span><span class=\"pl-c1\">96</span><span class=\"pl-k\">]].</span>m_sName <span class=\"pl-k\">==</span> <span class=\"pl-s\">\"六脉神剑\"</span> <span class=\"pl-k\">&#x26;&#x26;</span> <span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span><span class=\"pl-c1\">ZB</span><span class=\"pl-k\">[</span><span class=\"pl-c1\">4</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">==</span> <span class=\"pl-c1\">167</span>)\n    {\n      hurt = int(1.9 * hurt);\n    }\n    <span class=\"pl-k\">if</span>(<span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span>Skills<span class=\"pl-k\">[</span><span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span><span class=\"pl-c1\">body</span><span class=\"pl-k\">[</span><span class=\"pl-c1\">96</span><span class=\"pl-k\">]].</span>m_sName <span class=\"pl-k\">==</span> <span class=\"pl-s\">\"一阳指\"</span> <span class=\"pl-k\">&#x26;&#x26;</span> <span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span><span class=\"pl-c1\">ZB</span><span class=\"pl-k\">[</span><span class=\"pl-c1\">4</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">==</span> <span class=\"pl-c1\">166</span>)\n    {\n      hurt = int(1.6 * hurt);\n    }\n</code></pre>\n<p>可以看到降龙配九阳、六脉配易筋经加成最大。</p>\n<p>然后小无相功对所有拳掌都有一定加成，如果你的拳掌不属于上面，那么小无相功最佳：</p>\n<pre><code class=\"language-actionscript\">    <span class=\"pl-k\">if</span>(<span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span><span class=\"pl-c1\">ZB</span><span class=\"pl-k\">[</span><span class=\"pl-c1\">4</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">==</span> <span class=\"pl-c1\">148</span>)\n    {\n      hurt = int(1.4 * hurt);\n    }\n</code></pre>\n<p>特别地，左右互搏有 1.7-2.2 随机伤害加成：</p>\n<pre><code class=\"language-actionscript\"><span class=\"pl-k\">if</span>(<span class=\"pl-c1\">_root</span><span class=\"pl-k\">.</span><span class=\"pl-c1\">ZB</span><span class=\"pl-k\">[</span><span class=\"pl-c1\">4</span><span class=\"pl-k\">]</span> <span class=\"pl-k\">==</span> <span class=\"pl-c1\">190</span>)\n{\n  hurt = int((1.6 + 0.1 * random(6)) * hurt);\n}\n</code></pre>\n<h3>NPC</h3>\n<p>所有 NPC 均可修改为队友。\n游戏中不可加为队友的 NPC 修改为队友后战斗时无人物图像。</p>\n<pre><code>  1 王语嫣\n  2 令狐冲\n  3 仪琳\n  4 张无忌\n  5 胡斐\n  6 小龙女\n  7 杨过\n  8 公孙绿萼\n  9 段誉\n  10 狄云\n  11 小乞丐\n  12 黄蓉\n  13 韦小宝\n  14 双儿\n  15 赵敏\n  16 任盈盈\n　　17 向问天\n　　18 周芷若\n　　19 阿紫\n　　20 阿珂\n　　21 长平\n　　22 阿九\n　　23 九难\n　　24 岳灵珊\n　　25 香香公主\n　　26 苏荃\n　　27 袁承志\n　　28 蛛儿\n　　29 游坦之\n　　30 慕容复\n　　31 林平之\n　　32 田伯光\n　　33 欧阳克\n　　34 霍都\n　　35 虚竹\n　　36 乔峰\n　　37 郭靖\n　　38 神仙醋\n　　39 郭襄\n　　40 程灵素\n　　41 摘星子\n　　42 苗若兰\n　　43 阿大\n　　44 阿二\n　　45 白猿\n　　46 老虎\n　　47 莽牯朱蛤\n　　48 巨蟒\n　　49 茅十八\n　　50 胖头陀\n　　51 胖捕头\n　　52 鸠摩智\n　　53 游驹\n　　54 耕夫\n　　55 读书人\n　　56 梁子翁\n　　57 鳌拜\n　　58 冯锡范\n　　59 陈近南\n　　60 段正淳\n　　61 灭绝师太\n　　62 王夫人\n　　63 李捕头\n　　64 刑捕头\n　　65 多隆\n　　66 秀才\n　　67 教书先生\n　　68 完颜洪烈\n　　69 成吉思汗\n　　70 吴三桂\n　　71 崇祯\n　　72 鲜于通\n　　73 裘千尺\n　　74 裘千丈\n　　75 穆人清\n　　76 鹤笔翁\n　　77 鹿杖客\n　　78 白自在\n　　79 阿秀\n　　80 康熙\n　　81 金轮法王\n　　82 欧阳锋\n　　83 黄药师\n　　84 洪七公\n　　85 一灯\n　　86 周伯通\n　　87 裘千仞\n　　88 瑛姑\n　　89 梅超风\n　　90 傻姑\n　　91 慧轮\n　　92 黄眉僧\n　　93 枯荣大师\n　　94 无名僧\n　　95 圆真\n　　96 不戒和尚\n　　97 单正\n　　98 谭公\n　　99 谭婆\n　　100 何太冲\n　　101 平一指\n　　102 何红药\n　　103 绿竹翁\n　　104 段延庆\n　　105 叶二娘\n　　106 岳老三\n　　107 云中鹤\n　　108 斑淑娴\n　　109 丁敏君\n　　110 澄观\n　　111 风清扬\n　　112 宁中则\n　　113 无涯子\n　　114 李秋水\n　　115 天山童姥\n　　116 丁春秋\n　　117 苏星河\n　　118 薛慕华\n　　119 唐文亮\n　　120 阿三\n　　121 达尔巴\n　　122 陆乘风\n　　123 洪安通\n　　124 康亲王\n　　125 吴应熊\n　　126 海大富\n　　127 索额图\n　　128 太后\n　　129 玉玑子\n　　130 穆念慈\n　　131 成不忧\n　　132 梦姑\n　　133 郭芙\n　　134 阿朱\n　　135 李莫愁\n　　136 钟灵\n　　137 渔夫\n　　138 樵夫\n　　139 陆天抒\n　　140 花铁干\n　　141 水岱\n　　142 刘乘风\n　　143 血刀老祖\n　　144 侠客岛主\n　　145 张三\n　　146 李四\n　　147 黄裳\n　　148 黄真\n　　149 杨逍\n　　150 范遥\n　　151 韦一笑\n　　152 谢逊\n　　153 金花婆婆\n　　154 殷天正\n　　155 胡青牛\n　　156 苗人凤\n　　157 田归农\n　　158 公孙止\n　　159 张三丰\n　　160 宋远桥\n　　161 俞莲舟\n　　162 俞岱岩\n　　163 殷梨亭\n　　164 宋青书\n　　165 王重阳\n　　166 丘处机\n　　167 赵志敬\n　　168 尹志平\n　　169 掌钵长老\n　　170 持棒长老\n　　171 传功长老\n　　172 执法长老\n　　173 全冠清\n　　174 马夫人\n　　175 玄慈\n　　176 空闻\n　　177 方证\n　　178 阎基\n　　179 东方不败（假）\n　　180 东方不败\n　　181 任我行（无属性）\n　　182 任我行\n　　183 杨莲亭\n　　184 曲阳\n　　185 黄钟公\n　　186 黑白子\n　　187 秃笔翁\n　　188 丹青生\n　　189 左冷禅\n　　190 莫大\n　　191 岳不群\n　　192 天门\n　　193 定逸\n　　194 刘正风\n　　195 余沧海\n　　196 费彬\n　　197 冯墨风\n　　198 周芷若\n　　199 杨过\n　　200 南海神尼\n　　201 建宁公主\n　　202 谢烟客\n　　203 神雕\n　　204 ？？？\n　　205 蒙面人\n　　206 缘根\n　　207 老头子\n　　208 祖千秋\n　　209 达摩\n　　210 独孤求败\n　　211 渡劫\n　　212 渡厄\n　　213 渡难\n　　214 鹿清笃\n　　215 流云使\n　　216 妙风使\n　　217 辉月使\n　　218 木高峰\n　　219 史婆婆\n　　220 段天德\n　　221 冰蚕\n　　222 熊\n　　223 半瓶神仙醋\n　　224 木人\n　　225 铜人\n　　226 太监\n　　227 清兵\n　　228 家丁\n　　229 强盗\n　　230 劫匪\n　　231 铁掌帮众\n　　232 嵩山弟子\n　　233 华山弟子\n　　234 恒山弟子\n　　235 泰山弟子\n　　236 衡山弟子\n　　237 丐帮弟子\n　　238 日月教众\n　　239 少林弟子\n　　240 星宿弟子\n　　241 明教弟子\n　　242 老鸨\n  247 张小肉\n</code></pre>\n<p>列表 <code>z[NPC代号]</code> 储存了 NPC 的数值，例如 <code>z[6]</code> 为小龙女。</p>\n<p>NPC 数值列表如下：</p>\n<pre><code>0 当前生命 （ NPC 的生命、内力可以大于 99999）\n1 生命\n2 当前内力\n3 内力\n4 拆招 （ NPC 的属性可以大于 100，改成 900 以后所有敌人皆是一招灭之）\n5 搏击\n6 闪躲\n7 内功\n8 攻击\n9 速度\n10 武功1\n11 武功1经验\n12 武功2\n13 武功2经验\n14 武功3\n15 武功3经验\n16 馈赠物品1\n17 是否获赠物品1\n18 馈赠物品2\n19 是否获赠物品2\n20 馈赠物品3\n21 是否获赠物品3\n22 馈赠物品4\n23 是否获赠物品4\n24 好感度\n25 bool 效果未知\n26 bool 效果未知\n</code></pre>\n<h3>公告任务</h3>\n<pre><code>1.四十二章经的秘密\n2.闯王宝藏的秘密\n3.唐选诗集的秘密\n4.落花流水恶斗血刀僧\n5.华山论剑\n6.救治青翼蝠王\n7.归云庄英雄大会\n8.王语嫣的悲哀\n9.放浪形骸的浪子\n10.绝情谷婚变\n11.悲情杨过\n12.独孤求败的宠物\n13.昔日皇妃\n14.韦小宝性命危矣\n15.庄家的复仇\n16.魔教圣姑\n17.死守襄阳\n18.神雕大侠的三件礼物\n19.四个淫棍\n20.田归农的挑战\n21.回族部落的圣物\n22.群寇争镖银\n23.老尼姑的险境\n24.峨嵋派替天行道\n25.西夏招亲\n26.救治盲女\n27.青城派的仇怨\n28.东郭浪子心\n29.全真派和桃花岛的恩怨\n30.桃花岛主,怡笑江湖\n31.昆仑冰蚕\n32.毒王之争\n33.天王老子傲四方\n34.御厨的无奈\n35.腊八粥\n36.迷途中的小和尚\n37.擂鼓山棋局\n38.镖车被劫\n39.月下白骨\n40.阮姓无辜做冤魂\n41.丐帮和星宿的恶斗\n42-43.少林和武当的恶斗\n44.官逼民反\n45.神秘商人\n</code></pre>\n<p>列表 <code>sj</code> 储存事件完成情况，列表 <code>c</code> 储存条件触发情况。</p>\n<p>江湖记事的时间储存在列表 <code>k</code> 中，对应的记事储存在列表 <code>l</code> 中。</p>\n<h2>修改攻略</h2>\n<p>属性、问题随便，反正要修改。</p>\n<p>参见前述回到开始加入多个门派。</p>\n<h3>古墓</h3>\n<h4>入全真并叛出</h4>\n<p>第一天午时至酉时（千万别睡觉），回村遇官差调戏女子事件，选1，上前阻挡被秒杀。</p>\n<p>丘处机出现，醒来后马上去树林找他，选择加入全真派。</p>\n<p>全真教的选择题：前几个题全不选师傅（赵志敬），最后一个最下流无耻的选师傅（赵志敬）。</p>\n<p>休息，得到存档。进行修改，金钱改 999999，修为点改 999，闪、轻、内、搏、拆改 99， 其余属性改 100。</p>\n<p>内功改玉女，轻功改凌波，剑法改全真、玉女、玉女素心、独孤。掷针、天罗、美女、捕雀可直接修改，或在古墓中学。</p>\n<p>经脉可直接修改，或在游戏中点。</p>\n<p>如想学全真功夫，可找甄志丙学金雁功。学了全真剑法或三花聚顶掌，比武输了也去不了古墓。</p>\n<p>读档，到大殿找丘处机不断养生，直至 3 月比武，逃跑。</p>\n<h4>最快叛出全真</h4>\n<p>在游戏开始5天内，牛家村场景下，修改 <code>m[128]</code> 为 <code>150</code>，跳至加入全真事件。\n在全真派中，修改 <code>m[128]</code> 为 <code>108</code>，直接跳到叛出门派事件，触发入古墓事件。</p>\n<h4>拜入古墓</h4>\n<p>受辱骂后离开，古墓门口被玉峰蛰，醒来后回答选 1 （死了算了），拜入古墓。</p>\n<h4>传功</h4>\n<p>古墓中请小龙女传功，先学天罗地网掌，\n和小龙女切磋到 9 级（武功等级亦可修改存档，下同）再可学捕雀功，用修为点练至 5 级装备，\n让小龙女传功可得玉蜂针，学得掷针术。\n装备玉峰针后和用掷针术和小龙女切磋至 7 级可学美女拳法。</p>\n<p>掷针术、捕雀功均为游戏原创。\n掷针术可发射任意暗器。《神雕侠侣》中未提及掷针术，玉蜂针和冰魄银针皆有专门的手法，\n并非通用暗器手法。即便如周伯通这样的高手，因为不明手法，发射的玉蜂针威力全无。</p>\n<p>寡欲修到顶之后存档，修改为 1 级，然后再修。修过一定次数后，只需修寡欲 5 天即可从 1 级修到 10 级。\n不过生命内力可直接修改，因此这样没什么意义。</p>\n<h4>出古墓</h4>\n<p>修习寡欲至离十二月十五日最近的日期。\n十二月十五日，李莫愁会来，无论输赢小龙女都会说我们打不过师姐，然后放下断龙石，\n选择死要死在一起，二人进入密道。\n先得到九阴真经和玉女真经，然后会有字幕提示出古墓的走法：</p>\n<p>第1种提示，西 东 南 北 东 西，最后东或西，\n第2种提示，东 东 西 北 东 西，最后东或北，\n第2种提示，南 北 南 北 东 西，最后南或北。</p>\n<p>成功出古墓，小龙女为队友；走入死胡同则死亡。</p>\n<p>或者修改 <code>m[128]</code> 为 <code>340</code>，直接出古墓。</p>\n<h3>小龙女修改</h3>\n<p>修改小龙女数值，生命内力 999，属性 900，武功分别为驱蜂术（群攻）、玉女素心、美女拳法，武功经验为 999.\n三种物品（玉蜂浆、淑女剑、玉女心经）获赠改为 <code>true</code>. 好感改为 100.、</p>\n<p>如此修改后，任何敌人都是一招灭之。</p>\n<h3>全真</h3>\n<p>参见古墓。</p>\n<p>不同：</p>\n<ol>\n<li>回答问题时讨好赵志敬可得木剑、全真剑法。</li>\n<li>同古墓回答问题，找赵志敬切磋，连胜 10 次，得木剑、全真剑法，全真练到 9 级，找赵志敬得三花聚顶掌。</li>\n<li>6月比武得重阳神掌。</li>\n<li>9月比武得先天功。</li>\n</ol>\n<h3>少林</h3>\n<p>休息 2 次后到 1 年 1 月 2 日，牛家村中看到和尚，拜入少林。</p>\n<p>或修改 <code>m[139]</code> 为 <code>初入少林</code>，<code>m[140]</code> 为 <code>少林派</code>.</p>\n<p>藏经阁学佛法至 2 级，找慧伦学少林身法。</p>\n<p>找慧伦学长拳，长拳 7 级学罗汉拳，罗汉拳 7 级学般若拳。</p>\n<p>挑战罗汉堂首座得少林九阳功。</p>\n<p>至藏经阁学佛法至 3 月，挑战木人巷，得一苇渡江。</p>\n<h4>达摩堂</h4>\n<p>选择达摩堂。</p>\n<p>入堂得大力金刚掌。</p>\n<p>大力金刚掌 9 级，得大力金刚指。</p>\n<p>已学大力金刚指，修佛法到 5 级，得须弥山掌；修佛法 9 级，得拈花指。</p>\n<p>挑战达摩堂首座得如来千叶手。</p>\n<p>与空闻首次切磋胜利后得龙爪手，连续切磋胜利 10 次后得无相劫指。</p>\n<h4>般若堂</h4>\n<p>参见前述回到开始，重入少林。修佛法至 3、6、9 月，挑战木人巷。</p>\n<p>入堂得大还丹、纯钢剑、柳叶刀、回风拂柳剑秘籍、飞镖。</p>\n<p>从澄观处得漫天花雨、狂风刀法、分筋错骨手、劈空掌。</p>\n<p>挑战般若堂首座得金钢不坏神功。</p>\n<h4>南少林</h4>\n<p>参见前述回到开始，重入少林。修佛法至 3、6、9 月，挑战木人巷。</p>\n<p>入门得龙泉剑、天竺弯刀、蟠龙棍。</p>\n<p>从方证处得修罗刀法、达摩剑法、燃木刀法、韦佗杖法。</p>\n<h4>铜人阵</h4>\n<p>12 月挑战铜人阵，得易筋经。</p>\n<h3>武当</h3>\n<p>时间改到 1 年 1 月 3 日 1 时，进程改为<code>序幕2</code>，地点改为<code>酒 店</code>.</p>\n<p>去破庙，遇到强盗分赃，教训强盗。</p>\n<p>回酒店休息 2-3 次至 4 日，然后卸去加闪避的轻功，使闪避回落至 99，并与小龙女切磋，败北，血剩 1.\n然后出酒店正赶上强盗来报复，单挑强盗，败北（必须打输，否则俞岱岩不会出现，失去入武当的机会）。\n俞岱岩出面，加入武当。</p>\n<p>或者修改 <code>m[128]</code> 为 <code>225</code>，跳至加入武当事件。</p>\n<p>入门得武当长拳、梯云纵。</p>\n<p>武当长拳 8 级找俞岱岩学震山铁掌。</p>\n<p>侠义 6 级找俞岱岩学绵掌。（大殿加侠义，或直接修改。）</p>\n<p>基本剑法 7 级找殷梨亭学绕指柔剑。</p>\n<p>学绕指柔剑后杀死10个恶霸找殷梨亭学神门十三剑。</p>\n<p>绕指柔剑、神门十三剑均 10 级找殷梨亭学玄虚刀法。</p>\n<p>丹房帮忙十几次可得虎爪绝户手。丹房试药可刷生命、内力，或直接修改。</p>\n<p>侠义值 82 以上可得称号“武当八侠”。侠义值够高，宋远桥送武当九阳功。</p>\n<p>侠义值 70 去闭关室找张三丰闭关15天4次后，选“请太师傅传武当绝学”得纯阳无极功。\n再闭关 3-4 次，选“请太师傅传武当绝学”得太极劲。</p>\n<p>年底下山后，侠义值 100，回武当，单挑掌门，得太极拳。\n再次单挑掌门，得太极剑、真武剑。\n若已入其他门派，可修改门派为武当后回武当。</p>\n<h3>华山</h3>\n<h4>拜入华山</h4>\n<p>将时间修改为 1 年 1 月 4 日 7 时 1 刻， 进程为 <code>序幕2</code>，地点为 <code>酒 店</code>.</p>\n<p>去破庙，遇到木高峰，选择救人，然后选择冒充华山弟子。接着令狐冲出现，引荐你加入华山派。</p>\n<p>或者修改 <code>m[128]</code> 为 <code>250</code>，跳至加入华山事件。</p>\n<h4>基础</h4>\n<p>入门得华山长拳。</p>\n<p>至大殿儒风 3 级，华山长拳 8 级，找令狐冲得华山轻功、华山剑法。</p>\n<p>华山剑法 8 级，找令狐冲得太岳三青峰。</p>\n<p>儒风 5 级后找岳不群得华山心法。</p>\n<h4>思过崖</h4>\n<p>厨房，在令狐冲没进思过崖的时候，给师娘足够的食材（常要的有鲤鱼、草鱼、螃蟹、兔肉、鹿肉、野猪肉）及木柴后，\n可以学到宁氏一剑。还可得大概 25 种食物。\n在令狐冲进思过崖（三、六、九月）时，每次给她东西可得 2 瓶烧刀子。\n去思过崖给令狐冲 3 次（6 瓶）烧刀子后，可进思过崖密道。</p>\n<p>思过崖密道岔路三选一，出来后密道坍塌：</p>\n<ol>\n<li>夺命连环三仙剑、万花剑法、五大夫剑、百变千幻云雾剑法、快慢十七路</li>\n<li>金蛇秘笈、金蛇剑、金蛇锥 （可以给袁承志）</li>\n<li>魔教兵器四件：白龙剑、黑血神针、穿云刀、黄金杵（与剧情无关）</li>\n</ol>\n<p>尽管武功和物品都可修改，建议用 SL 刷 1，\n因为这 5 种剑法练到 9 级后和在思过崖的令狐冲切磋，切磋完后不论输赢都可习得五岳剑法，算有点剧情。\n修改 <code>m[128]</code> 为 <code>240</code>，直接学会五岳剑法，不用刷 5 种剑法。</p>\n<p>或者直接修改 <code>m[128]</code> 为 <code>175</code>，不用等三、六、九月，不用给烧刀子，且可以重复入山洞。</p>\n<h4>剑宗</h4>\n<p>后山木屋找穆人清，改拜其为师（前提是儒风未顶级），得狂风快剑。</p>\n<p>从穆人清处亦可得夺命连环三仙剑（得诸思过崖）、漫天花雨（得诸少林寺般若堂）。</p>\n<p>漫天花雨 9 级找穆人清得神行百变。</p>\n<p>神行百变 5 级后第二天在后山木屋遇见风清扬。如未学紫霞，可选自己或令狐冲学习独孤。否则一无所获。</p>\n<p>可以修改 <code>m[128]</code> 为 <code>301</code>，直接得独孤九剑，不用拜穆人清，不用未学紫霞。</p>\n<h4>紫霞秘籍</h4>\n<p>儒风顶级，未学剑宗武功可得。拜入剑宗之后可以通过征服华山派获得。</p>\n<h4>下山</h4>\n<p>然后就是不断儒风 15 日至年末。下山后林平之跟随。\n至林家老宅得辟邪剑谱，灭日月神教得葵花宝典，\n先切磋提升属性后再赠送。</p>\n<h3>聚贤居</h3>\n<p>队友：小龙女、林平之。</p>\n<p>将门派修改为古墓派，师承改为小龙女。（古墓派无法灭，嘻嘻。）</p>\n<p>窍门：装备的武器馈赠给队友，队友得到馈赠，而武器仍在自己手里，研习的武功同理。</p>\n<p>切磋林平之，提升其属性。</p>\n<p>改等级到 30 级以下，废除小龙女武功（三项武功代码改为 0，否则一招灭敌太快了，逃跑都来不及），\n输给半瓶醋得秘籍：松风剑法、奇门三才刀、太祖棍、五罗轻烟掌、锁喉擒拿手、飞檐走壁、叫花内功；\n改等级到 30 级以上，输给半瓶醋得秘籍：越女剑法、伏魔杖法、化骨绵掌、凝血神爪、北斗仙踪、紫薇心法。</p>\n<h3>每月事件</h3>\n<p>【救治青翼蝠王】神秘商人处买棉衣，或直接修改，装备棉衣，战莽牯朱蛤，胜后韦一笑教寒冰绵掌。</p>\n<p>趁现在队伍有两个空位，先拿闯王宝藏图：找胡斐打胜他，带他去药王庄，程灵素加入。\n顺便去阎基居，打胜得胡家刀法，自己先学再送给胡斐。\n去苗人凤家选择帮苗人凤，打胜何红药并且侠义够高即可得到闯王宝藏图和苗家剑法。</p>\n<p>【救治盲女】医术80以上，先到南方【树林】加入游坦之，给阿紫治眼会牺牲游坦之，打败丁春秋换到【神木王鼎】【腐尸毒】【解毒术】。</p>\n<p>【放荡形骸的浪子】由于拜入武当，牛家村已灭，无法买酒，只能直接修改：葡萄酒，梨花酒，百草美酒，高粱酒。跟令狐冲聊天后，队伍有空位，令狐冲加入队伍。</p>\n<p>【悲情杨过】给断肠草。事先踢掉最弱的阿紫，杨过加入队伍。</p>\n<p>【四个淫棍】目前队伍中有小龙女、林平之、令狐冲、杨过，可以避免淫棍加入，可得武功。\n田伯光的狂风刀法已经从少林学到，欧阳克的蛤蟆功不如霍都的龙象般若功强，因此帮霍都。</p>\n<p>【天王老子傲四方】选帮助向问天，队伍满，向问天不得加入。做完此任务后可去梅庄，打败任我行可习狮吼功、吸星大法。</p>\n<p>【桃花岛主，贻笑江湖】 选择帮李莫愁胜利后获得五毒秘传，选择帮助黄药师胜利后习得玉箫剑法和弹指神通。</p>\n<p>【四十二章经的秘密】去京城杀段天德，饶过完颜洪烈，得刀、棍。\n反复去京城，搜集到 6 本四十二章经。\n踢杨过（目前最弱）去渡口，至神龙教，征服，得 1 本四十二章经，另苏荃加入队伍。\n从神秘商人处得到夜行衣。穿夜行衣至少林寺，乔装混入藏经阁，寻找四十二章经。\n藏经阁需碰运气，不一定找得到，且三楼有可能碰到扫地、张小肉没收。如无耐心可直接修改（镶蓝旗）。\n收集齐全四十二章经后，进入，得银100万。</p>\n<p>此时林平之切磋得差不多了，给他辟邪。灭日月神教，得葵花，给林平之。至此林平之长成，全属性过百。</p>\n<p>【死守襄阳城】与金轮法王对决，队伍满员，郭靖不加入。</p>\n<p>【东郭狼子心】打败何太冲，福缘>80，获得《九阳真经》和蟠桃。</p>\n<p>【迷途小和尚】虽然现在是古墓派，到底在少林和虚竹呆过，虚竹马上认出我是师弟。我告知去少林的路，获赠\n某药丸 10 枚。</p>\n<p>【韦小宝性命危矣】队伍满员，避免其加入，得银500两。</p>\n<p>【回族部落的圣物】得《可兰经》，队伍满员，香香公主不加入。</p>\n<p>【魔教圣姑】完成天王老子傲四方和梅庄任务，踢掉最弱的苏荃，任盈盈加入。</p>\n<p>【落花流水斗血刀僧】由于只有狄云加入队伍才能得《神照经》，所以踢掉任盈盈。帮落花流水，选不杀狄云，\n狄云加入，并得到《神照经》和《唐诗选辑》。\n狄云是吃货，正好拿华山宁中则做的菜宴请他，不断宴请加好感，最高加到 100.</p>\n<p>【西夏招亲】打败鸠摩智，得火焰刀。</p>\n<p>【王语嫣的悲哀】踢掉最弱的狄云打慕容复，胜利后王语嫣加入。\n王语嫣极弱，赠女装后好一点。</p>\n<p>【闯王宝藏的秘密】如前所述，已拿【闯王宝藏图】，得到倚天剑，屠龙刀，打狗棒，霹雳雷火弹10颗。</p>\n<p>【唐诗选辑的秘密】得到唐诗选辑，做完任务就得到5000两。</p>\n<p>【庄家的复仇】找四十二章经时曾在京城杀掉鳌拜，故可得庄家回报。队伍满员，避免双儿加入，得十八泥偶，可\n研习罗汉伏魔功。</p>\n<p>【良辰吉日】：选择一位女性队员做老婆。该名队员属性会暴涨。</p>\n<p>【擂鼓山棋局】段延庆自杀时静观其变，让虚竹阻止并成为掌门，自己则避免所有内功被洗。</p>\n<p>【田归农的挑战】踢掉最弱的王语嫣，找胡斐，赢后可得冷月宝刀。</p>\n<p>【群寇争镖银】选择帮阿九姑娘，胜出队伍有空位阿九加入，否则得3000两。选择帮田归农，得随机银两。两个一起打，得到一大笔随机银两。</p>\n<p>【神雕侠的三件礼物】踢掉胡斐，选择归还打狗棒，因为闯王宝藏里已经拿了 1 根了，没必要贪这根。郭襄加入。\n神秘商人处购买峨眉九阳功，赠郭襄。然后女装赠郭襄。馈赠完毕，属性勉强能看了。</p>\n<p>【昔日的皇妃】悟性>50且侠义>70得九阴真经，否则习得空明拳；悟性&#x3C;50学到左右互搏。\n我喜欢空明拳，故事先修改侠义为 0.</p>\n<p>【绝情谷婚宴】周伯通走时，选一，先得到3个生生造化丸，战斗赢后得到公孙绿萼（队伍有空位加入，无空位送君子剑和淑女剑）选二，得断魂草。建议选一，因为小龙女会要淑女剑。断肠草可以在神秘商人处购买，且此任务可反复做。</p>\n<p>【全真派与桃花岛的恩怨】黄药师传落英神剑掌和兰花拂穴手再给5个九花玉露丸。</p>\n<p>【老尼姑的险境】得天山掌法，小心侠义别超过 80，否则会成为恒山掌门。这个掌门是个空头衔，一样可以征服恒山。</p>\n<p>【腊八粥】由于悟性大于 50，太玄功没得学（可以直接修改）。需确保侠义值非正，否则连架也没得打。</p>\n<p>然后再把侠义改成大于 30，队伍满员，去无量山洞，得凌波微步。</p>\n<p>到塞外找萧峰，确保侠义大于 80，第一次获胜得降龙，第二次得打狗，\n第三次萧峰加入队伍（需事先踢一人，例如最弱的郭襄，不过我没踢，\n让萧峰塞外隐居吧）。</p>\n<p>征服各门派可得一大堆武功。</p>\n<h3>华山之巅</h3>\n<h4>玩家</h4>\n<pre><code>侠义 &#x3C;= 0\n生命内力：原始值为 99999。\n属性原始值：内、搏、拆、闪、轻为 99，其他 100.\n五属性加内功、轻功数值： 99x.\n内功：玉女心经\n轻功：凌波微步\n装备：倚天加软猬甲（衣服随意，例如女装，暗器随意）\n招式：辟邪剑法、八荒六合唯我独尊、神照、天罗地网势、美女拳法、玉女剑法、玉女素心剑法、玉女心经\n</code></pre>\n<p>未装备快捷的古墓派武功：</p>\n<ul>\n<li>捕雀功，只加轻不加闪，且为游戏杜撰，悖于原著（参见古墓部分）</li>\n<li>掷针术为游戏杜撰，悖于原著（参见古墓部分）</li>\n<li>驱蜂术（仅为 NPC 可用，玩家使用威力为 0）</li>\n</ul>\n<p>使用神照不用龟息是因为龟息加别人不如神照一下复活。玩家自身血超过 99999 无需加血，若秒杀而死根本来不及加血。</p>\n<p>八荒弱于倚天加独孤，不过内、搏刷到 99x 后没有差别，均为极大溢出，八荒的画面效果要美得多。</p>\n<h4>队友</h4>\n<ol>\n<li>小龙女：由于属性过高，因此保持武功全废，否则一下就打玩了。</li>\n<li>林平之：血少了点，不过也撑到达摩手下才死，也算够了。</li>\n<li>令狐冲：华山学独孤，酒、紫薇软剑已送。</li>\n<li>东方不败：修改器改出来的，画面中没有形体，孤零零的速度条，更像鬼魅了。</li>\n</ol>\n<p>玩家不出手，小龙女无法出手，就靠三个队友出手绰绰有余。</p>\n<h2>TODO</h2>\n<p>砍树至午时，回村，与官差争执，醒后至树林找丘处机入全真。</p>\n<p>回答问题不要讨好赵志敬，得全真心法。大殿找丘处机养生至 3 月。比武逃跑，判处全真。</p>\n<p>以死相逼入古墓。找小龙女学天罗地网势。</p>\n<p>修改 <code>m[139]</code> 为 <code>初入武当</code>，<code>m[140]</code> 为 <code>武当派</code>.得武当长拳。</p>\n<p>武当长拳 8 级，找俞岱岩学震山铁掌。已学震山铁掌，侠义 6 级找俞岱岩学绵掌。（大殿加侠义）</p>\n<p>学绕指柔剑后，至大殿累计打败 10 个恶人，找殷梨亭学神门十三剑。</p>\n<p>修改 <code>m[139]</code> 为 <code>初入华山</code>，<code>m[140]</code> 为 <code>华山派</code>。多和林平之切磋，掷针术升到 7 级。</p>\n<p>修改 <code>m[128]</code>，反复进秘洞，直到得万花剑法、百变千幻云雾剑法等，并得金蛇剑法、金蛇剑。</p>\n<p>修改 <code>m[128]</code> 为 <code>301</code>，得独孤九剑。</p>\n<p>修改 <code>m[128]</code> 为 <code>230</code>，<code>m[139]</code> 为 <code>初入全真</code>，<code>m[140]</code> 为 <code>古 墓</code>.找小龙女学美女拳法。</p>\n<p>修改 <code>m[139]</code> 为 <code>初入少林</code>，<code>m[140]</code> 为 <code>少林派</code>. 门派技能改为 <code>佛法</code>.</p>\n<p>至 3、6、9月过木人巷，选达摩堂。修佛法 9 级，大力金刚掌 9 级，得大力金刚指、须弥山掌，得拈花指。</p>\n<h2>参考</h2>\n<ul>\n<li><a href=\"http://tieba.baidu.com/p/541670293\">1.08版《金庸群侠传3》豪华官方全攻略</a></li>\n<li><a href=\"http://blog.sina.com.cn/s/blog_400954050101iqt4.html\">金庸群侠传3（加强版）大揭秘</a></li>\n<li><a href=\"http://tieba.baidu.com/p/781354346\">个人整理的金群3加强版作弊攻略</a></li>\n<li><a href=\"http://tieba.baidu.com/p/697519351\">金三完整资料攻略</a></li>\n<li><a href=\"http://tieba.baidu.com/f?kz=584635176\">金三武功鹿死谁手</a></li>\n</ul>","date_published":"Thu, 24 Aug 2017 13:06:40 GMT","date_modified":"Sat, 26 Jul 2025 05:29:46 GMT"},{"id":"https://mmap.page/dapi/jyqxz2-cheat/","url":"https://mmap.page/dapi/jyqxz2-cheat/","title":"金庸群侠传 2 加强版作弊教程","content_html":"<h1>金庸群侠传 2 加强版作弊教程</h1>\n<p>Windows 存档目录为</p>\n<pre><code>C:\\Documents and Settings\\用户名\\Application Data\\Macromedia\\Flash Player\\\n#SharedObjects\\随机字母数字\\游戏网址目录\\随机字母数字\\\n</code></pre>\n<p>Linux:</p>\n<pre><code>~/.config/google-chrome/Default/Pepper Data/Shockwave Flash/\nWritableRoot/#SharedObjects/随机字母数字/游戏网址目录/随机字母数字/\n</code></pre>\n<p>存档文件为 <code>gamezly.sol</code> （存档一）、<code>gamelzy</code> （存档二）、<code>gameylz</code> （存档三）。</p>\n<p>存档后需要退出游戏，否则存档文件不会更新。</p>\n<h2>基本属性</h2>\n<p>变量命名比金庸群侠传 3 有规律多了，基本是拼音首字母。</p>\n<p>| 变量 | 含义 | 备注 |\n| name_1 | 姓 ||\n| name_2 | 名 ||\n| LV | 等级 ||\n| JYZ | 经验值 |\n| S_M | 生命 | 最大值 9999 |\n| S_M0 | 当前生命 | 最大值 9999 |\n| N_L | 内力 | 最大值 9999 |\n| N_L0 | 当前内力 | 最大值 9999 |\n| F_Y | 福缘 | 最大值 100 |\n| S_W | 声望 | 最大值 999 |\n| W_X | 悟性 | 最大值 100 |\n| L_D、L_D0 | 力道 | 最大值 300，研习易筋经、九阴真经、九阳真经、葵花宝典等后 <code>L_D</code> 最大 500 |\n| H_T、H_T0 | 护体 | 最大值 300，研习易筋经、九阴真经、九阳真经、葵花宝典等后 <code>H_T</code> 最大 500 |\n| S_F | 身法 | 最大值 100 |\n| Q_Z | 拳掌 | 最大值 100 |\n| Y_J | 御剑 | 最大值 100 |\n| A_Q | 暗器 | 最大值 100 |\n| Y_L | 医疗 | 最大值 100 |\n| Y_D | 用毒 | 最大值 100 |\n| J_D | 解毒 | 最大值 100 |\n| X_Y | 侠义 | 小于 50 为恶，最大值 100 |\n| Y_Z | 银两 | 最大值 9999 |\n| XXD | 学习点 | 最大值 999 |\n| Menpai | 门派 | 初始为「无门派」 |\n| Chenhao | 称号 ||</p>\n<h2>武功</h2>\n<p><code>lv_</code> 开头的变量记录武功等级，<code>exp_</code> 开头的变量记录武功经验。\n<code>lv_*XF</code> 则记录心法的等级，最高 5 级。其他武功 <code>lv_</code> 最高 10 级。</p>\n<p><code>exp_</code> 只决定升级，如果只改 <code>lv_</code> 到 10，使用一定次数后可能会出现错误。\n不同的武功经验对应的等级不同。例如降龙 1300 满级，龙象 2200 满级。</p>\n<p>| 代码 | 武功 | 备注 |\n| taijiquan | 太极拳 | 遇强则强，特殊之处是对付无名僧一招秒杀 |\n| qishang | 七伤拳 | 升级减血上限 |\n| xingyi | 形意拳 ||\n| anran | 黯然销魂掌 ||\n| tianshan | 天山六阳掌 | 10 级后一定几率生成生死符 |\n| tiezhang | 铁掌 ||\n| liumai | 六脉神剑 ||\n| nianhua | 拈花指 ||\n| taijijian | 太极剑 ||\n| wuyue | 五岳剑法 ||\n| xuantie | 玄铁剑法 ||\n| jiuyang | 九阳神功 ||\n| beiming | 北冥 | 吸内力 |\n| hanbing | 寒冰真气 | 一定几率（10 级最多 7 次）延缓、停止对手行动至打斗结束 |\n| kongming | 空明拳 ||\n| luohan | 罗汉拳 ||\n| xianglong | 降龙十八掌 ||\n| mianzhang | 绵掌 ||\n| hunyuan | 混元掌 ||\n| yiyang | 一阳指 ||\n| tanzhi | 弹指神通 ||\n| canhe | 参合指 ||\n| jinshe | 金蛇剑法 ||\n| dugu | 独孤九剑 ||\n| pixie | 辟邪剑法 | 强力高速 |\n| taixuan | 太玄经神功 ||\n| longxiang | 龙象般若功 ||\n| jinzhong | 吐纳术 | 回血 |\n| jichujian | 基础剑 | 升到 10 级强于最弱剑术 |\n| jichuquan | 基础拳 | 升到 10 级强于最弱拳掌 |</p>\n<p>注意：</p>\n<ul>\n<li>\n<p>辟邪为 <code>pixie</code> 而不是 <code>biexe</code>.</p>\n</li>\n<li>\n<p>吐纳心法对应的是 <code>no_tnxf</code>、<code>lv_tunaXF</code>，而吐纳术对应的却是 <code>lv_jinzhong</code>、<code>exp_jinzhong</code>.</p>\n<p>似乎原本有一种减伤害的金钟罩功夫，后来去掉了，改成加血的吐纳术。</p>\n</li>\n<li>\n<p><code>hhh</code> 记录九阴神爪等级，<code>iii</code> 记录九阴神爪经验。</p>\n</li>\n<li>\n<p><code>kkk</code> 为自创等级。<code>lll</code> 为自创经验。<code>jjj</code> 为自创武功名称。</p>\n<ul>\n<li>\n<p>游戏的 bug，<code>jjj</code> 仅体现在战斗中。武功栏中始终是【还我漂漂拳】。</p>\n</li>\n<li>\n<p>左右互搏，拳掌、御剑、暗器、用毒 100，力道 500，自创 10 级时，伤害 6000 * 2，威力在所有武功中最大。</p>\n</li>\n<li>\n<p><code>rrr</code> 记录战胜半瓶神仙醋的次数，改成 19 后再战胜一次即可自创武功。</p>\n</li>\n</ul>\n</li>\n<li>\n<p>左右互搏代码未知。</p>\n<pre><code>  伤害 * 0.75 * 2.\n</code></pre>\n</li>\n</ul>\n<h2>物品</h2>\n<p><code>no_</code> 开头的变量记录物品数量。背包中物品数量只有两位，实际不止，超过 99 战斗时照常使用。</p>\n<p>常用物品：</p>\n<ul>\n<li><code>no_jhylw</code>， 九花玉露丸，补 80% 生命、内力。</li>\n<li><code>no_fb</code>，飞镖，暗器、用毒 100 后恒定伤害 1500，如有左右互搏则恒定伤害 1125 * 2.</li>\n<li><code>no_sxf</code>，生死符，暗器、用毒 100 后恒定伤害 1350.</li>\n</ul>\n<p>有些物品只能通过修改改出：</p>\n<ul>\n<li>大还丹（补 45% 内力）</li>\n<li>天山雪莲（扩充 10% 生命、内力，补满生命、内力）</li>\n<li>玄冰碧火酒</li>\n<li>瑶琴（对应情节未开发）</li>\n<li>打狗棒（对应情节未开发）</li>\n</ul>\n<h2>场景</h2>\n<p><code>CJ</code> 记录场景：【昆仑仙境】、【华山】、【剑冢】、【百花谷】、【衡阳】、【襄阳】、【侠客岛】、\n【武当派】、【明教过道】、【黑木崖】、【练毒功】、【少林寺】。</p>\n<h2>攻略</h2>\n<h3>自创</h3>\n<p>首先，剧情进行至衡阳城，存档。\n修改生命、内力 9999，悟性 49，力道、护体为 300，其他属性为 100，银两 99999，学习点 999.</p>\n<p>打败半瓶醋 20 次后可学自创，自创学习后会洗掉所有武功。因此先学自创。\n生命 9999 不够，改九花玉露丸数量。\n普通攻击打败太慢，改飞镖数量。\n<code>rrr</code> 改成 19，到地图刀剑处，有一定概率碰到半瓶醋，获胜得自创。</p>\n<p>打败半瓶醋后会减侠义（人品），由于初始侠义 50，减 1 后为恶，阿紫出现。\n帮她捉虫可以增加毒术，但是毒术已经改到 100 了，因此不用理她。</p>\n<p>遇到半瓶醋 20 次投降后可以得龙象般若功或学习点或钱或天下第一称号。\n或者直接改 <code>lv_longxiang</code> 和 <code>exp_longxiang</code>.</p>\n<h3>衡阳城</h3>\n<p>找小宝货郎买金蛇套装，得金蛇剑法，装备金蛇剑、金丝甲。</p>\n<p>客栈上楼遇田伯光和仪琳。选择和田伯光结拜的话以后可以找风清扬学独孤九剑，不结拜的话可以找令狐冲学。\n和田伯光结拜的话，会碰到泰山派道人，阻止田伯光灭口的话会跌侠义值，不过无所谓，因为战胜半瓶醋已经跌侠义了。</p>\n<p>武馆可以学形意拳。</p>\n<p>医馆的金疮药、小还丹太次，不用买。</p>\n<h3>百花谷</h3>\n<p>找周伯通切磋，先输 1 场，得左右互搏。</p>\n<p>左右互搏得到，悟性可以改 100 了。再赢 1 场，得九阴真经。</p>\n<h3>辟邪剑谱</h3>\n<p>福威镖局找林平之。再去破庙击败木高峰。回福威镖局告诉林平之。</p>\n<p>然后再去福威镖局找林平之，得知林已杀木高峰，不过眼睛瞎了无法找余沧海报仇。</p>\n<p>至青城派杀余沧海，然后回福威镖局得辟邪剑谱。</p>\n<h3>无量山洞</h3>\n<p>至无量山洞，点磕头 100 下，得北冥、凌波微步。</p>\n<p>出洞，击败莽牯朱蛤。使用可以解毒变 100，不过解毒已经改到 100 了。</p>\n<h3>九阳神功</h3>\n<p>至昆仑派，输给何太冲。注意何太冲每击只伤 1，因此事先要找周伯通打成贫血，否则有的等了。</p>\n<p>输掉后被打落山崖，得九阳神功。</p>\n<h3>少林</h3>\n<p>至少林寺，选偷入藏经阁，一定概率得拈花指和易筋经。</p>\n<p>或者也可以直接修改 <code>no_yijinXF</code> 得到易筋经。</p>\n<p>偷到拈花指和易筋经后可拜入少林寺（拜入后就再没机会偷了）。</p>\n<p>拜入后从玄苦处学得罗汉拳。罗汉拳 10 级，得混元掌。混元掌 6 级，得参合指。</p>\n<p>然后去野外杀生（强盗、老虎） 20 次，回少林寺，会被关，打赢厨僧后成为少林弃徒。</p>\n<p>如果超过 30 级即使再杀生也成不了弃徒。这时可直接改门派或者改等级。</p>\n<h3>弹指神通</h3>\n<p>此时等级应该已过 20 了，再去破庙，遇李莫愁，选择静观其变，得弹指神通。</p>\n<h3>剑冢</h3>\n<p>助大雕，得玄铁剑、玄铁剑法。</p>\n<h3>黯然销魂掌</h3>\n<p>至渡口，与杨过切磋，获胜得黯然销魂掌。</p>\n<h3>万劫谷</h3>\n<p>至万劫谷，选择对付四大恶人，击败段延庆，得一阳指。</p>\n<h3>天龙寺</h3>\n<p>至天龙寺，击败鸠摩智，改姓段，得六脉神剑。（若没在万劫谷得一阳指，则得一阳指而不是六脉神剑。）</p>\n<h3>聚贤庄</h3>\n<p>这时声望够高，应该已经得到刘正风金盆洗手请帖和聚贤庄邀请函了。</p>\n<p>先去聚贤庄，助萧峰。然后再去长白山，得降龙十八掌。</p>\n<h3>笑傲江湖</h3>\n<p>去衡阳参见刘正风金盆洗手大会，事先不要去嵩山派，否则会成为阻止刘正风金盆洗手的人，且得不到笑傲江湖曲谱。</p>\n<p>费彬阻止金盆洗手，曲洋救走刘正风，追出，听合奏《笑傲江湖》，击败费彬，得《笑傲江湖》曲谱。</p>\n<p>至襄阳城衙门，击败士兵，遭暗算下狱。战胜丁典，不跟随越狱，得乌蚕衣（最强护甲）。</p>\n<p>第二天提审时不承认，见绿竹翁，不要赠《笑傲江湖》曲谱，\n否则会得到黑木令，去日月神教会战东方不败，战胜也得不到《葵花宝典》。\n除非先加入日月神教，再带着曲谱到襄阳城衙门，触发绿竹翁事件。</p>\n<p>返回衙门，击败，得银两。</p>\n<h3>寒冰真气</h3>\n<p>至嵩山派，得五岳令，至华山找封不平，再返回嵩山派，至襄阳妓院找玉玑子，仍返回嵩山派，至铸剑谷教训定逸。</p>\n<p>最后至嵩山派得寒冰真气。</p>\n<h3>华山</h3>\n<p>侠义改为 50 以上，如果没有成为少林弃徒，则将门派改为「无门派」。</p>\n<p>入华山，得《华山心法》。先别练到 5 级，否则一找岳不群说话就会进入思过崖剧情。</p>\n<p>找岳不群说话，这样以后思过崖剧情可得五岳剑法。</p>\n<p>找岳灵珊说话，有一定几率会切磋，连输 10 次，以后思过崖剧情可得紫霞心法。\n因为岳灵珊每击只能伤 1，因此事先先到渡口找杨过打成贫血，否则有的等了。</p>\n<p>找令狐冲说话，给他酒、杯（衡阳小宝货郎处购买）可以得独孤九剑。\n如果不找令狐冲说话的话，因为事先和田伯光结拜过，思过崖剧情可从风清扬处得到独孤九剑。</p>\n<p>华山心法 5 级，找岳不群至思过崖闭关，休息几次后，悟出五岳剑法。</p>\n<p>遇田伯光，将其击败。（虽说是来抓你走的，但是打输了直接 game over.）</p>\n<p>再休息几次后，岳灵珊会来送紫霞秘籍。</p>\n<p>然后参加五岳并派大会，获胜，成为五岳掌门。</p>\n<h3>侠客岛</h3>\n<p>此时当仍为善，可乘此机会去侠客岛（恶人学不到太玄经）。</p>\n<p>至渡口找张三，到侠客岛，得腊八粥，参悟武功得太玄经神功。</p>\n<h3>入武当</h3>\n<p>门派改为「无门派」，入武当。</p>\n<p>如等级在 30 以上，一入武当马上找俞岱岩学武当心法，再学绵掌，武当心法 5 级后则学梯云纵。\n期间切勿和张三丰讲话，否则会进入围攻光明顶剧情，学不到武功。\n如果不行，把等级改到 30 以下。</p>\n<h3>光明顶</h3>\n<p>等级 30 时至光明顶，山脚遇灭绝与魔教教众，助魔教，进山洞，1、2、3、2，选书信，得乾坤大挪移，学习到顶级。</p>\n<p>相助明教，靠乾坤大挪移得七伤拳。击败灭绝得倚天剑（最强剑）。</p>\n<p>这里若是相助正派，回武当得太极拳、太极剑、真武剑（还不如玄铁剑），但是得不到七伤拳、倚天剑。</p>\n<p>至百花谷，与周伯通切磋，靠乾坤大挪移得空明拳。</p>\n<p>七伤拳和空明拳是乾坤大挪移能学到的武功，其他的学不到。</p>\n<h3>葵花宝典</h3>\n<p>至黑木崖，入日月神教，铁掌 10 级，找向问天。出来后再进黑木崖，击败任我行，得《葵花宝典》。</p>\n<p>至此所有秘籍都修炼了，力道、护体可达最大值 500.</p>\n<p>此后需要经验值可以找任我行切磋，增加得比较快。</p>\n<p>如果碰到任我行说身体不适，如果想拿「东方不败」的称号，那么选择终于等到这一天了，击败向问天、任我行，得称号。</p>\n<p>拿了称号也没有其他好处，\n不拿的话反正渡口有杨过可以切磋，任我行除了会吸内力外实力差不多（周伯通弱好多，奇怪），都可以。</p>\n<h3>长白山</h3>\n<p>35 级到长白山，助天山童姥得天山六阳掌。</p>\n<p>至此除了太极拳、太极剑以外，所有武功都学了。这两样可以通过修改学习。</p>\n<h3>华山之巅</h3>\n<p>华山论剑，击败匪兵丙、萧峰、东方不败、无名僧、半瓶醋通关。</p>","date_published":"Thu, 24 Aug 2017 13:06:40 GMT","date_modified":"Sat, 26 Jul 2025 05:29:46 GMT"},{"id":"https://mmap.page/dapi/shuoba-xizang/","url":"https://mmap.page/dapi/shuoba-xizang/","title":"跋说吧西藏","content_html":"<h1>跋说吧西藏</h1>\n<p>宁肯. 说吧，西藏[M]. 北京:十月文艺出版社北京,2013-10. ISBN 9787530213360</p>\n<p><a href=\"http://book.douban.com/subject/25764322/\">http://book.douban.com/subject/25764322/</a></p>\n<blockquote>\n<p>进入一棵树是可能的\n进入岩石也是可能的\n当我回忆往昔\n我觉得就在它们之中</p>\n</blockquote>\n<p>-- 《在一棵树中回忆》, p. 1</p>\n<blockquote>\n<p>事物总是缠绕在一起，可知部分总是引起更多未知部分。</p>\n</blockquote>\n<p>-- 《在一棵树中回忆》, p. 2</p>\n<p>案：「可」当为「已」。\n「可知」、「不可知」和「已知」、「未知」是两回事。</p>\n<blockquote>\n<p>宁： 我不写完这本书有点怕去西藏，为什么说呢，\n就是它那儿一变化之后，比如包括咱们六中那附近改变了之后，\n我会觉得它对我是一种摧残，就是说，\n如果我没把那个世界用文字固定下来之前，我要去了就把自己毁了。</p>\n<p>林： 那就把原来一切消解了。</p>\n<p>宁： 那就和我原来那个东西不是一个味了。</p>\n</blockquote>\n<p>-- 《西藏谈话录》，p. 149</p>\n<p>注：「宁」为「宁肯」，「林」为「林跃」，两人在 20 世纪 80 年代「援藏」时同住拉萨六中附近。</p>\n<p>案：「那儿一变化之后」，「就和我原来那个东西不是一个味了」，因此应对的措施是「把那个世界用文字固定下来」。\n但是「把那个世界用文字固定下来」又何尝不「是一种摧残」呢？\n每次回忆，总会有一些想象的成分加进去，总会有一些东西被想象所扭曲。\n「用文字固定下来」就更是如此，毕竟和回忆相比，文字是一维的，更容易产生扭曲。\n「那儿一变化之后」，「原来那个东西」就「不是一个味了」。文字固定的效用是有限的。</p>\n<blockquote>\n<p>宁： 能不用大家说习惯了的词就不用，找到自己又平常又贴切的表达。\n...\n宁： 什么一形容天，就天高云淡，云绽天开，什么月上柳梢头，人约黄昏后，就这种现成的语言你甭想在我这书里找到。\n...\n宁： 实际上有些词由于过度使用已用废了，报废了。\n...\n宁： 如果我不能用一种新的语言表达，比如那种景色，或人物交代——\n...\n宁： ... 我就宁可用最朴素的语言最平白的最日常的最基本的语词表达，\n我不知道你记不记得鲁迅的《狂人日记》，开头给我印象特深，\n「今天晚上，很好的月光」。\n林： 那是连小学一年纪的孩子都会写的。\n宁： 对！非常的明白，今晚月光很好，它就不像说，「今晚月光如水」「皓月当空」，那成什么了！\n...\n宁： 它就不像烂文人经常写的，它就一下回到最根本最原始的语言，今晚月光很好，我靠，多本真呀！\n... 我说语言，如果你不能出新就回到本真上来，回到这儿来。\n...\n宁： 哎，回到原初，回到最朴素，最准确。如果你有创新，你就用创新，没创新就回到这上。\n...\n宁： 这就像语言的一个底线，你时刻站在这个预言的底线上，站在最基本上，不跨出是不跨出，\n一跨出就一定是达到另一个极致，是别人无法超越的，要不然就退守到底线上。\n...\n宁： 绝不能既不退守底线，也没创新，使用那种华丽的似是而非的人云亦云的现成的。</p>\n</blockquote>\n<p>-- 《西藏谈话录》，p. 161-163</p>\n<p>案：其实科技文本的语言就追求朴素准确。文学则是在朴素准确之外另有趣味的追求。\n而所谓的「华丽的似是而非的人云亦云的现成的」，则既无趣味，又不准确，确是「由于过度使用已用废」。\n不准确，也类似王国维《人间词话》中说的「隔」。</p>\n<blockquote>\n<p>宁： 是什么是就说什么事，你不如我那《天・藏》的开头，就是一个陈述句，就没任何形容词，\n「我的朋友王摩看到马丁格的时候，雪已飘过那个午后。」\n...\n宁： 你说简单不简单，是最简单的，可实际要通过多少复杂的手段才能找到它？\n我最终找到这句话，这个开头，太难了，多少个开头之后才有了这个开头。</p>\n</blockquote>\n<p>-- 《西藏谈话录》, p. 164</p>\n<p>案：用词确实是朴素准确了。但是这个句式并不朴素，仍有一种「文学」气。同时这个句式也算不上创新。\n因此这个开头是一个反面的例子，不光要注意用词，还要注意句式。\n这个开头受句式拖累，算不得「最简单」。其实平常人随便想个开头，一般不会想出这种句式。\n恰是文学气重的人，挖空心思容易想出这种句式。用力过了。\n当然不是说用大力一定不好，可是用力归用力，露出用力的痕迹可不美。\n「天然去雕饰」，很好；「妆成有却无」，也不错。\n若是整容的「美人」，一望即知，那这整容的水平看来也不怎么样。</p>\n<blockquote>\n<p>宁： ... 对，我曾给一个时尚杂志写过一片西藏，哎呦写得我这难受呀，难受死了，此后再也不写了，\n甚至我告诉你，我不如他们写的好，因为他们都写油了，\n他们写的那个陈词滥调写得那叫顺溜呀，我还真做不到。</p>\n</blockquote>\n<p>-- 《西藏谈话录》, p. 179</p>\n<blockquote>\n<p>旅行的过程是一个强烈地意识到自我与他者互动的过程，这种过程正是文学的滋生地之一。\n西班牙大哲学家奥德嘉·嘉塞曾经说过：告诉我你关注什么，我就会告诉你你是谁。\n人往往是通过自己关注的东西来创造自己的，不论我们将注意力投向何方，我们都会被它塑造。\n你关注远方，远方必定会塑造你，你关注旅行，旅行必定会塑造你。在这个意义上，奥德嘉·嘉塞进一步说：\n「生命本身就是一件有诗意的工作，人是他自己的小说家，因此生命事实上就是一种文学形式。」</p>\n</blockquote>\n<p>-- 《一个人的道路——我的自述》, p. 203</p>\n<blockquote>\n<p>在穿越了大面积的杂乱无章的时尚建筑后，拙政园并没有给我带来愉快之情，\n相反它像标本一样被夹在无限大的杂乱无章之中。</p>\n</blockquote>\n<p>-- 《泰州・答问》, p.266</p>\n<p>我以前写过类似的文字，苏州给我的感觉是一些古旧的残迹被抛掷到了现代的汪洋之中。\n这种怪异的不协调感让我很不适应。我只能安慰自己说很多城市连感受这种不适的机会都没有。\n后来有时看到媒体上的文章，说是「古典与现代的完美结合」就感叹真是各人有各人的想法，\n要我说是「古典与现代的完美不结合」才对。</p>","date_published":"Thu, 24 Aug 2017 11:59:00 GMT","date_modified":"Sat, 23 Nov 2019 19:11:50 GMT"},{"id":"https://mmap.page/dapi/zhuzhu/","url":"https://mmap.page/dapi/zhuzhu/","content_html":"<p>二零零幾年淘寶早期的時候，cn的大量網站都是淘寶的彈窗廣告，十分討厭。\n過了幾年沒有了。現在支付寶對linux、mac os x的支持度也比幾年前好多了。\n所以我有一個錯覺：做大了，多少會守一點規矩。現在看來這個真是錯覺。:-()</p>\n<p>-- <a href=\"https://plus.google.com/+JakukyoFriel/posts/JPTTkp54nZv\">Sep 16, 2012</a> on Aliyun OS</p>","date_published":"Mon, 21 Aug 2017 03:35:43 GMT","date_modified":"Sat, 23 Nov 2019 19:11:50 GMT"},{"id":"https://mmap.page/poems/quatrains/","url":"https://mmap.page/poems/quatrains/","title":"絕句","content_html":"<h1>絕句</h1>\n<h2>詞將窮</h2>\n<pre><code>去留肝膽兩昆侖\n辭達而已未成章\n望斷天涯不回首\n相付惟有淚千行\n</code></pre>\n<p>composed at 2011-04-23</p>\n<h2>無題</h2>\n<pre><code>柯亭亡臣傳竹笛\n孤山處士妻梅花\n莫羡錦鱗人爭乳\n自有芙蕖憐小蝦\n</code></pre>\n<p>composed at 2011-06-01</p>\n<h2>打油一首嘆喪失光榮傳統不發月餅</h2>\n<pre><code>月影即是餅\n入眼甘如飴\n畵餅不似月\n遇食亦無虧\n</code></pre>\n<p>composed at 2011-09-16</p>\n<h2>古絕一對</h2>\n<p>昨日遊清涼山公園，中有南唐古井名還陽者，深幽似通冥府，感其名，因作古絕一對。</p>\n<pre><code>五十弦斷盆可鼓\n卅載井枯水猶涼\n還陽徒爾十指戕\n莫若尸居觀天長\n\n君言弦斷盆可鼓\n卻道井枯水猶涼\n卅載尸居觀天恢\n一朝還陽十指戕\n</code></pre>\n<p>composed at 2011-10-15</p>\n<h2>讀莊</h2>\n<pre><code>生寄死歸奚足悲\n莊生猶嘆吾質失\n寢說豈忘堅白昧\n入土難安皮囊室\n</code></pre>\n<p>composed at 2011-12-02</p>\n<h2>詞窮</h2>\n<pre><code>天網恢恢筌蹄朽\n窮不窮處詞未工\n欲將殘生抵一聯\n奈何蝶心曉夢終\n</code></pre>\n<p>free edition, composed at 2012-03-19</p>\n<pre><code>盡忘筌蹄風月好\n齊觀窮達薄詞工\n欲將殘歲抵詩句\n無奈蝶心晨夢終\n</code></pre>\n<p>bondage edition, composed at 2012-03-20, and edited at 2012-03-27 (change '餘歲' to '殘歲') and 2012-09-02 (change '曉' to '晨', to avoid 孤平)</p>","date_published":"Sun, 20 Aug 2017 08:25:35 GMT","date_modified":"Sat, 23 Nov 2019 19:28:41 GMT"},{"id":"https://mmap.page/poems/","url":"https://mmap.page/poems/","title":"詩存","content_html":"<h1>詩存</h1>\n<ul>\n<li><a href=\"https://mmap.page/poems/resentment-in-boudoir.md\">閨怨</a></li>\n<li><a href=\"https://mmap.page/poems/drinking.md\">飲酒二首</a></li>\n<li><a href=\"https://mmap.page/poems/exodia.md\">Exodia</a></li>\n<li><a href=\"https://mmap.page/poems/quatrains.md\">其他絕句</a></li>\n<li><a href=\"https://mmap.page/poems/southern-opera.md\">南曲一首</a></li>\n</ul>","date_published":"Sun, 20 Aug 2017 08:25:35 GMT","date_modified":"Fri, 21 Apr 2023 11:03:43 GMT"},{"id":"https://mmap.page/dapi/","url":"https://mmap.page/dapi/","content_html":"<h2>故紙</h2>\n<ul>\n<li>\n<p><a href=\"https://mmap.page/dapi/chengshuxianhou.md\">如何考察成书先后</a></p>\n<p>古书成书先后的判断方法</p>\n</li>\n<li>\n<p><a href=\"https://mmap.page/dapi/zuozhuan_guo-jue-ming.md\">左傳春秋經國加爵加名之用例</a></p>\n<p>左傳春秋經中「國（或部族）+爵+名」的全部用例</p>\n</li>\n<li>\n<p><a href=\"https://mmap.page/dapi/redman.md\">赤狄</a></p>\n<p>江戶年間，日人重載了「赤狄」一語（原謂春秋時狄人一支）</p>\n</li>\n<li>\n<p><a href=\"https://mmap.page/dapi/daoliangmou.md\">稻粱謀</a></p>\n<p>辨「稻粱謀」、「餬口」二語</p>\n</li>\n<li>\n<p><a href=\"https://mmap.page/dapi/moshou.md\">跋春秋學史</a></p>\n<p>徐彥等對《公羊墨守》「墨守」一詞的誤解</p>\n</li>\n<li>\n<p><a href=\"https://mmap.page/dapi/bidouxiangzao.md\">跋貴妃的紅汗</a></p>\n<p>釋「香藻」</p>\n</li>\n<li>\n<p><a href=\"https://mmap.page/dapi/huangkanshoupifuhao.md\">跋黃侃手批白文十三經</a></p>\n<p>黃侃手批白文十三經所用符號</p>\n</li>\n<li>\n<p><a href=\"https://mmap.page/dapi/jingxuejueyuan.md\">跋經學抉原</a></p>\n<p>蒙文通所謂「經傳」，與古學異趣</p>\n</li>\n<li>\n<p><a href=\"https://mmap.page/dapi/xiaochuang.md\">跋兩晉至唐靈座靈牀漫談</a></p>\n<p>小牀與靈牀</p>\n</li>\n<li>\n<p><a href=\"https://mmap.page/dapi/lunyu-huijiaojishi.md\">跋論語彙校集釋</a></p>\n<p>本書彙校，頗為粗疏</p>\n</li>\n<li>\n<p><a href=\"https://mmap.page/dapi/lunyucidian-patch.md\">跋論語譯注</a></p>\n<p>后附《論語詞典》「德」字用例漏了 1 個</p>\n</li>\n<li>\n<p><a href=\"https://mmap.page/dapi/lunyu-zhengzhu.md\">跋唐寫本論語鄭氏注及其研究</a></p>\n<p>後出的兩篇關於論語鄭注的論文</p>\n</li>\n<li>\n<p><a href=\"https://mmap.page/dapi/hezhe.md\">跋中國語言學論文集</a></p>\n<p>「閉門造車，出門合轍」之例</p>\n</li>\n</ul>\n<h2>舊瓶</h2>\n<ul>\n<li>\n<p><a href=\"https://mmap.page/dapi/evil-interview.md\">魔王訪談錄</a></p>\n<p>嘗試寫小説，結果寫成了這副樣子。。。</p>\n</li>\n</ul>\n<h2>生活</h2>\n<ul>\n<li>\n<p><a href=\"https://mmap.page/dapi/wash-clothes.md\">洗衣</a></p>\n<p>如何混洗内外衣、洗毛衣</p>\n</li>\n<li>\n<p><a href=\"https://mmap.page/dapi/packaging.md\">行李</a></p>\n<p>精简衣物，选择便于携带的衣物（组合）</p>\n</li>\n</ul>\n<h2>詩箋</h2>\n<ul>\n<li><a href=\"https://mmap.page/dapi/chufenger.md\">楚风儿</a></li>\n</ul>\n<h2>算器</h2>\n<ul>\n<li><a href=\"https://mmap.page/dapi/ai.md\">AI</a></li>\n<li><a href=\"https://mmap.page/dapi/avoid-html.md\">少写些 HTML</a></li>\n<li><a href=\"https://mmap.page/dapi/flutter.md\">Flutter试玩</a></li>\n<li><a href=\"https://mmap.page/dapi/learn-programming.md\">编程入门路线</a></li>\n<li><a href=\"https://mmap.page/dapi/not-a-blog.md\">这里并不是 blog</a></li>\n<li><a href=\"https://mmap.page/dapi/windows-handbook.md\">Windows 使用手冊</a></li>\n</ul>\n<h2>文藝</h2>\n<ul>\n<li><a href=\"https://mmap.page/dapi/lingfeng.md\">《铃丰的恋物语与剑道社》「用感觉来写」的文学追求：以语法特征分析为中心</a></li>\n</ul>\n<h2>閑話</h2>\n<ul>\n<li>\n<p><a href=\"https://mmap.page/dapi/shuoba-xizang.md\">跋说吧西藏</a></p>\n<p>关于文学</p>\n</li>\n</ul>\n<h2>游戲</h2>\n<ul>\n<li><a href=\"https://mmap.page/dapi/jyqxz2-cheat.md\">金庸群侠传 2 加强版作弊教程</a></li>\n<li><a href=\"https://mmap.page/dapi/jyqxz3-cheat.md\">金庸群侠传 3 作弊教程</a></li>\n<li><a href=\"https://mmap.page/dapi/jyqxz3-gumu.md\">金庸群侠 3 古墓版攻略</a></li>\n</ul>\n<h2>語言</h2>\n<ul>\n<li>\n<p><a href=\"https://mmap.page/dapi/shath-yar.md\">Shath'Yar 语</a></p>\n<p>探索WOW中的古神语</p>\n</li>\n</ul>\n<hr>\n<p><a href=\"https://mmap.page/poems/README.md\">詩存</a> | <a href=\"https://mmap.page/dapi/log.md\">碎碎念</a></p>","date_published":"Sun, 20 Aug 2017 08:25:35 GMT","date_modified":"Sat, 26 Jul 2025 05:04:12 GMT"},{"id":"https://mmap.page/vim/completion/","url":"https://mmap.page/vim/completion/","title":"Vim Completion Configuration","content_html":"<h1>Vim Completion Configuration</h1>\n<h2>A Bit of History</h2>\n<p>Vim has built-in support for completions in insert or replace modes,\nmostly based on the content of the current file and included files.\nBy default, it uses separate Emacs-style key bindings (<code>&#x3C;C-x C-key></code>)\nfor different kinds of completions.\nSee <code>:help ins-completion</code> for more information.</p>\n<p>The modern approach is utilizing language server protocol, a.k.a. LSP, and machine learning.</p>\n<p>The concept of LSP is pioneered by vscode,\nso a lot of language servers are written in Node.js and TypeScript.\nWhile mostly used for LSP,\n<a href=\"https://github.com/neoclide/coc.nvim\">CoC</a> brings the ecosystem of vscode extensions to vim,\nwhich makes porting them to vim easier.</p>\n<p>Then Neovim 0.5+ introduces native LSP support,\nbased on Lua instead of Node.js.\nHowever, as mentioned above, since a lot of language servers are written in Node.js,\nmost likely Node.js is still needed.</p>\n<h2>Machine Learning based Completion</h2>\n<p>Popular options of machine learning assisted completion are:</p>\n<ul>\n<li>Tabnine</li>\n<li>GitHub Copilot</li>\n<li>Codeium</li>\n<li>Amazon CodeWhisperer</li>\n</ul>\n<p>I have used Tabnine (free plan) for a while.\nIt does not include whole line and full-function code completion.\nAlthough Tabnine Pro offers offline installation, it requires contacting <a href=\"https://support.tabnine.com/hc/en-us/articles/5409869385873-Offline-Installation-Usage-of-Tabnine\">sales</a>.\nIts free plan is based on the cloud, just like Copilot.</p>\n<p>Tabnine Pro is <a href=\"https://www.tabnine.com/pricing\">$12 per month</a>, slightly higher than Copilot (<a href=\"https://github.com/features/copilot/\">$10 per month</a>).\nAnd qualified open source project contributors can use Copilot for free.</p>\n<p>Both Codeium and Amazon CodeWhisperer are free for personal use.\nCurrently, CodeWhisperer only supports VSCode and JetBrain IDEs.</p>\n<p>I use Copilot and Codeium at the same time under Neovim,\nwhere <a href=\"https://github.com/hrsh7th/nvim-cmp\">nvim-cmp</a> can use both as a completion source.\nCodeium tends to offer multi-line completion as a whole,\nand Copilot are more likely to provide completions line by line.\nThe completion quality is roughly the same, as I have experienced.</p>\n<h3>My LazyVim Configuration for Copilot and Codeium</h3>\n<pre><code class=\"language-lua\"><span class=\"pl-c\">-- lua/config/lazy.lua</span>\n<span class=\"pl-c1\">require</span>(<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>lazy<span class=\"pl-pds\">\"</span></span>).<span class=\"pl-c1\">setup</span>({\n  <span class=\"pl-smi\">spec</span> <span class=\"pl-k\">=</span> {\n    { <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>LazyVim/LazyVim<span class=\"pl-pds\">\"</span></span>, <span class=\"pl-smi\">import</span> <span class=\"pl-k\">=</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>lazyvim.plugins<span class=\"pl-pds\">\" </span></span>},\n    { <span class=\"pl-smi\">import</span> <span class=\"pl-k\">=</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>lazyvim.plugins.extras.coding.copilot<span class=\"pl-pds\">\" </span></span>},\n    { <span class=\"pl-smi\">import</span> <span class=\"pl-k\">=</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>plugins<span class=\"pl-pds\">\" </span></span>},\n  },\n})\n\n<span class=\"pl-c\">-- lua/plugins/cmp.lua</span>\n<span class=\"pl-k\">return</span> {\n  <span class=\"pl-c\">-- The official plugin does not support nvim-cmp, use a community one instead.</span>\n  {\n    <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>jcdickinson/codeium.nvim<span class=\"pl-pds\">\"</span></span>,\n    <span class=\"pl-smi\">dependencies</span> <span class=\"pl-k\">=</span> {\n      <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>nvim-lua/plenary.nvim<span class=\"pl-pds\">\"</span></span>,\n      <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>hrsh7th/nvim-cmp<span class=\"pl-pds\">\"</span></span>,\n    },\n    <span class=\"pl-en\">config</span> <span class=\"pl-k\">=</span> <span class=\"pl-k\">function</span>()\n      <span class=\"pl-c1\">require</span>(<span class=\"pl-s\"><span class=\"pl-pds\">\"</span>codeium<span class=\"pl-pds\">\"</span></span>).<span class=\"pl-c1\">setup</span>({})\n    <span class=\"pl-k\">end</span>,\n  },\n}\n</code></pre>","date_published":"Sun, 23 Jul 2017 13:56:52 GMT","date_modified":"Tue, 25 Apr 2023 07:46:55 GMT"},{"id":"https://mmap.page/","url":"https://mmap.page/","content_html":"<p>This is a learning-by-doing project for me to experiment <a href=\"https://lume.land/\">Lume</a> and <a href=\"https://deno.land/\">Deno</a>.</p>\n<h2>Random Pages</h2>\n<p>Some random pages for demonstration purposes (content may be outdated or auto generated via AI).</p>\n<h3>Syntax Highlighting</h3>\n<p>Syntax highlighting in Lume is supported via <a href=\"https://lume.land/plugins/prism/\">Prism</a> or <a href=\"https://lume.land/plugins/code_highlight/\">Highlight.js</a>.\nAnd two community plugins for <a href=\"https://deno.land/x/lume_glow\">Glow</a> and <a href=\"https://deno.land/x/lume_shiki\">Shiki</a> are available.</p>\n<p>Glow is too naive to me and supports only a limited set of languages.\nCompared to Prism and Highlight.js, Shiki is more powerful and ships zero JavaScript in runtime.\nFor this site, I use <a href=\"https://github.com/wooorm/starry-night\">starry-night</a>, which is similar to Shiki in essence,\nbut matches GitHub in that it produces classes and works with the CSS it ships.\nThere is no Lume plugin for Starry Night, but it is easy to use with Lume:</p>\n<pre><code class=\"language-ts\"><span class=\"pl-smi\">site</span>.<span class=\"pl-en\">use</span>(<span class=\"pl-en\">remark</span>({\n  rehypePlugins: [[\n    <span class=\"pl-smi\">rehypeStarryNight</span>, {\n      grammars: <span class=\"pl-smi\">all</span> \n    }]],\n}));\n</code></pre>\n<p>Some random pages with syntax highlighting:</p>\n<ul>\n<li><a href=\"https://mmap.page/dive-into/exceptions.md\">Exception and Union Type</a></li>\n<li><a href=\"https://mmap.page/java/a-little.md\">Notes on A little Java, a Few Patterns</a></li>\n<li><a href=\"https://mmap.page/dive-into/ruby.md\">Quirks of Ruby</a></li>\n</ul>\n<h3>More Random Pages</h3>\n<ul>\n<li><a href=\"https://mmap.page/dive-into/ts-check.md\">Fight for Type Safety Stand with JavaScript</a> (ts-check with JSDoc comments)</li>\n<li><a href=\"https://mmap.page/dive-into/eslint.md\">An Opinionated Guide to ESLint</a></li>\n<li><a href=\"https://mmap.page/dive-into/make.md\">Write Makefile Compatible with Both GNU make and BSD make</a></li>\n<li>Neovim <a href=\"https://mmap.page/vim/completion.md\">code completion</a> and <a href=\"https://mmap.page/vim/spell.md\">spell checking</a></li>\n<li><a href=\"https://mmap.page/dive-into/gitmoji.md\">Selected Gitmojis</a></li>\n<li><a href=\"https://mmap.page/web/html-history.md\">History of HTML through Linux/BSD Websites</a></li>\n<li><a href=\"https://mmap.page/dive-into/gh-pages.md\">Build a Micro Static Site With GitHub Pages</a></li>\n<li><a href=\"https://mmap.page/dive-into/rarcrack.md\">RarCrack Basic Guide</a></li>\n<li><a href=\"https://mmap.page/dapi/README.md\">Notes</a> and <a href=\"https://mmap.page/poems/README.md\">poems</a> written in Chinese</li>\n</ul>\n<h2>Markdown Sandbox</h2>\n<p>The following table uses GitHub Flavored Markdown (GFM) table syntax,\nwhich may not render correctly in all Markdown viewers:</p>\n<table>\n<thead>\n<tr>\n<th><a href=\"https://github.com/weakish\" title=\"GitHub\">gh</a></th>\n<th><a href=\"https://gist.github.com/weakish\" title=\"GitHub Gist\">gist</a></th>\n<th><a href=\"https://social.vivaldi.net/@lib\" title=\"@lib@vivaldi.net\">mastodon</a></th>\n<th><a href=\"https://api.github.com/users/weakish/gpg_keys\" title=\"2414 AEA0 EA48 5263 9697 F1BA 55F6 EEC2 EA3F 0A87\">gpg</a></th>\n<th><a href=\"https://mmap.page/rss.xml\" title=\"Recent Updates in RSS Feed (XML)\">rss</a></th>\n<th><a href=\"https://mmap.page/feed.json\" title=\"All Posts in JSON Feed\">json</a></th>\n<th><a href=\"https://mmap.page/log/README.md\" title=\"Micro web log\">/log</a></th>\n<th><a href=\"https://mmap.page/movies/\" title=\"Recently Watched Movies\">/movies</a></th>\n<th><a href=\"https://mmap.page/uses/README.md\" title=\"Setups, gear, software\">/uses</a></th>\n</tr>\n</thead>\n</table>\n<p><a href=\"https://app.netlify.com/sites/weakish/deploys\"><img src=\"https://api.netlify.com/api/v1/badges/2ebbcd01-c006-40c1-92cd-b927220814bc/deploy-status\" alt=\"Netlify Status\"></a></p>","date_published":"Sun, 11 Sep 2016 00:46:52 GMT","date_modified":"Fri, 25 Jul 2025 15:54:06 GMT"},{"id":"https://mmap.page/coding-style/","url":"https://mmap.page/coding-style/","title":"Style Guide","content_html":"<h1>Style Guide</h1>\n<p>These are for personal reference only.</p>\n<ul>\n<li><a href=\"https://mmap.page/coding-style/general.md\">General</a></li>\n<li><a href=\"https://mmap.page/coding-style/formatting.md\">Formatting</a></li>\n<li><a href=\"https://mmap.page/coding-style/c.md\">C</a></li>\n<li><a href=\"https://mmap.page/coding-style/go.md\">Go</a></li>\n<li><a href=\"https://mmap.page/dive-into/eslint.md\">JavaScript/TypeScript</a></li>\n<li><a href=\"https://mmap.page/coding-style/kotlin.md\">Kotlin</a></li>\n<li><a href=\"https://mmap.page/coding-style/python.md\">Python</a></li>\n<li><a href=\"https://mmap.page/coding-style/ruby.md\">Ruby</a></li>\n<li><a href=\"https://mmap.page/coding-style/sh.md\">Shell</a></li>\n</ul>","date_published":"Sun, 11 Sep 2016 00:46:52 GMT","date_modified":"Mon, 24 Apr 2023 08:23:55 GMT"},{"id":"https://mmap.page/dive-into/make/","url":"https://mmap.page/dive-into/make/","title":"Write Makefile Compatible with Both GNU make and BSD make","content_html":"<h1>Write Makefile Compatible with Both GNU <code>make</code> and BSD <code>make</code></h1>\n<p>BSD make is simple, but GNU make is more popular due to Linux's popularity.\nThus, I prefer to write Makefile compatible with both versions.</p>\n<h2>Syntax</h2>\n<p>The following syntax is valid in both GNU make and BSD make.</p>\n<pre><code class=\"language-make\"><span class=\"pl-k\">include</span> config.mk\n\n<span class=\"pl-c\"># variable declaration (this is a comment)</span>\n<span class=\"pl-smi\">PREFIX</span> = /usr/local\n\n<span class=\"pl-c\"># First target is the default target which will be invoked when typing `make`.</span>\n<span class=\"pl-en\">all</span>: this-is-a-target another-target\n\n<span class=\"pl-en\">this-is-a-target</span>:\n        echo command\n        echo `echo command substitution`\n        @echo not echo the command line to screen\n        -echo keep going even if command returns a nonzero status\n\n<span class=\"pl-en\">another-target</span>: sourcefile\n        echo will only run if sourcefile timestamp is newer\n        echo ${PREFIX}\n</code></pre>\n<h2>BSD vs. GNU</h2>\n<blockquote>\n<p>BSD Make just knows about dependencies, targets, rules and macros.\nGNU Make adds built in rules to that mix to make it easier for the developer.</p>\n<p>It turns out that details of systems are conflicting and cannot be known in advance.\nBSD Make deals with system dependencies by having the system define its parameters.\nGNU Make's built in rules turn out to be inadequate.</p>\n</blockquote>\n<p>-- <a href=\"http://www.cplusplus.com/articles/jTbCpfjN/\">kbw</a></p>\n<blockquote>\n<p>When using <code>bsd.*.mk</code>, each Makefile can build only one program or library.</p>\n<p>...</p>\n<p>The file <code>bsd.port.mk</code> is at the center of FreeBSD Ports,\nthe system that builds software packages for FreeBSD.\n(NetBSD <code>pkgsrc</code> calls this file <code>bsd.pkg.mk</code>.)</p>\n</blockquote>\n<p>-- <a href=\"https://stackoverflow.com/questions/2131219/merits-of-bmake/25152244\">George Koehler</a></p>\n<blockquote>\n<p>Most of openbsds simple Makefiles are compatible with bmake\nbut if it gets a little bit more complicated\nthere are small differences that break the build.</p>\n<p>... the openbsd Makefiles <code>/usr/share/mk</code> ... are  not really portable\nand use openbsd specific binaries like <code>lorder</code> and <code>tsort</code> with the openbsd specific <code>-q</code> flag.</p>\n<p>And most software is using GNU Make,\nI think it would be way more work to use bsd makefiles on linux targets,\nthey are not really written to be portable.</p>\n</blockquote>\n<p>-- <a href=\"https://forum.voidlinux.eu/t/pitfalls-on-bmake-bsd-make/956/2\">Duncaen</a></p>\n<p>Under debian, BSD make is available as the <code>bmake</code> package.\nAnd FreeBSD makefile templates for bmake are available as the <code>freebsd-mk</code> package.</p>\n<h2>Bonus: Plan9 mk</h2>\n<p><code>mk</code> in Plan9 is similar to BSD make, with fewer rules.</p>\n<p>The main difference is templating:</p>\n<ul>\n<li>BSD Makefile supports standard templates <code>.include &#x3C;bsd.prog.mk></code> and nonstandard templates <code>.include \"/path/to/included.mk\"</code> or <code>include filename</code>,</li>\n<li>Plan9 Makefile does not support standard templates, and it uses different syntax for nonstandard templates <code>&#x3C;/path/to/included.mk</code>.</li>\n<li>Plan9 Makefile also supports including command line output (<code>&#x3C;|cat /path/to/included.mk></code>).</li>\n</ul>\n<p>Plan9 also supports using different shells within a single mkfile:</p>\n<pre><code class=\"language-sh\">MKSHELL=/bin/rc\nuse-rc:V:\n    for(i <span class=\"pl-k\">in</span> a b c) <span class=\"pl-c1\">echo</span> <span class=\"pl-smi\">$i</span>\n\nMKSHELL=sh\nuse-sh:V:\n    <span class=\"pl-k\">for</span> <span class=\"pl-smi\">i</span> <span class=\"pl-k\">in</span> a b c<span class=\"pl-k\">;</span> <span class=\"pl-k\">do</span> <span class=\"pl-c1\">echo</span> <span class=\"pl-smi\">$i</span><span class=\"pl-k\">;</span> <span class=\"pl-k\">done</span>\n</code></pre>","date_published":"Tue, 16 Aug 2016 08:03:18 GMT","date_modified":"Tue, 06 Sep 2022 05:05:55 GMT"},{"id":"https://mmap.page/uses/borg/","url":"https://mmap.page/uses/borg/","title":"A Short Borg Tutorial","content_html":"<h1>A Short Borg Tutorial</h1>\n<p><a href=\"https://www.borgbackup.org/\">Borg</a> is the new generation of <a href=\"https://attic-backup.org/\">attic</a>.</p>\n<pre><code class=\"language-sh\">borg init --encryption=keyfile /path/to/repo\nborg create -C lz4 /path/to/repo::NAME-YOUR-BACKUP <span class=\"pl-k\">~</span>/Documents\n</code></pre>\n<h2>Free space</h2>\n<p>Before you start creating backups,\nplease make sure that there is always a good amount of free space\non the filesystem that has your backup repository (and also on ~/.cache).</p>\n<h2>Encryption</h2>\n<p>Default enabled with <code>repokey</code> method.</p>\n<pre><code>borg init --encryption=none|repokey|keyfile PATH\n</code></pre>\n<p>When repository encryption is enabled,\nall data is encrypted using 256-bit AES encryption\nand the integrity and authenticity is verified using HMAC-SHA256.</p>\n<ul>\n<li><code>repokey</code>: key is stored inside the repository (<code>config</code>);</li>\n<li><code>keyfile</code>: key is stored under <code>~/.config/borg/keys/</code>;</li>\n</ul>\n<p>In both modes, the key is stored in encrypted form\nand can be only decrypted by providing the correct passphrase.</p>\n<p>Do not forget to backup the key (e.g. via <code>borg key export</code>).</p>\n<p>For automated backups the passphrase can be specified\nusing the BORG_PASSPHRASE environment variable.</p>\n<p>Be careful how you set the environment;\nusing the env command, a <code>system()</code> call or using inline shell scripts\nmight expose the credentials in the process list directly\nand they will be readable to all users on a system.\nUsing <code>export</code> in a shell script file should be safe, however,\nas the environment of a process is accessible only to that user.\nAlso, using a shell command may leak the passphrase in shell history file.</p>\n<p>For server backup, have a look at <a href=\"https://torsion.org/borgmatic/\">borgmatic</a>.</p>\n<h2>Compression</h2>\n<pre><code>borg create --compression lz4\n</code></pre>\n<p>I prefer <code>lz4</code> since it is very fast.\nIf the repository is on a remote host with slow (dial-up) connection,\nI recommend <code>lzma</code> instead.\nThe default option is no compression.</p>\n<h2>Upgrade from attic</h2>\n<pre><code>borg upgrade --inplace REPOSITORY\n</code></pre>\n<p>If a backup copy is required, omit the <code>--inplace</code> option.</p>\n<h2>Hosted Services</h2>\n<ul>\n<li>\n<p><a href=\"https://www.rsync.net/products/borg.html\">rsync.net</a> supports borg and scp, rsync, git, etc.\nNodes available globally.\nA <code>--remote-path</code> argument with <code>borg14</code>, <code>borg12</code>, or <code>borg0</code> must be specified to use borg with rsync.net.</p>\n</li>\n<li>\n<p><a href=\"https://www.borgbase.com/\">BorgBase</a> is a dedicated borg repository hosting service with specific APIs.\nBesides paid plans with a similar price to rsync.net (cheaper for more than 1TB files),\nit also offers a free plan (10 GB and 2 repos).\nNodes available in US and EU.</p>\n</li>\n<li>\n<p><a href=\"https://www.hetzner.com/storage/storage-box/\">Hetzner</a> Storage Box supports borg, rsync, sftp, scp, rclone, and restic (but not git).\nIts plans are much cheaper than BorgBase or rsync.net but start from 1 TB.</p>\n</li>\n</ul>","date_published":"Sun, 24 Jul 2016 15:49:09 GMT","date_modified":"Tue, 15 Jul 2025 15:16:01 GMT"},{"id":"https://mmap.page/python/persistence/","url":"https://mmap.page/python/persistence/","title":"Python Persistence","content_html":"<h1>Python Persistence</h1>\n<p><strong>This survey is outdated and unmaintained.</strong>\nFor compatibility with other programs,\nI would recommend JSON or SQLite instead.</p>\n<h2>tl;tr</h2>\n<p>If we care about compatibility with different Python versions,\nuse <code>cPickle</code> with binary protocol and <code>fast</code> option.</p>\n<p>Otherwise, just use marshal.</p>\n<h2>Performance</h2>\n<p>A benchmark of marshal, pickle, json, capnp for python 2.7 on my machine.</p>\n<pre><code class=\"language-python\"><span class=\"pl-k\">import</span> timeit\n\nmd <span class=\"pl-k\">=</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>marshal.dumps({'people': [{'name': 'Alice'}]})<span class=\"pl-pds\">\"</span></span>\nim <span class=\"pl-k\">=</span> <span class=\"pl-s\"><span class=\"pl-pds\">'</span>import marshal<span class=\"pl-pds\">'</span></span>\n\np d<span class=\"pl-k\">=</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>pickle.dumps({'people': [{'name': 'Alice'}]})<span class=\"pl-pds\">\"</span></span>\n\nip <span class=\"pl-k\">=</span> <span class=\"pl-s\"><span class=\"pl-pds\">'</span>import cPickle as pickle<span class=\"pl-pds\">'</span></span>\n\njd <span class=\"pl-k\">=</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>json.dumps({'people': [{'name': 'Alice'}]})<span class=\"pl-pds\">\"</span></span>\nij <span class=\"pl-k\">=</span> <span class=\"pl-s\"><span class=\"pl-pds\">'</span>import json<span class=\"pl-pds\">'</span></span>\n\ncd <span class=\"pl-k\">=</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>bm_capnp.AddressBook.new_message(people=[{'name': 'Alice'}])<span class=\"pl-pds\">\"</span></span>\nic <span class=\"pl-k\">=</span> <span class=\"pl-s\"><span class=\"pl-pds\">'</span>import capnp; import bm_capnp<span class=\"pl-pds\">'</span></span>\n\n<span class=\"pl-k\">def</span> <span class=\"pl-en\">benchmark</span>(<span class=\"pl-smi\">d</span>, <span class=\"pl-smi\">i</span>):\n    <span class=\"pl-k\">return</span> timeit.timeit(d, i, <span class=\"pl-v\">number</span><span class=\"pl-k\">=</span><span class=\"pl-c1\">10000</span>)\n\n<span class=\"pl-c\"># Benchmarking</span>\nm <span class=\"pl-k\">=</span> benchmark(md, im)\np <span class=\"pl-k\">=</span> benchmark(pd, ip)\nj <span class=\"pl-k\">=</span> benchmark(jd, ij)\nc <span class=\"pl-k\">=</span> benchmark(cd, ic)\n\n<span class=\"pl-c\"># Output result</span>\noutput <span class=\"pl-k\">=</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span><span class=\"pl-c1\">{name}</span>: <span class=\"pl-c1\">{time}</span><span class=\"pl-pds\">\"</span></span>.format\n\noutput(<span class=\"pl-v\">name</span><span class=\"pl-k\">=</span><span class=\"pl-s\"><span class=\"pl-pds\">'</span>marshal<span class=\"pl-pds\">'</span></span>, <span class=\"pl-v\">time</span><span class=\"pl-k\">=</span>m)\noutput(<span class=\"pl-v\">name</span><span class=\"pl-k\">=</span><span class=\"pl-s\"><span class=\"pl-pds\">'</span>(c)pickle<span class=\"pl-pds\">'</span></span>, <span class=\"pl-v\">time</span><span class=\"pl-k\">=</span>p)\noutput(<span class=\"pl-v\">name</span><span class=\"pl-k\">=</span><span class=\"pl-s\"><span class=\"pl-pds\">'</span>json<span class=\"pl-pds\">'</span></span>, <span class=\"pl-v\">time</span><span class=\"pl-k\">=</span>j)\noutput(<span class=\"pl-v\">name</span><span class=\"pl-k\">=</span><span class=\"pl-s\"><span class=\"pl-pds\">\"</span>Cap'n Proto<span class=\"pl-pds\">\"</span></span>, <span class=\"pl-v\">time</span><span class=\"pl-k\">=</span>c)\n</code></pre>\n<p>Cap'n Proto requires an additional schema file:</p>\n<pre><code class=\"language-capnp\"><span class=\"pl-c1\">@0x934efea7f017fff0</span>;\n\n<span class=\"pl-k\">struct</span> <span class=\"pl-en\">Person</span> {\n  name <span class=\"pl-c1\">@0</span> <span class=\"pl-k\">:Text</span>;\n}\n\n<span class=\"pl-k\">struct</span> <span class=\"pl-en\">AddressBook</span> {\n  people <span class=\"pl-c1\">@0</span> <span class=\"pl-k\">:List(Person)</span>;\n}\n</code></pre>\n<p>Result:</p>\n<pre><code>marshal: 0.08457612991333008\n(c)pickle: 0.31447696685791016\njson: 0.7639560699462891\nCap'n proto: 0.4193081855773926\n</code></pre>\n<p>So marshal seems the fastest on my machine.</p>\n<p>However, with binary protocol and <code>fast</code> option,\n<code>cPickle</code> is mostly as fast as <code>marshal</code>.</p>\n<pre><code class=\"language-python\"><span class=\"pl-k\">>>></span> md <span class=\"pl-k\">=</span> <span class=\"pl-s\"><span class=\"pl-pds\">'</span>marshal.dumps([1, 2, 3])<span class=\"pl-pds\">'</span></span>\n<span class=\"pl-k\">>>></span> im <span class=\"pl-k\">=</span> <span class=\"pl-s\"><span class=\"pl-pds\">'</span>import marshal<span class=\"pl-pds\">'</span></span>\n<span class=\"pl-k\">>>></span> pd <span class=\"pl-k\">=</span> <span class=\"pl-s\"><span class=\"pl-pds\">'</span>fp.dump([1, 2, 3])<span class=\"pl-pds\">'</span></span>\n<span class=\"pl-k\">>>></span> ip <span class=\"pl-k\">=</span> <span class=\"pl-s\"><span class=\"pl-pds\">\"</span>import cPickle; fp = cPickle.Pickler(open('/tmp/1', 'wb'), 2); fp.fast = 1<span class=\"pl-pds\">\"</span></span>\n<span class=\"pl-k\">>>></span> timeit.timeit(md, im, <span class=\"pl-v\">number</span><span class=\"pl-k\">=</span><span class=\"pl-c1\">1000</span>)\n<span class=\"pl-c1\">0.012997150421142578</span>\n<span class=\"pl-k\">>>></span> timeit.timeit(pd, ip, <span class=\"pl-v\">number</span><span class=\"pl-k\">=</span><span class=\"pl-c1\">1000</span>)\n<span class=\"pl-c1\">0.017292022705078125</span>\n</code></pre>\n<h2>Compatibility</h2>\n<h3>Compatibility with different Python versions</h3>\n<p>Marshal is for internal usage (<code>.pyc</code>).\nSo its format may be modified on future versions of Python.\nCurrently (up to Python 3.4.3), there are 4 versions of <code>marshal</code>.\nThe current version can be viewed via <code>marshal.version</code>.</p>\n<h3>Compatibility with other languages</h3>\n<p>Implemented in other languages:</p>\n<ul>\n<li>Ruby: <a href=\"http://github.com/daeken/RMarshal\">RMarshal</a></li>\n<li>Go: <a href=\"https://github.com/hambster/gopymarshal\">gopymarshal</a></li>\n<li>Perl: (read-only) <a href=\"https://github.com/gitpan/Python-Serialise-Marshal\">https://github.com/gitpan/Python-Serialise-Marshal</a></li>\n</ul>\n<h2>Export to JSON</h2>\n<p>To communicate with other programs,\nwe can export to JSON.</p>\n<p>On Python 2.7+, the <code>json</code> module from <code>stdlib</code>\nis <a href=\"http://stackoverflow.com/a/15440843\">fast in encoding and decoding JSON</a>.\nNo need to use other modules.</p>","date_published":"Tue, 12 Apr 2016 13:56:34 GMT","date_modified":"Mon, 05 Sep 2022 10:56:44 GMT"},{"id":"https://mmap.page/dapi/chengshuxianhou/","url":"https://mmap.page/dapi/chengshuxianhou/","title":"如何考察成书先后","content_html":"<h1>如何考察成书先后</h1>\n<p>一般而言，在不考虑出土文献的前提下，判断整本书的先后：</p>\n<ol>\n<li>确定了时代的书籍（多为目录类）对两书成书情况的记载。</li>\n<li>从用字、语法、文风等语言学特征判断。</li>\n<li>考证作者年代先后。</li>\n<li>从涉及的史实（包括具体的历史事件，以及某一时代的思潮风尚）来判断。</li>\n<li>其他确定了时代的书对这两种书的征引的情况。</li>\n</ol>\n<p>两本书中某段内容的先后，不一定符合两本书的先后，例如：</p>\n<p>I. A 书比 B 书时代早，但是 A 中的某段内容其实是后人根据 B 补的（这又包括 A 本来有这段内容或类似这段的内容，但是后来残缺了，于是后人拿 B 中的段落去补，以及 A 本来根本没有类似内容，但是后人为了使 A 更全等原因，拿 B 中的内容去补）。\nII. A 和 B 其实都是抄了更早的 C。\nIII. A 抄了 C，B 抄了 D。</p>\n<p>对于 I. 上述判断整本书时代的方法同样适用</p>\n<ol>\n<li>确定了时代的书籍记载了后人补 A 的情况，或者记载了到某时 A 中的某部分已经亡佚了，目标段落恰巧在亡佚的部分</li>\n<li>同前</li>\n<li>确定作者有助于限定范围，例如某时代的作者不可能写出目标段落</li>\n<li>同前</li>\n<li>考察对目标段落的征引情况</li>\n<li>目标段落和全书的吻合程度</li>\n<li>目标段落在两书中的比较</li>\n</ol>\n<p>7 比较复杂一点，比如 A 详细, B 简略，这有两种情况：</p>\n<p>7.1 B 早 A 晚，A 在 B 的基础上添油加醋\n7.2 A 早 B 晚，B  概括了 A 的记载</p>\n<p>这个判断就比较复杂，要考虑多种因素，写出来太多了。</p>\n<p>举一个例子：</p>\n<p>A 简略记载了 X 国 Y 地 M 做了某件丑事。\nB 详细记载了 X 国的 M 做丑事的具体经过，对话乃至心理活动，但是没提到 Y 地。</p>\n<p>假设 A 概括了 B，那么 B 没有记载 Y，A 从何得知 Y 地呢？ 除非 A 从 C 中得知了，这个属于 II，这里不讨论。如果说 A 添油加醋，何以其他细节都省略，唯独加了 Y 地？除非有其他因素（例如 A 的作者讨厌 Y 地的人，所以有意把这件记载安到 Y 地，或者 B 的作者是 Y 地的人，为家乡讳，省略了 Y 地），我们不倾向 A 概括了 B 。</p>\n<p>然后我们考虑 B 添油加醋了 A，然后发现 B 具体描述了经过，能更好的说明 B 中的主张，那么省略 Y 地这一细节的记载很可能就是 B 的作者认为 Y 地这一细节没什么用。</p>\n<p>由此我们倾向 B 晚于 A。当然有可能是 B 抄 A 的时候漏掉了 Y 地 两个字，或者是后人传抄 B 的时候漏掉了。但是类似的倾向性证据搜集多了就能说明问题了。</p>\n<p>II 的话：</p>\n<p>如果 C 还在，且其年代确定，那就没什么好讨论的了。</p>\n<p>如果 C 在，但年代不确定，那么应用 1-5 于 A、 B、 C</p>\n<p>如果 C 已经亡佚，或不确定有 C 存在：</p>\n<ol>\n<li>确定了时代的书籍记载了A 或 B 抄 C 的情况</li>\n<li>若语言学分析的结果是目标段落和 A 与 B 的成书年代皆不合，反而体现了早于两者的时代特征</li>\n<li>同前</li>\n<li>同前</li>\n<li>同前，引用目标段落而不标 A、B，反而标明了 C 的情况。</li>\n</ol>\n<p>III. 将以上方法类推到 C 和 D 的考察中。</p>\n<hr>\n<p>以上是一般的方法。对于先秦两汉的古籍，考察其年代，首先要有“别本单行”的意识：最早是单篇，现在看到的都是后人编的。比如《莊子》和《列子》就都是后人编集的。</p>\n<p>余嘉锡《古书通例》云：“古人著书，本无专集，往往随作数篇，即以行世。传其学者各以所得，爲题书名”，“虽其平日因人事之肆应，作爲书疏论说，亦所以发明其学理，语百变而不离其宗，承其学者，聚而编之，又以其所见闻，及后师之所讲习，相与发明其义者，附入其中，以成一家之学。故西汉以前无文集，而诸子即其文集。非其文不美也，以其爲微言大义之所托，言之有物，不徒藻绘其字句而已”，“其书不作于一时，其先后亦都无次第。随时所作，即以行世”。</p>\n<p>所以先秦两汉的书，不便笼统地讲时代，需分出：</p>\n<p>一、 我们现在看到的版本，是什么时候定型的？\n二、 这书最早的胚胎，大约是什么时候出来的？</p>\n<p>然后对具体的段落的年代，只能参考一和二，不能直接套用结论，很可能还要再考察。</p>\n<p>由于先秦两汉的书成书情况的特征，出土文献还是最简便、最直接的方法。</p>","date_published":"Mon, 11 May 2015 09:43:00 GMT","date_modified":"Sat, 23 Nov 2019 19:11:50 GMT"},{"id":"https://mmap.page/dapi/bidouxiangzao/","url":"https://mmap.page/dapi/bidouxiangzao/","title":"跋貴妃的紅汗","content_html":"<h1>跋貴妃的紅汗</h1>\n<p>孟晖. 2010-08-01. 贵妃的红汗[M]. 南京: 南京大学出版社. ISBN 9787305075278</p>\n<blockquote>\n<p>《肘後備急方》...也記有「蓽豆香藻法」...從配料與製作程序來看，這裏所介紹的也是一種比較簡單的澡豆。「藻」乃「澡」字之誤。 (pp. 4-5)</p>\n</blockquote>\n<p>案「藻」不誤。\n「藻」有「藻飾」義。\n此引《肘後備急方》「蓽豆香藻法」，末云「粉飾之也」，「粉飾」即「藻飾」。</p>\n<p>【附記】已提交給作者，作者已知悉。</p>","date_published":"Sun, 04 Jan 2015 14:36:12 GMT","date_modified":"Sat, 23 Nov 2019 19:11:50 GMT"},{"id":"https://mmap.page/dapi/xiaochuang/","url":"https://mmap.page/dapi/xiaochuang/","title":"跋兩晉至唐靈座靈牀漫談","content_html":"<h1>跋兩晉至唐靈座靈牀漫談</h1>\n<p>靈牀之大小，《兩晉至唐靈座靈牀漫談》引《宋書·王微傳》「五尺牀」，主張五尺之牀難爲臥具，又引《陳書·姚察傳》、《謝貞傳》以「小牀」作靈牀之文。</p>\n<p>案：《梁書》卷五二云「朔望祥忌，可權安小牀」，亦以小牀爲靈牀。且唐以前之小牀亦非臥具，《北史》卷四八「御牀西北小牀上南坐」，《舊唐書》卷一八六「各危坐於小牀」，《御覽》卷三九三引《晉中興書》云陶淡「設小床獨坐不與人共」，皆其證。（宋以後則小牀多指臥具。）唯《宋書》之「五尺牀」，《陳書》、《梁書》之「小牀」，傳主皆尚儉，故常禮或非盡以小牀爲靈牀。如《文選》陸機《弔魏武帝文》云魏武帝《遺令》以「八尺牀」（《御覽》、《類聚》引作「六尺牀」，恐爲形訛，宋趙如燧《野谷詩稿·銅雀臺辭》云「明月空照八尺牀」，亦作「八尺」。）爲靈牀。</p>\n<h2>參考文獻</h2>\n<p>王寧玲. 兩晉至唐靈座靈牀漫談[M]. 《文教資料》,2012(34).</p>","date_published":"Fri, 10 May 2013 13:54:56 GMT","date_modified":"Sat, 23 Nov 2019 19:11:50 GMT"},{"id":"https://mmap.page/dapi/lunyu-huijiaojishi/","url":"https://mmap.page/dapi/lunyu-huijiaojishi/","title":"跋論語彙校集釋","content_html":"<h1>跋論語彙校集釋</h1>\n<p>論語彙校集釋. 黃懷信主撰. 周海生,孔德立參撰. 上海:上海古籍出版社2008年8月. ISBN 978-7-5325-4675-6</p>\n<p>論語原文以唐開成石經本爲底本。</p>\n<p>彙校先明各舊本異同，次列各家舊校，後加案語。舊本中，敦煌諸唐寫本《論語》殘卷據《敦煌論語集解校證》，而日本正平刊本《論語集解》據《四部叢刊》本。案《四部叢刊》本實據正平刊本影寫本影印，不僅字形走樣，還有異文和誤字。</p>\n<p>集釋錄各家舊說大體以時代早晚爲序，一般不取重複，凡訓說相同者取最早一家。</p>\n<p>散見於清人著作中的相關論說亦摘要輯取，然其涉獵，區區二十種而已，恐難稱備。</p>\n<p>至於「懷信案」部分，余不敏，不能置一詞。</p>\n<p>本書彙校，頗為粗疏，余略為翻檢，即為之瞠目，茲臚列如左：</p>\n<p>巻三 八侑第三</p>\n<p>p262 子曰：「賜也！爾愛其羊，我愛其禮。」</p>\n<p>案：開成石經「爾」作「女」。且下「彙校」出「女愛其羊」四字。</p>\n<p>巻十 鄉黨第十</p>\n<p>p930 疾，君視之，東首，加朝服，拖紳。</p>\n<p>案：開成石經「拖」作「扡」。且下「彙校」出「扡紳」二字。似非偶然，疑用別本作工作底本。</p>\n<p>巻十一 先進第十一</p>\n<p>子張問善人之道。子曰：「不踐迹，亦不入於室。」</p>\n<p>案：敦斯3011號寫本句末有「也」字。「彙校」失校。</p>\n<p>巻十五 衛靈公第十五</p>\n<p>p1416 曰：「吾人於人也，誰毀誰譽？如有所譽者，其有所試矣。</p>\n<p>案：當作「吾之於人也」。且下「彙校」出「吾之於人也」五字。</p>\n<p>巻十四 憲問第十四</p>\n<p>p1284 豈若匹夫匹婦之為諒也，自經於溝瀆而莫之知也？</p>\n<p>案：「彙校」部分所引崔灝《四書考異》文字，不屬校勘。</p>\n<p>巻五 公冶長第五</p>\n<p>p4110-412 子貢曰：「夫子之文章，可得而聞也。夫子之言性與天道，不可得而聞也。」</p>\n<p>案：「不可得而聞也」，高麗本「也」下有「矣」字，阮元校勘記中有，「彙校」中沒有吸收。而且「彙校」中引用的錢曾《讀書敏求記》、馮登府《論語異文考證》中都提到了高麗本。</p>\n<p>巻十四 憲問第十四</p>\n<p>p1256 子路問成人。子曰：「若臧武仲之知，公綽之不欲，卞莊子之勇，冉求之藝，文之以禮樂，亦可以為成人矣！」</p>\n<p>案：「若臧武仲之知」，皇本、高麗本「知」作「智」，阮元校勘記中有，「彙校」中沒有吸收。「彙校」云天文本作「智」，然《天文本單經論語校勘記》中無此條。「彙校」云伯2579號作「智」，案2579爲2597之誤。</p>\n<p>卷十七 陽貨第十七</p>\n<p>p1518 子曰：「唯上知與下愚不移。」</p>\n<p>案：皇本「知」作「智」，阮元校勘記失校，「彙校」承其誤。</p>\n<p>p1567 子曰：「鄙夫可與事君也與哉？其未得之也，患得之；旣得之，患失之。茍患失之，無所不至矣！」</p>\n<p>案：高麗本「未得之」後無「也」字，，阮元校勘記中有，「彙校」中沒有吸收。</p>\n<p>卷十八 微子第十八</p>\n<p>p1651 周公謂魯公曰：「君子不施其親，不使大臣怨乎不以。故舊無大故，則不棄也。無求備於一人。」</p>\n<p>案：「無求備於一人」，「彙校」出「無求備於一人」。且正平本「無」作「毋」，「彙校」失載。</p>\n<p>卷二十 堯曰第二十</p>\n<p>p1728 謹權量，審法度，修廢官，四方之政行焉。</p>\n<p>案：開成石經「修」作「脩」。且下「彙校」出「脩廢官」三字。另「彙校」云高麗本作「修」，案阮校高麗本作「脩」。</p>\n<p>p1744 「彙校」出內之咎</p>\n<p>案：天文本同，「彙校」失校。</p>\n<p>巻十二 顏淵第十二</p>\n<p>p1121 季康子問政於孔子曰：「如殺無道，以就有道，何如？」孔子對曰：「子為政，焉用殺？子欲善，而民善矣！君子之德風；小人之德草；草上之風，必偃。」</p>\n<p>案：「彙校」部分「君子之德風小人之德草」一條「伯2402號」當爲「伯3402號」。</p>\n<p>定州簡本失校的情況我後來也發現了兩處，因書不在手邊，故不列出。</p>","date_published":"Sun, 10 Mar 2013 13:15:18 GMT","date_modified":"Sat, 23 Nov 2019 19:11:50 GMT"},{"id":"https://mmap.page/poems/resentment-in-boudoir/","url":"https://mmap.page/poems/resentment-in-boudoir/","title":"閨怨","content_html":"<h1>閨怨</h1>\n<pre><code>幼曾鈔女誡，\n長亦畏豬籠。\n敗柳庭前落，\n出牆杏正紅。\n</code></pre>\n<p>composed at 2012-12-23</p>","date_published":"Sun, 23 Dec 2012 14:16:00 GMT","date_modified":"Sat, 23 Nov 2019 19:28:41 GMT"},{"id":"https://mmap.page/poems/southern-opera/","url":"https://mmap.page/poems/southern-opera/","title":"南曲","content_html":"<h1>南曲</h1>\n<p>【水底魚】伐芥為舟，鵲閒鴻鴈休。千重山近，瞬目間四秋。涸轍鮒幸，晤莊生<small>立地</small>獲救。縫腸半朽，半朽<small>怎生</small>飴悍鷲？</p>\n<p>composed at 2012-05-21</p>","date_published":"Mon, 21 May 2012 10:24:09 GMT","date_modified":"Sat, 23 Nov 2019 19:28:41 GMT"},{"id":"https://mmap.page/dapi/daoliangmou/","url":"https://mmap.page/dapi/daoliangmou/","content_html":"<p>粱謂粟之精良者，北地產稻稀少，二者皆不易得，故古人往往以稻粱連稱。是「稻粱謀」非同於「餬口」也。今粱、稻皆易得，則時移世易矣！</p>","date_published":"Mon, 21 May 2012 01:12:43 GMT","date_modified":"Sat, 23 Nov 2019 19:11:50 GMT"},{"id":"https://mmap.page/dapi/redman/","url":"https://mmap.page/dapi/redman/","title":"赤狄","content_html":"<h1>赤狄</h1>\n<p>廣瀨淡窗《送人遊宦長崎》（文化五、六年作）中有「赤狄情難測」一句，自注曰：「近來赤人申請互市。」岡村繁注謂赤狄乃俄羅斯人，此句指文化元年(1804)九月，俄羅斯船進長崎，俄羅斯使萊薩諾夫申請互市之事。(岡村繁著、俞慰慈譯《江戶漢詩選注》，見岡村繁全集第八卷《毛詩正義注疏選箋（外二種）》第526-527頁，上海：上海古籍出版社2009年6月，ISBN 978-7-5325-5110-1）</p>","date_published":"Tue, 15 May 2012 11:47:57 GMT","date_modified":"Sat, 23 Nov 2019 19:11:50 GMT"},{"id":"https://mmap.page/dapi/hezhe/","url":"https://mmap.page/dapi/hezhe/","title":"跋中國語言學論文集","content_html":"<h1>跋中國語言學論文集</h1>\n<p>我看到其中的《國語中雙聲節並列語兩成分間的聲調關係》一文(pp. 299-314)的時候，有一種熟悉感，難道說我以前在別的地方看到過這篇文章？</p>\n<p>最近翻查檢索書籍的時候，無意中找到了。原來余嘉錫的《世說新語箋疏》中有相關的論述，我原來看到過，難怪感覺熟悉呢！</p>\n<p>《世說·排調》載：「諸葛令、王丞相共爭姓族先後，王曰：『何不言葛、王，而云王、葛？』令曰：『譬言驢馬，不言馬驢，驢寧勝馬邪？』」余嘉錫《箋疏》謂：「凡以二名同言者，如其字平仄不同，而非有一定之先後，如夏商、孔顏之類。則必以平聲居先，仄聲居後，此乃順乎聲音之自然，在未有四聲之前，固已如此。故言王、葛驢馬，不言葛、王馬驢，本不以先後為勝負也。如公穀、蘇李、嵇阮、潘陸、邢魏、徐庾、燕許、王孟、韓柳、元白、溫李之屬皆然。」(1983)</p>\n<p>丁氏此文最早發表在1969年的《史語所集刊》39卷2期(pp. 155-147)上。而《世說新語箋疏》為余嘉錫先生遺著，余先生1955年去世後，由周祖謨等整理成書，因故出版一再拖延，1983年方由中華書局出版。余、丁二人各自注意到此問題，看法亦相近，所謂「閉門造車，出門合轍」，殆此之謂歟。（丁氏關注的範圍較廣，不僅僅限於人名並列，也不僅僅限於平先仄後的情形。但是其文第二部份《本論》首先就討論姓氏並列語的問題，其旨趣和余氏相近。）</p>\n<p>引用文獻</p>\n<p>余嘉錫. 1983. 世說新語箋疏[M]. 北京:中華書局:791-792</p>","date_published":"Sat, 12 May 2012 11:38:22 GMT","date_modified":"Sat, 23 Nov 2019 19:11:50 GMT"},{"id":"https://mmap.page/dapi/lunyu-zhengzhu/","url":"https://mmap.page/dapi/lunyu-zhengzhu/","title":"跋唐寫本論語鄭氏注及其研究","content_html":"<h1>跋唐寫本論語鄭氏注及其研究</h1>\n<p>王素. 唐寫本論語鄭氏注及其研究[M]. 北京:文物出版社,1991年11月. ISBN 7-5010-0503-6</p>\n<p>分上下两卷。上卷爲鄭注校錄，據現已發現之唐寫本，恢復半部《鄭注》的原貌。下卷收入王氏所撰相關論文，兼收早期、近期國內外相關論文。</p>\n<p>榮新江《鳴沙集》中有《唐寫本論語鄭氏注及其研究拾遺》一文，增校此書未收之唐鈔本殘片三件。後新出吐魯番文書又有《堯曰》殘篇一片，王氏《吐鲁番新出闞氏王国〈論語鄭氏注〉寫本補說》以爲亦是鄭注，文見《文物》2007年第11期。另，據儒藏精華編目錄，第281冊收有《唐寫本論語鄭氏注》一書。</p>","date_published":"Thu, 03 May 2012 16:56:08 GMT","date_modified":"Sat, 23 Nov 2019 19:11:50 GMT"},{"id":"https://mmap.page/dapi/zuozhuan_guo-jue-ming/","url":"https://mmap.page/dapi/zuozhuan_guo-jue-ming/","title":"左傳春秋經國加爵加名之用例","content_html":"<h1>左傳春秋經國加爵加名之用例</h1>\n<p>下表羅列了春秋經中「國（或部族）+爵+名」這一類的全部用例。標註年數以及楊伯峻《春秋左傳注》的小節數、頁數。本表據楊伯峻《春秋左傳詞典》編製。</p>\n<table>\n<thead>\n<tr>\n<th>人名</th>\n<th>位置</th>\n<th>用例及備註</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>戎蠻子赤</td>\n<td>哀4/6/1625</td>\n<td>晉人執戎蠻子赤歸于楚 公羊作曼</td>\n</tr>\n<tr>\n<td>吳子乘</td>\n<td>襄12/4/995</td>\n<td>吳子乘卒</td>\n</tr>\n<tr>\n<td>吳子遏</td>\n<td>襄25/10/1095</td>\n<td>吳子遏伐楚 公羊、榖梁作謁。據左傳，吳子卒於是役。</td>\n</tr>\n<tr>\n<td>吳子夷末</td>\n<td>昭15/1/1368</td>\n<td>吳子夷末卒 公羊作夷昧</td>\n</tr>\n<tr>\n<td>吳子光</td>\n<td>定14/5/1593</td>\n<td>吳子光卒</td>\n</tr>\n<tr>\n<td>吳子餘祭</td>\n<td>襄29/4/1153</td>\n<td>閽弑吳子餘祭</td>\n</tr>\n<tr>\n<td>宋公佐</td>\n<td>昭25/7/1455</td>\n<td>宋公佐卒于曲棘</td>\n</tr>\n<tr>\n<td>宋公茲父</td>\n<td>僖23/2/401</td>\n<td>宋公茲父卒</td>\n</tr>\n<tr>\n<td>宋公成</td>\n<td>昭10/6/1314</td>\n<td>宋公成卒</td>\n</tr>\n<tr>\n<td>宋公王臣</td>\n<td>文7/4/554</td>\n<td>宋公王臣卒</td>\n</tr>\n<tr>\n<td>宋公鮑</td>\n<td>成2/5/785</td>\n<td>宋公鮑卒</td>\n</tr>\n<tr>\n<td>宋公馮</td>\n<td>莊2/5/159</td>\n<td>宋公馮卒</td>\n</tr>\n<tr>\n<td>宋公御說</td>\n<td>僖9/1/323</td>\n<td>宋公御說卒 公羊、榖梁作禦</td>\n</tr>\n<tr>\n<td>宋公固</td>\n<td>成15/5/871</td>\n<td>宋公固卒</td>\n</tr>\n<tr>\n<td>宋公和</td>\n<td>隱3/5/25</td>\n<td>宋公和卒</td>\n</tr>\n<tr>\n<td>杞伯姑容</td>\n<td>襄6/1/945</td>\n<td>杞伯姑容卒</td>\n</tr>\n<tr>\n<td>杞伯益姑</td>\n<td>昭6/1/1273</td>\n<td>杞伯益姑卒</td>\n</tr>\n<tr>\n<td>杞伯郁釐</td>\n<td>昭24/5/1449</td>\n<td>杞伯郁釐卒</td>\n</tr>\n<tr>\n<td>杞伯匄</td>\n<td>襄23/2/1071</td>\n<td>杞伯匄卒</td>\n</tr>\n<tr>\n<td>杞伯成</td>\n<td>定4/5/1533</td>\n<td>杞伯成卒于會</td>\n</tr>\n<tr>\n<td>杞伯過</td>\n<td>哀8/6/1646</td>\n<td>杞伯過卒</td>\n</tr>\n<tr>\n<td>沈子逞</td>\n<td>昭23/7/1440</td>\n<td>沈子逞滅 公羊作楹，榖梁作盈</td>\n</tr>\n<tr>\n<td>沈子嘉</td>\n<td>定4/3/1533</td>\n<td>以沈子嘉歸，殺之</td>\n</tr>\n<tr>\n<td>胡子豹</td>\n<td>定15/3/1599</td>\n<td>以胡子豹歸</td>\n</tr>\n<tr>\n<td>胡子髡</td>\n<td>昭23/7/1440</td>\n<td>胡子髡、沈子逞滅</td>\n</tr>\n<tr>\n<td>邾子蘧蒢</td>\n<td>文13/3/593</td>\n<td>邾子蘧蒢卒 公羊、榖梁作籧篨</td>\n</tr>\n<tr>\n<td>邾子益</td>\n<td>哀8/4/1646</td>\n<td>歸邾子益于邾</td>\n</tr>\n<tr>\n<td>邾子牼</td>\n<td>襄17/1/1029</td>\n<td>邾子牼卒 公羊、榖梁作瞷</td>\n</tr>\n<tr>\n<td>邾子穿</td>\n<td>定3/2/1530</td>\n<td>邾子穿卒</td>\n</tr>\n<tr>\n<td>邾子貜且</td>\n<td>成17/12/896</td>\n<td>邾子貜且卒</td>\n</tr>\n<tr>\n<td>邾子瑣</td>\n<td>莊28/2/238</td>\n<td>邾子瑣卒</td>\n</tr>\n<tr>\n<td>邾子華</td>\n<td>昭1/5/1198</td>\n<td>邾子華卒</td>\n</tr>\n<tr>\n<td>晉侯重耳</td>\n<td>僖32/4/488</td>\n<td>晉侯重耳卒</td>\n</tr>\n<tr>\n<td>晉侯彪</td>\n<td>昭10/4/1313</td>\n<td>晉侯彪卒</td>\n</tr>\n<tr>\n<td>晉侯夷吾</td>\n<td>僖24/5/412</td>\n<td>晉侯夷吾卒</td>\n</tr>\n<tr>\n<td>晉侯獳</td>\n<td>成10/5/847</td>\n<td>晉侯獳卒</td>\n</tr>\n<tr>\n<td>晉侯去疾</td>\n<td>昭30/2/1505</td>\n<td>晉侯去疾卒</td>\n</tr>\n<tr>\n<td>晉侯周</td>\n<td>襄15/7/1021</td>\n<td>晉侯周卒</td>\n</tr>\n<tr>\n<td>晉侯驩</td>\n<td>文6/4/543</td>\n<td>晉侯驩卒</td>\n</tr>\n<tr>\n<td>晉侯黑臀</td>\n<td>宣9/9/700</td>\n<td>晉侯黑臀卒于扈</td>\n</tr>\n<tr>\n<td>晉侯夷</td>\n<td>昭16/4/1375</td>\n<td>晉侯夷卒</td>\n</tr>\n<tr>\n<td>晉侯佹諸</td>\n<td>僖9/5/324</td>\n<td>晉侯佹諸卒</td>\n</tr>\n<tr>\n<td>秦伯罃</td>\n<td>文18/2/628</td>\n<td>秦伯罃卒</td>\n</tr>\n<tr>\n<td>秦伯稻</td>\n<td>宣4/2/676</td>\n<td>秦伯稻卒</td>\n</tr>\n<tr>\n<td>曹伯射姑</td>\n<td>莊23/9/225</td>\n<td>曹伯射姑卒</td>\n</tr>\n<tr>\n<td>曹伯壽</td>\n<td>宣14/2/753</td>\n<td>曹伯壽卒</td>\n</tr>\n<tr>\n<td>曹伯須</td>\n<td>昭18/1/1393</td>\n<td>曹伯須卒</td>\n</tr>\n<tr>\n<td>曹伯襄</td>\n<td>僖28/20/451</td>\n<td>曹伯襄復歸于曹 文9/10/571 曹伯襄卒</td>\n</tr>\n<tr>\n<td>曹伯滕</td>\n<td>昭14/2/1363</td>\n<td>曹伯滕卒</td>\n</tr>\n<tr>\n<td>曹伯負芻</td>\n<td>襄18/5/1035</td>\n<td>曹伯負芻卒于師</td>\n</tr>\n<tr>\n<td>曹伯盧</td>\n<td>成13/4/859</td>\n<td>曹伯盧卒于師 公羊、榖梁作廬</td>\n</tr>\n<tr>\n<td>曹伯終生</td>\n<td>桓10/1/127</td>\n<td>曹伯終生卒</td>\n</tr>\n<tr>\n<td>曹伯班</td>\n<td>僖7/5/315</td>\n<td>曹伯班 公羊作般</td>\n</tr>\n<tr>\n<td>曹伯露</td>\n<td>定8/5/1562</td>\n<td>曹伯露卒</td>\n</tr>\n<tr>\n<td>曹伯陽</td>\n<td>哀8/1/1646</td>\n<td>以曹伯陽歸</td>\n</tr>\n<tr>\n<td>曹伯午</td>\n<td>昭27/6/1481</td>\n<td>曹伯午卒</td>\n</tr>\n<tr>\n<td>莒子朱</td>\n<td>成14/1/867</td>\n<td>莒子朱卒</td>\n</tr>\n<tr>\n<td>莒子去疾</td>\n<td>昭14/5/1363</td>\n<td>莒子去疾卒</td>\n</tr>\n<tr>\n<td>莒子庚輿</td>\n<td>昭23/6/1440</td>\n<td>莒子庚輿來奔</td>\n</tr>\n<tr>\n<td>莒子狅</td>\n<td>哀14/8/1681</td>\n<td>莒子狅卒</td>\n</tr>\n<tr>\n<td>許男成</td>\n<td>哀13/2/1674</td>\n<td>許男成卒 公羊作戌</td>\n</tr>\n<tr>\n<td>許男甯</td>\n<td>襄26/8/1111</td>\n<td>許男甯卒于楚</td>\n</tr>\n<tr>\n<td>許男斯</td>\n<td>定6/1/1555</td>\n<td>以許男斯歸</td>\n</tr>\n<tr>\n<td>許男新臣</td>\n<td>僖4/2/287</td>\n<td>許男新臣卒</td>\n</tr>\n<tr>\n<td>許男業</td>\n<td>文5/7/538</td>\n<td>許男業卒</td>\n</tr>\n<tr>\n<td>許男錫我</td>\n<td>宣17/1/770</td>\n<td>許男錫我卒</td>\n</tr>\n<tr>\n<td>陳侯朔</td>\n<td>文13/2/593</td>\n<td>陳侯朔卒</td>\n</tr>\n<tr>\n<td>陳侯柳</td>\n<td>定8/9/1562</td>\n<td>陳侯柳卒</td>\n</tr>\n<tr>\n<td>陳侯午</td>\n<td>襄4/1/931</td>\n<td>陳侯午卒</td>\n</tr>\n<tr>\n<td>陳侯溺</td>\n<td>昭8/2/1299</td>\n<td>陳侯溺卒</td>\n</tr>\n<tr>\n<td>陳侯杵臼</td>\n<td>僖12/4/340</td>\n<td>陳侯杵臼卒 公羊作處臼</td>\n</tr>\n<tr>\n<td>陳侯林</td>\n<td>莊1/5/156</td>\n<td>陳侯林卒</td>\n</tr>\n<tr>\n<td>陳侯躍</td>\n<td>桓12/4/133</td>\n<td>陳侯躍卒</td>\n</tr>\n<tr>\n<td>陳侯款</td>\n<td>僖28/12/450</td>\n<td>陳侯款卒</td>\n</tr>\n<tr>\n<td>陳侯鮑</td>\n<td>桓5/1/102</td>\n<td>陳侯鮑卒</td>\n</tr>\n<tr>\n<td>陳侯吳</td>\n<td>昭13/8/1343</td>\n<td>陳侯吳歸于陳 定4/1/1533 陳侯吳卒</td>\n</tr>\n<tr>\n<td>楚子旅</td>\n<td>宣18/5/776</td>\n<td>楚子旅卒 榖梁作呂</td>\n</tr>\n<tr>\n<td>楚子審</td>\n<td>襄13/3/998</td>\n<td>楚子審卒</td>\n</tr>\n<tr>\n<td>楚子昭</td>\n<td>襄28/9/1139</td>\n<td>楚子昭卒</td>\n</tr>\n<tr>\n<td>楚子麇</td>\n<td>昭1/10/1199</td>\n<td>楚子麇卒 公羊、榖梁作卷</td>\n</tr>\n<tr>\n<td>楚子虔</td>\n<td>昭11/3/1321</td>\n<td>楚子虔誘蔡侯般殺之于申</td>\n</tr>\n<tr>\n<td>楚子居</td>\n<td>昭26/6/1469</td>\n<td>楚子居卒</td>\n</tr>\n<tr>\n<td>楚子軫</td>\n<td>哀6/6/1632</td>\n<td>楚子軫卒</td>\n</tr>\n<tr>\n<td>頓子牂</td>\n<td>定14/2/1593</td>\n<td>以頓子牂歸 公羊作牄</td>\n</tr>\n<tr>\n<td>齊侯小白</td>\n<td>僖17/5/372</td>\n<td>齊侯小白卒</td>\n</tr>\n<tr>\n<td>齊侯無野</td>\n<td>成9/7/841</td>\n<td>齊侯無野卒</td>\n</tr>\n<tr>\n<td>齊侯杵臼</td>\n<td>哀5/4/1629</td>\n<td>齊侯杵臼卒 公羊作處臼</td>\n</tr>\n<tr>\n<td>齊侯昭</td>\n<td>僖27/2/442</td>\n<td>齊侯昭卒</td>\n</tr>\n<tr>\n<td>齊侯祿父</td>\n<td>桓14/6/139</td>\n<td>齊侯祿父卒</td>\n</tr>\n<tr>\n<td>齊侯潘</td>\n<td>文14/3/600</td>\n<td>齊侯潘卒</td>\n</tr>\n<tr>\n<td>齊侯元</td>\n<td>宣10/5/704</td>\n<td>齊侯元卒</td>\n</tr>\n<tr>\n<td>齊侯環</td>\n<td>襄19/7/1044</td>\n<td>齊侯環卒 公羊作瑗</td>\n</tr>\n<tr>\n<td>齊侯陽生</td>\n<td>哀10/3/1654</td>\n<td>齊侯陽生卒</td>\n</tr>\n<tr>\n<td>潞子嬰兒</td>\n<td>宣15/3/758</td>\n<td>以潞子嬰兒歸</td>\n</tr>\n<tr>\n<td>滕子嬰齊</td>\n<td>僖19/1/379</td>\n<td>宋人執滕子嬰齊</td>\n</tr>\n<tr>\n<td>滕子原</td>\n<td>昭3/1/1231</td>\n<td>滕子原卒 公羊作泉</td>\n</tr>\n<tr>\n<td>滕子寧</td>\n<td>昭28/5/1490</td>\n<td>滕子寧卒</td>\n</tr>\n<tr>\n<td>滕子結</td>\n<td>哀4/9//1625</td>\n<td>滕子結卒</td>\n</tr>\n<tr>\n<td>滕子虞毋</td>\n<td>哀11/4/1657</td>\n<td>滕子虞毋卒</td>\n</tr>\n<tr>\n<td>榖伯綏</td>\n<td>桓7/2/118</td>\n<td>榖伯綏來朝 左傳：名，賤之也。公羊、榖梁以為乃失地之君，故書其名，楊《注》駁之。</td>\n</tr>\n<tr>\n<td>蔡侯申</td>\n<td>宣17/2/770</td>\n<td>蔡侯申卒 蔡文公</td>\n</tr>\n<tr>\n<td>蔡侯廬</td>\n<td>昭13/8/1343</td>\n<td>蔡侯廬歸于蔡 昭20/5/1406 蔡侯廬卒</td>\n</tr>\n<tr>\n<td>蔡侯申</td>\n<td>哀4/1/1624</td>\n<td>盜殺蔡侯申 蔡昭公</td>\n</tr>\n<tr>\n<td>蔡侯獻舞</td>\n<td>莊10/5/182</td>\n<td>以蔡侯獻舞歸</td>\n</tr>\n<tr>\n<td>蔡侯封人</td>\n<td>桓17/4/148</td>\n<td>蔡侯封人卒</td>\n</tr>\n<tr>\n<td>蔡侯般</td>\n<td>昭11/3/1321</td>\n<td>楚子虔誘蔡侯般殺之于申</td>\n</tr>\n<tr>\n<td>蔡侯朱</td>\n<td>昭21/6/1423</td>\n<td>蔡侯朱出奔楚 榖梁作東</td>\n</tr>\n<tr>\n<td>蔡侯考父</td>\n<td>隱8/3/56</td>\n<td>蔡侯考父卒</td>\n</tr>\n<tr>\n<td>蔡侯肸</td>\n<td>僖14/5/346</td>\n<td>蔡侯肸卒</td>\n</tr>\n<tr>\n<td>蔡侯東國</td>\n<td>昭23/5/1440</td>\n<td>蔡侯東國卒于楚</td>\n</tr>\n<tr>\n<td>鄧侯吾離</td>\n<td>桓7/2/118</td>\n<td>鄧侯吾離來朝 左傳：名，賤之也。公羊、榖梁以為乃失地之君，故書其名，楊《注》駁之。</td>\n</tr>\n<tr>\n<td>鄭伯捷</td>\n<td>僖32/2/488</td>\n<td>鄭伯捷卒 公羊作接</td>\n</tr>\n<tr>\n<td>鄭伯寤生</td>\n<td>桓11/2/129</td>\n<td>鄭伯寤生卒</td>\n</tr>\n<tr>\n<td>鄭伯突</td>\n<td>桓15/4/141</td>\n<td>鄭伯突出奔蔡 桓15/9/142 鄭伯突入于櫟 莊21/2/216 鄭伯突卒</td>\n</tr>\n<tr>\n<td>鄭伯蘭</td>\n<td>宣3/7/668</td>\n<td>鄭伯蘭卒</td>\n</tr>\n<tr>\n<td>鄭伯堅</td>\n<td>成4/2/817</td>\n<td>鄭伯堅卒</td>\n</tr>\n<tr>\n<td>鄭伯費</td>\n<td>成6/7/825</td>\n<td>鄭伯費卒</td>\n</tr>\n<tr>\n<td>鄭伯睔</td>\n<td>襄2/4/919</td>\n<td>鄭伯睔卒</td>\n</tr>\n<tr>\n<td>鄭伯髡頑</td>\n<td>襄7/9//949</td>\n<td>鄭伯髡頑如會，未見諸侯，丙戌，卒于鄵 頑，公羊、榖梁作原，鄵，公羊、榖梁作操</td>\n</tr>\n<tr>\n<td>鄭伯嘉</td>\n<td>昭12/2/1330</td>\n<td>鄭伯嘉卒</td>\n</tr>\n<tr>\n<td>鄭伯寧</td>\n<td>昭28/3/1490</td>\n<td>鄭伯寧卒</td>\n</tr>\n<tr>\n<td>鄭伯蠆</td>\n<td>定9/2/1570</td>\n<td>鄭伯蠆卒 公羊作囆</td>\n</tr>\n<tr>\n<td>衛侯鄭</td>\n<td>僖30/3/478</td>\n<td>衛侯鄭歸于衛 宣9/10/700 衛侯鄭卒</td>\n</tr>\n<tr>\n<td>衛侯燬</td>\n<td>僖25/1/430</td>\n<td>衛侯燬滅邢 左傳：同姓也，故名。公羊、榖梁同義。孔廣森《公羊通義》：滅同姓名，唯謂滅周之同姓。若齊之於萊，楚之於夔，彼雖自為同姓，而於王家則為庶姓，罪猶差輕。 僖25/2/430 衛侯燬卒</td>\n</tr>\n<tr>\n<td>衛侯輒</td>\n<td>哀16/1/1697</td>\n<td>衛侯輒來奔</td>\n</tr>\n<tr>\n<td>衛侯惡</td>\n<td>昭7/5/1282</td>\n<td>衛侯惡卒</td>\n</tr>\n<tr>\n<td>衛侯衎</td>\n<td>襄26/3/1110</td>\n<td>衛侯衎復歸于衛 襄29/3/1153 衛侯衎卒</td>\n</tr>\n<tr>\n<td>衛侯元</td>\n<td>哀2/2/1610</td>\n<td>衛侯元卒</td>\n</tr>\n<tr>\n<td>衛侯晉</td>\n<td>桓12/8/133</td>\n<td>衛侯晉卒</td>\n</tr>\n<tr>\n<td>衛侯朔</td>\n<td>桓16/5/145</td>\n<td>衛侯朔出奔齊 莊6/2/167 衛侯朔入于衛 莊25/2/231 衛侯朔卒</td>\n</tr>\n<tr>\n<td>衛侯速</td>\n<td>成2/6/785</td>\n<td>衛侯速卒 公羊作遬</td>\n</tr>\n<tr>\n<td>衛侯臧</td>\n<td>成14/6/868</td>\n<td>衛侯臧卒</td>\n</tr>\n<tr>\n<td>薛伯定</td>\n<td>定12/1/1584</td>\n<td>薛伯定卒</td>\n</tr>\n<tr>\n<td>薛伯夷</td>\n<td>哀10/9/1655</td>\n<td>薛伯夷卒 公羊作寅</td>\n</tr>\n<tr>\n<td>薛伯榖</td>\n<td>昭31/3/1510</td>\n<td>薛伯榖卒</td>\n</tr>\n</tbody>\n</table>","date_published":"Thu, 03 May 2012 16:37:56 GMT","date_modified":"Sat, 23 Nov 2019 19:11:50 GMT"},{"id":"https://mmap.page/dapi/evil-interview/","url":"https://mmap.page/dapi/evil-interview/","title":"魔王訪談錄","content_html":"<h1>魔王訪談錄</h1>\n<p>最近，由於一個特殊的機緣，我有幸到魔窟走了一遭。利用這個難得的機會，我找魔王做了一個訪談。</p>\n<p>我：魔王大人，有時間做個訪談嗎？</p>\n<p>魔王：可以。不過作為交換，訪談結束後你要回答我三個問題。如果你的回答不真誠，那你就得留下來給我改善下伙食。</p>\n<p>我：成交。您聽說了最近「魔王火燒公主」的事件了嗎？新時代的魔王似乎很有創新精神呢。既然得不到公主的歡心，索性燒死算了。所有權的最重要的部份是處分權吧，從這個意義上說，奪走公主的生命，不正是一種終極的佔有的方式嗎？新時代的魔王，似乎大獲全勝呢。對此，像您這樣終日宅在魔窟之內的傳統魔王有什麽話要說嗎？</p>\n<p>魔王：燒個人也燒不死的垃圾，也配稱魔王？</p>\n<p>我：雖然沒死，但是這並不影響大局。公主燒成這樣，以後恐怕很少會有王子對她感興趣了吧？何況，不論公主以後還能不能討得王子的歡心，終其一生，恐怕她都走不出魔王的陰影了吧。想想公主的未來吧，求學、工作、戀愛、結婚、養兒，無時無刻不受到這次事件的影響。想想吧，每次洗髮的時候，每次水流從頭頂經臉側毫無阻礙地流向下頜的時候，公主又一次意識到，她的一隻耳朵已經沒有了，無論她多麼恨那個魔王，都無法否認，那個魔王改變了她的一生。恐怕很少有人，能像那個邪惡的魔王一樣，對她的人生施加那麼深刻而長遠的影響吧？某種意義上說，無論魔王的下場如何，他都作為揮之不去的陰影，伴隨公主一生呢。</p>\n<p>魔王：別喋喋不休了，我都快以為你是來推銷汽油和打火機的。提出你的問題。</p>\n<p>我：我的疑惑是，爲什麽一代又一代的魔王都一根筋地去搶公主，然後讓王子尋上門來殺死自己，讓王子把毫髮無傷的公主帶回去，白白地成就了王子的英名和公主的姻緣？既然能做到魔王，怎麼也不會是笨蛋吧？十幾歲的小孩都想得到的主意，魔王沒有理由想不到吧？就算一個魔王沒想到，這麼多魔王不會一個都沒想到吧？背後到底有什麽隱情呢？</p>\n<p>魔王：所以我說那小子不是魔王。燒不死人還在其次，最主要的是，火燒公主，那是只有人類纔會有的想法。當他點火的那一瞬間，他就宣告了自己的失敗，他知道公主的心裏沒有他，他沒機會得到公主的心了，只能以這樣的方式來影響公主的人生了。而魔王，永遠不會真正絕望，魔王永遠堅信，公主是深愛自己的。</p>\n<p>我：公主深愛魔王？故事裏可從來沒這麼說過。</p>\n<p>魔王：那是你沒有認真去讀！你想想，公主從小生在王宮之中，從小到大，就知道以後要嫁給王子，而魔王是邪惡的。你還能期望她有多少自己的主見呢？所以我們魔王都把公主帶到偏僻的魔窟，這裡沒有世俗的干擾，正適合公主在這樣一個清幽的環境中思考自己的人生，叩問自己的內心，脫離俗知俗見的束縛。假以時日，公主一定能意識到，是世俗的偏見蒙蔽了自己的本心，其實自己喜歡的，是魔王。</p>\n<p>我：原來是這樣啊。那怎麼就沒聽說有哪位公主大徹大悟了呢？</p>\n<p>魔王：你竟敢質疑我的話？大部份的情況是，那些王子都來得太快了，公主還沒有足夠的時間想清楚。還有，一旦公主最後跟了魔王，王室一定會作為莫大的醜聞秘而不宣，難道還會編成故事四處宣揚不成？</p>\n<p>我：唉，原來是家醜不外揚呀。就沒有哪家媒體爆料嗎？</p>\n<p>魔王：以人類為銷售對象的媒體敢把自己擺在反人類的立場上嗎？</p>\n<p>我：那倒是。說不定有不少王子都被魔王做掉了，只是媒體不報導而已。</p>\n<p>魔王：那倒不是。魔王和王子戰鬥，有一個很大的破綻。所以魔王和王子的戰鬥，從來都是輸多贏少。</p>\n<p>我：哦？什麽破綻？</p>\n<p>魔王：因為怕公主傷心欲絕，除非不得已，魔王并不想真下殺手，往往留有餘地，希望只是擊傷或是擊退，而不要傷了王子的性命。還有，生死之際，是認清內心的絕好的契機。所以很多魔王都在戰鬥中故意讓自己陷入可能毀滅的危機之中，希望在這個瞬間，公主能夠意識到，在魔王和王子生死相搏的時候，開始是想要王子獲勝，但是真到魔王要死的時刻，又暗暗希望魔王不要死。這是極端危險的，因為有勇氣來魔窟的王子實力不會太低。但是生死關頭的契機太難得了，很少有魔王能抵擋住這種致命的誘惑。</p>\n<p>我：原來魔王在和王子的戰鬥中吃了這麼多暗虧呢。真是的，魔王原來多逍遙自在啊，就是因為喜歡公主纔變得這麼憋屈吧？</p>\n<p>一直漫不經心地回答我的問題的魔王，正色道：愛上公主，這是魔王的宿命。</p>\n<p>我：就沒有魔王能逃脫這個宿命嗎？</p>\n<p>魔王想了一會，道：曾經有一個例外。有一位魔王，一直不去搶公主。直到王子和公主成婚的前一天，突然出現，把公主搶走了。王子趕到，殺死了魔王。王子和公主發現，魔王的魔窟已經按婚禮的樣子佈置好了，而且比王宮的佈置更好，所以乾脆就召集眾人，在魔窟舉行了婚禮。</p>\n<p>我：那他最終還是沒逃過宿命啊。</p>\n<p>魔王：不，他愛的不是公主，而是王子。他本來想一輩子呆在魔窟，不去打擾王子和公主的幸福生活。但是在王子成婚前的那一天，他也忍不住前去看了一眼。正好被他聽到公主在向王子抱怨婚禮的佈置不夠好，王子一個勁地賠不是。魔王看到自己的心上人賠不是的樣子，心都碎了。但是他又不能出手相助，因為王子是不會接受魔王的幫助的。於是他就乾脆把公主搶了，又把自己的魔窟按婚禮的樣子佈置。魔王的法力高強，婚禮的陳設自然不是凡間的王宮可比。然後，就是與心上人的一戰。本來魔王是希望就這樣一直戰鬥下去的，但是到後來王子體力漸漸不夠了。魔王擔心王子體力不支，新婚之夜又被公主抱怨，就故意賣個破綻。於是體力不支，本已絕望的王子一劍刺破了魔王的胸膛。絕處逢生的喜悅，成就英名的歡喜，新婚在即的快樂，交織在一起，王子臉上露出了由衷的笑容。望著王子的笑臉，那一刻的魔王是最幸福的：「恐怕你得知可以繼承王位或者公主答應你的求婚的時候，你都沒有這麼開心吧。你這一生最大的歡喜，是我帶給你的。就在此刻。而你的笑容，也溫暖了我的心。我這一生最大的溫暖，是你帶給我的。也是就在此刻。」</p>\n<p>我沉浸在這個動人的故事中，久久沒有回過神來。突然魔王說：輪到你了。回答我三個問題！我看你一副陶醉的模樣，倒對你的性取向很是好奇，回答我，你的性取向是什麽？</p>\n<p>我想了想，答道：Every man had thought that he loved women, until he met his superman.</p>\n<p>這是一個很有技巧的回答。首先它是真誠的，并沒有違反約定。其次它其實什麽也沒說。表面上似乎是說我是gay，但也可以不是，因為我可能還沒遇到我的superman嘛。當然魔王可能不會這麼容易糊弄，可能會問我到底遇到了沒有。但是這樣的話，他就又花費了一次提問的機會，我安然離開的可能性也就會變大不少。</p>\n<p>誰知魔王卻沒有過多糾纏，接著問了一個無關的問題：大便之後你用哪種草紙？</p>\n<p>我松了一口氣，心想這個魔王不過就是有點猥瑣，有點八卦，應該不難應付。我如實回答了這個問題。</p>\n<p>事實證明，魔王不是那麼簡單的人物。他這一問只是讓我自以為過關，產生輕視之心而已。</p>\n<p>魔王慢悠悠地說：嗯，我知道這種紙。雖然在超市它被標成衛生紙，其實和某些面紙一樣柔軟。好了，最後一個問題，你有沒有想過，你精心呵護的菊花，那個男人根本就不屑一顧呢？</p>\n<p>我後背全是冷汗，但仍然竭力喊道：那你有沒有想過，也許公主根本就不喜歡魔王呢？所謂公主其實是喜歡魔王的，只是她的本心被遮蔽了，她自己沒有意識到，也許根本就是魔王的一廂情願？</p>\n<p>魔王：反問不是回答！今晚我可以喝到排骨湯了。</p>\n<p>我纔發現我一時情急，竟然忘了回答問題。但是我並不甘心就這樣死掉，所以強辯道：你根本就是被我說破了事實氣急敗壞吧？還魔王呢！一點沒有涵養！</p>\n<p>魔王：氣急敗壞的是你自己吧。讓你死得明白吧，雖然我本來沒有必要告訴你。你的反問只是迴避，你沒有勇氣真誠地面對這個問題。我深信公主其實是喜歡我的，雖然她自己沒有意識到，是因為我是魔王。我有作為魔王的自尊和驕傲。你並不是魔王，那你又憑什麽深信你愛的那個男人也愛你呢？</p>\n<p>我萬念俱灰地閉上了眼睛。魔王所說的沒錯，我害怕這個問題，我不敢面對，我沒有真誠地回答這個問題，所以我將付出我的代價。</p>\n<p>在等待死亡的那一刻，不知不覺地，我又想起那個讓我魂牽夢繞的男人。此時此刻，他又在幹什麼呢？沒來由地，我仿佛看到他就在不遠處看著我。我想，旁人只會以為我死在魔王的手裡，誰又知道我其實是死在那個人的注視之下呢？能在他的注視之下死去，也是一種幸福吧。</p>\n<p>這時魔王卻嘆了口氣：我想你知道答案了，說出來吧。</p>\n<p>我並沒有睜開眼睛，輕輕地說：當我閉上雙眼的時候，我能感覺到那個男人凝視我的目光是那樣地深情。那一刻，我知道他是愛我的。</p>\n<p>說完我纔意識到，我答出來了，我不用死了。但我又有點疑惑，爲什麽魔王要提醒我，如果他不提醒我，那時的我早已把問題和約定忘到九霄雲外，我自己是不會想到要回答問題的。</p>\n<p>魔王看到我疑惑的目光，猜到了我的想法：你剛來的時候，靈魂中充斥著悲傷、焦灼、不甘、絕望、懷疑等等情緒，這樣的靈魂勾起了我的食慾，所以我纔陪你做什麽訪談，我只是想借機吃掉你。但是剛剛你的靈魂十分平和，對我來說就是淡而無味了。所以我就提醒你一下，一般而言，在必死的心態下，突然得知已經知道答案，說出來就可以獲救的話，人會有一種絕處逢生的喜悅。我趁這個時候，在你想說未說的時刻，把你一口吞下，雖然是囫圇吞棗，但多少還有些味道。哪知你一點情緒的波動都沒有。</p>\n<p>我：這種平和的心態，我想我並不能保持很久。</p>\n<p>魔王：但是你已經真誠地回答了我三個問題，依照約定，我只能送你回去。</p>\n<p>於是我逃離了魔窟，回到了這個有人說比魔窟還兇險的美好的現實世界。</p>\n<hr>\n<p>by Jakukyo Friel <a href=\"mailto:weakish@gmail.com\">weakish@gmail.com</a> under GPL-2</p>","date_published":"Thu, 03 May 2012 15:53:26 GMT","date_modified":"Sat, 23 Nov 2019 19:16:00 GMT"},{"id":"https://mmap.page/poems/drinking/","url":"https://mmap.page/poems/drinking/","title":"飲酒二首","content_html":"<h1>飲酒二首</h1>\n<h2>無量</h2>\n<pre><code>不厭嘉蔬惧酌清\n平生見觶便心驚\n綠珠行酒固無飲\n刀下墜樓何預卿\n</code></pre>\n<p>作於民國 96 年 (2007)，為余所作第一首近體詩。\n（案：「固無飲」原作「固不飲」，「不」不合律，故改作「無」。）</p>\n<h2>琴無弦</h2>\n<pre><code>玄風竹葉青\n白首鱔魚黃\n未飲舌先絆\n方醺目半張\n</code></pre>\n<p>composed at 2012-03-27</p>","date_published":"Tue, 27 Mar 2012 03:48:23 GMT","date_modified":"Sat, 23 Nov 2019 19:28:41 GMT"},{"id":"https://mmap.page/dapi/jingxuejueyuan/","url":"https://mmap.page/dapi/jingxuejueyuan/","title":"跋經學抉原","content_html":"<h1>跋經學抉原</h1>\n<p>蒙文通. 經學抉原[M]. 上海:上海人民出版社,2006年8月. ISBN 7-208-06300-1</p>\n<h2>重編前言</h2>\n<p>(蒙默)</p>\n<p>丁卯，先生纂《經學抉原》，乃就《導言》改定而成，(虛案：《經學導言》)又增寫數篇，(1)而論說較前精進。(1)</p>\n<h2>經學導言</h2>\n<p>經學這門學問，明註是一步，明傳是一步，明經是一步，明道是一步，若只在前三步裏邊纔做得一步，不能做明道的學問，那還算不得一個造詣高深的學問家。(41)</p>\n<blockquote>\n<p>明註已足盡吾年矣！</p>\n</blockquote>\n<h2>經學抉原</h2>\n<p>史公序《十二諸侯年表》，列孔氏《春秋》、《左氏春秋》、《鐸氏微》、《虞氏春秋》、《呂氏春秋》，凡五家，不數《公羊》、《榖梁》，以此二家者即孔氏之學，而《左氏》、《呂氏》之各自爲家也。(74-75)</p>\n<blockquote>\n<p>竊以為不數《公》、《榖》者，未必以其不各自爲家也。或因《公》、《榖》成書晚也。《公羊》徐彥《疏》引戴宏說，即謂「至漢景帝時」「著於竹帛」。</p>\n</blockquote>\n<p>史遷書稱《春秋國語》，兩言左邱失明，厥有《國語》，是史公所見左氏書惟《國語》耳。《十二諸侯年表序》云：「左邱明因孔子史記，具論其語，成《左氏春秋》。」曰「具論其語」，知《左氏春秋》即《國語》也。《論衡·案書篇》：「《左氏》傳經，辭語尚略，故復選錄《國語》之辭以實。」則取《左氏春秋》《國語》為《左氏傳》，漢儒故知其事，史公蓋見《國語》而未見後出之《傳》也。(75)</p>\n<blockquote>\n<p>以兩言「左邱失明，厥有《國語》」，論定史公所見惟《國語》，又以「具論其語」論定史公所言《左氏春秋》即指《國語》，竊以為有失審慎。兩言「左邱失明，厥有《國語》」者，或以舉《國語》以該《左傳》，或因左邱之書以《國語》為著，司馬遷未必但見《國語》也。又，余初見蒙氏引《史記》、《論衡》二書，而於《史記》之「因孔子史記」、《論衡》之「傳經」，不置一詞，未嘗不疑惑叢生也。後於蒙氏下文左、孔相乖之論繹讀再三，始悟蒙氏「《左氏》自據《不修春秋》以立言，此漢師不以《左氏》為經，謂不祖孔子，不傳《春秋》者」之精義。無論史公序《十二諸侯年表》不數《公》、《榖》究出何因，亦無論史公見《左傳》否，要之，《公》、《榖》為孔氏學，師承有自，而《左》無師承，又與孔相乖，故不祖孔子，不傳《春秋》也。今學界多以《左》為經傳，實則其所謂經傳者，已與蒙氏所謂經傳者旨趣相殊也。今學界多用古學，以史視經，以為《左》既為解經而作，三傳之中，舍《左》不能明《春秋》之史事，《左》如何不得稱傳也。既以經為史，宜乎其以傳為史注也。若蒙氏所謂經傳者，則異其趣。蒙氏《儒學五論題辭》即言：「經其表而傳記為之裏。」(212)李源澄《經學通論·論今古學》云：「經學之爲經學，原以儒學納於經文之下而成，有經無說，亦不成其爲經學。故漢人重師說，先師所不傳，道亦不傳也。」(李源澄. 經學通論[M]. 上海:華東師範大學出版社,2010年3月:28. ISBN 978-7-5617-7362-8)殆與蒙氏之意同。《左》既無師承，又與孔相乖，宜乎蒙氏不以《左》為《春秋》之傳也。以《左》為《春秋》之傳，則經傳與史注復有何別乎？故蒙氏此說，實已非同古學</p>\n</blockquote>\n<hr>\n<blockquote>\n<p>本文之正文皆照錄蒙氏原文，愚見括注虛案或縮進以別之，唯以下至「文字第十」則撮舉《抉原》各節大義。蓋皆本蒙氏之說，摘句而連綴之，顧不盡為蒙氏原文。</p>\n</blockquote>\n<p>序(54-56)</p>\n<p>舊史第一(56-59) 三古列國之史，國各不同。孔子固據魯以述文，亦變魯以協道。</p>\n<p>焚書第二(59-63)\n秦官舊籍猶存，孔氏之業不殘。樂本無經，其節具於《禮》，其歌具於《詩》。</p>\n<p>傳記第三(63-67) 六經傳記，其文多矣，其來遠矣。孔子之定六經，已自有傳。孔子之前，更有傳也。自武帝罷傳記博士，古傳遂缺矣。孔子弟子散於九流，故傳記又往往取諸諸子以為書。諸子書多在傳記中，蓋亦因《詩》、《書》、百家語並在博士。</p>\n<p>今學第四(67-71) 今文之學能自相同者，帝王稱制臨決之故也。漢之絀古文，疑以獻王故也。武帝好文辭，浮麗之論滋起，至東京而今文之弊極矣！末流之害既深，古文之學遂乘之而起。</p>\n<p>古學第五(71-77) 壁中書，古文家見之，今文家亦見之，皆以傳記視之，不以為經耳。《毛》、《魯》故訓不相遠，《左氏》自為一家，據不修春秋立言，不祖孔子。中興之際，古文家尊《毛詩》，今文家亦尊《毛詩》；今文家排《左氏》，古文家亦排《左氏》也。併《左氏》、《周官》於六藝，劉歆事業也。古文至杜預、王弼始全離今文而自樹一幟也。執《周官》以徧說群經者，鄭氏家法也。</p>\n<p>南學、北學第六(77-81) 南學，子雍（王肅）之術；北學，康成（鄭玄）之學。南學蓋源於仲子（宋衷）之《後定》而大於子雍也。鄭玄括囊大典，網羅眾家，冶今古兩學於一鑪。王肅難鄭，一蹈鄭氏，或又甚焉。遂二家分行南北。河洛尚篤信康成，江左則不能確宗王氏。唐一區宇，製作正義，南北二學遂合而為一。</p>\n<p>內學第七(81-83) 信毖緯者，今文家有之，古文家亦有之。闢毖緯者，古文家有之，今文家亦有之。緯學雖導源於西京，然西京為律歷陰陽之學，而非成、哀以後圖讖之學。齊人五德之運，此《七略》數術之學也；燕人形解銷化，此《七略》方技之學也。遠則燕齊殊科，近則兩漢異致，皆於經術無涉。自儒者混而同之，各家之真遂莫能辨析也。兩漢經學有經學之師傳，言五德者有五德之師傳，亦可知陰陽五行說之不與經相混淆。《封禪書》所載鼎書、札書，在《漢紀》并謂之讖，尤足見圖書古固有之，入後則并為讖。此桓譚所謂增損圖書，矯稱讖記，張衡所謂圖讖成於哀平之際者也。</p>\n<p>魯學、齊學第八(84-87) 就漢世言之，魯學謹篤，齊學恢宏，風尚各殊者，正以魯固儒學之正宗，而齊乃諸子之萃聚也。井研先生以燕學同於齊學，蓋燕之風尚，素與齊同，燕之儒生多自齊往故也，則燕學者齊學之附庸也。善條列諸子者，無過於莊子、荀子、司馬談三家，若劉氏九流之分，本以校書而立部別，《淮南·要略》所陳，專就致用立說，皆不足持之以辨章學術。法家統於道家，名家統於墨家，陰陽家則巫史所傳舊文，無裨學術。則六家之學，惟儒與道、墨而已。</p>\n<p>晉學、楚學第九(87-91) 今文之學源於齊、魯，而古文之學源於梁、趙也。三晉之史視齊、魯為備。三晉之學，秦人所深斥者也。秦人之所尊者，齊、魯之學也。在漢亦齊、魯諸儒與方士并進。今古學門戶雖成立於漢，然齊、魯以并進而漸合，晉學以獨排而別行，則始於秦。三晉以史學為正宗，魯人以經學為正宗，若楚人之學，則屈宋以來，自以辭賦為正宗也。東方，儒、墨；北方，法家；南方，道家。</p>\n<p>文字第十(92-93)</p>\n<hr>\n<h2>廖季平先生與清代漢學</h2>\n<p>汪中之流，固亦嘗推崇東原戴氏也，蓋前乎戴氏者，其治瑣事謏聞，與經事相比，如惠氏箋《漁洋菁華錄》之流；至戴氏而一革舊習，鄙唐宋以下事不屑言，悍然攻程朱之說而不顧，漢學之壁壘至東原而始固，此前世之所以推東原也。今之盛推東原者並此而不知，徒以俞氏著書擬於高郵王氏，由俞推王，由王推戴，顧曰戴長於斷，余固不知言考據而不能斷，兩《經解》中不能斷者將誰氏也？清世每惠、戴並稱，惠言《易》宗虞，言《左氏》宗服，於《書》、《禮》宗鄭，能開家法之端者實惠氏；於虞《易》言消息，故通條例之學者亦始惠氏，雖後之通家法、明條例者或精於惠氏，而以惠、戴相較，則惠實爲優。世之研骨化石者，得其半骼殘骸，於以推測其全體，得他之片骨殘骸，又以推測一全體，此家法條例之比也。苟萃衆多不同世之化石於一室，割短續長，以成一具體備形之骸，雖至愚人亦不出此。不明家法，不究條例，萃古文於一篇，折群言而歸一是，於此而言學在能斷，余不知斷從何起？事之可笑，孰過於斯！(104)</p>\n<h2>儒家政治思想之發展</h2>\n<p>秦、漢間學者言三代事，多美備，不爲信據。不信，則擯疑之誠是也，然學人必爲說若是者，何耶？斯殆陳古刺今，以召來世。其頌述三古之隆，正其想望後來之盛。(152)</p>\n<h2>儒家法夏法殷義</h2>\n<p>蓋晚周之學，諸派漸融，舍短取長，以易舊貫，家各然也。誠以儒家之義，有取之法家者，儒法固相讎，因曰法殷，不謂取法家也。又有取之墨家者，因曰法夏，不謂取墨家也。(189)</p>\n<h2>《儒學五論》題辭</h2>\n<p>宗道者綜諸子以斷其義，純為空言；宗儒者綜諸子而備其制，益切於用。(202)</p>\n<blockquote>\n<p>蒙氏於《論經學遺稿丙篇》亦言：「戰國末期，百家之學術漸趨於匯合，綜百家之長而去其短者為雜家，《呂覽》為之始，而《淮南》繼之。惟雜家以道德為中心，故偏於玄言，不切世用。繼雜家而起者為經術，為儒家，推明仁義之說，固視道家為精，其言政術亦視雜家為備，其取雜家而代之固宜。」(210,211)顧余則以為空言可喜，切用無味。</p>\n</blockquote>\n<p>殆以諸子之義既萃於經術，則經術為根底，而百氏其柯條。支義奇詞，胥就董理，諸子之於經術，倘正辯證法發展之謂歟！此則孟、荀儒者之術，入漢而為經生之業，以恢詭無方之諸子，轉而為湛深純一之經術，道之相承，固宜如此。(202)</p>\n<blockquote>\n<p>此段論漢儒采諸子，誠為切要。蒙氏謂儒「湛深純一」，而斥諸子之「支義奇詞」，其於《論經學遺稿丙篇》又云：「周秦諸子為國史上最為燦爛之思想文化，而經術者此燦爛文化結晶也。」(210)「是則晚周諸子入漢一變而為經學，經學固百家言之結論，六經其根柢，而發展之精深卓絕乃在傳記，經其表而傳記為之裏也。」(212)皆宗儒者之言也。但不知辯證法之於經術，今日之宗儒者當以其為根底歟，抑柯條歟？</p>\n</blockquote>\n<h2>論經學遺稿乙篇</h2>\n<p>前則《呂覽》、《淮南》之書，及《尸》、《管》之儔，胥主於道家以綜百氏，司馬談父子亦其流也。(208)</p>\n<p>道家起於南方，偏於玄虛，以仁義為小；法家盛於北方，重視現實，以仁義為迂（大也）；皆遠於中華傳統之文化。(211)</p>\n<h2>孔子和今文學</h2>\n<p>秦始皇對儒生是深惡痛絕的。然而漢武對儒生卻又推崇備至，這又當如何解釋呢？其實，秦皇、漢武並沒有多大的差別。秦是因「人善其所私學，以非上之所建立」，纔致焚書之禍。從《說苑》的記載看，鮑白令（應是鮑丘之誤，即《鹽鐵論》之包丘子，《史記》之浮丘伯，詳《浮丘伯傳》）提出「禪讓」理論，面責秦始皇為桀紂，而主張五帝「官天下」，反對「家天下」。然而「禪讓」卻是今文學一大義。儒生就是堅持這一主張來與秦的統治者作鬥爭的，所以始皇必至坑儒。但漢武帝又何嘗不如此呢？趙綰、王臧請立「明堂」，這也是今文學一大義（詳後）。趙、王兩人都是武帝的老師，但因此兩人同致殺身之禍。即如武帝以後的眭孟、蓋寬饒，也是請漢帝禪讓而致殺身之禍的。由此可見，凡堅持儒家學說的人，無論是六國之君或秦始皇、漢武都是不能容忍的。而儒之為漢代社會上多數人所推崇，正在於此等人物和他們所堅持的大義。至於漢武帝時所謂以儒顯的，首先是公孫弘這種曲學阿世者。「罷黜百家，立學校之官，皆自仲舒發之。」這是後世稱為大有功於儒學的人。但「湯、武革命」，豈非今文學一大義（詳後）嗎？董仲舒卻變湯、武「革命」為三代「改制」。「易姓受命」是禪讓的學說，但董仲舒何以又要說「繼體守文之君」（即世及之君）「不害聖人之受命」，同時又把今文學主張的井田變為限田呢？實際上，儒家最高的理想與專制君主不相容的精微部份，阿世者流一齊都打了折扣而與君權妥協了，今文學從此也就變質了。董仲舒又何嘗不是曲學阿世之流。儒學本為後來所推重，這時經董仲舒、公孫弘之流的修改與曲解之後，這樣變了質的儒學，卻又是專制帝王漢武帝樂於</p>\n<h2>治經雜語</h2>\n<p>《周官》一書貌似規模宏大，職官分明，故後世有「周公致太平」、劉歆偽造之說。然細究其實，亦殊混亂，如選舉不盡屬大宗伯，軍事不盡屬大司馬，冢宰所主則多為王朝內府之事。若再細審之，則各官職分之重複者亦復不少。可見其實非系統完整之理想制度。至其所反映之社會制度亦與戰國以後之實況不合而頗與西周相符（別有專文），皆可證其為就舊日之檔案整理而成者。(269)</p>\n<p>惠棟是懂家法的，張惠言之於《易》，莊存與之於《公年》，(虛案：疑當作「公羊」)都可說是明於漢家家法的。(269)</p>\n<p>章太炎頗推重孫詒讓《周禮正義》、黃以周《禮書通故》二書，然二書路數則不同。孫為漢學路子，純宗鄭玄，然信之太過。黃以周則不純為漢學，也講宋學，以宋學方法講漢學則時有臆說。然其書又多用林昌彝《三禮通釋》，而其下結論則較林為精，林書則為《五禮通考》路子。(270)</p>\n<p>孫明復講《春秋》大一統，蓋針對唐末五代之藩鎮割據而發，故其說得以不脛而走。胡安國《春秋傳》大攘夷，則就南宋形勢言之，故其書終宋之時代三傳行世。(270)</p>\n<blockquote>\n<p>「聯繫實際」，自古有之。</p>\n</blockquote>\n<p>司馬談所言正是說明漢初所謂黃老是什麽，這也說明了《呂覽》的主旨所在。到《淮南》就和《呂覽》精神不同，雖然《呂覽》之精不如《淮南》，但合於一世之用則高於《淮南》。(273)</p>\n<p>西漢學術，應當明確由儒家轉變到經生的過程，伏生《尚書大傳》、韓太傅《詩外傳》、董生《春秋繁露》，還是儒家，而劉向、匡衡之輩，則為經生。儒家則猶意氣風發，經生則章句之徒而已。(274)</p>\n<h2>對《辭海》徵求意見稿經學條目所提意見</h2>\n<p>《周禮正義》　以東漢鄭玄注為依據。惟對部份清儒如惠士奇、金鍔、鄒漢勳等因不墨守鄭學，雖有很多精辟之論亦棄而不取，但仍是解釋《周禮》比較完備的書。(277)</p>\n<p>《儀禮正義》 有系統的《儀禮》注解書。對宋儒、清儒如盛世佐等學說雖不合鄭義，亦並加棌入，與其他墨守漢學的著作不同。書內部分是作者死後他的弟子楊大堉將作者稿本加以整理補成此書，這部分就差一些。（後來曹元弼作《禮經校釋》，是專為此書而作。曹氏墨守鄭學，意義已不同了）(277)</p>\n<p>乾嘉學派主要是反對宋明理學，不用唐以後一切學說，自以為是漢學，它是以訓詁為中心。(278)</p>","date_published":"Sun, 25 Mar 2012 10:11:01 GMT","date_modified":"Sat, 23 Nov 2019 19:11:50 GMT"},{"id":"https://mmap.page/dapi/lunyucidian-patch/","url":"https://mmap.page/dapi/lunyucidian-patch/","title":"跋論語譯注","content_html":"<h1>跋論語譯注</h1>\n<p>楊伯峻. 論語譯注[M]. 2版. 北京:中華書局,1980年12月. ISBN 7-101-00334-6</p>\n<p>此書爲今譯今注之典範。</p>\n<p>後附《論語詞典》，亦極有用。唯偶有小誤，如「德」字，《論語》凡40見，《詞典》統計為39見，今依《譯注》所標章節，臚列如左：</p>\n<p>1.9 2.1 2.3 4.11 4.25 6.29 7.3 7.6 7.23 8.1 8.20 8.20 9.18 11.3 12.10 12.10 12.19 12.19 12.21 12.21 13.22 14.4 14.4 14.5 14.33 14.34 14.34 14.34 14.34 1534 15.13 15.27 16.1 16.12 17.13 17.14 18.5 19.2 19.11 19.11</p>","date_published":"Fri, 16 Mar 2012 13:13:05 GMT","date_modified":"Sat, 23 Nov 2019 19:11:50 GMT"},{"id":"https://mmap.page/dapi/moshou/","url":"https://mmap.page/dapi/moshou/","content_html":"<p>趙伯雄. 春秋學史. 濟南:山東教育出版社,2004年4月. ISBN 7-5328-4203-7</p>\n<p>未暇通讀，繙閱之際，偶見可議者二。</p>\n<p>第九章第四節述陳立、皮錫瑞，(729-739)第五節述廖平、康有爲，(740-767)以鹿門長季平二歲，置皮氏於廖氏之前，亦可，然通篇無一語道及廖氏於皮氏之影響，可乎？</p>\n<p>第三章第五節述鄭玄《發墨守》、《針膏肓》、《起廢疾》，因言及何休《公羊墨守》、《左氏膏肓》、《穀梁廢疾》，云：「何氏三書，今已不傳，但從書名看，當是墨守《公羊》經義，以攻擊《左傳》、《穀梁》之非。」(234)案《公羊墨守》之「墨守」，非本《戰國策》「墨翟之善守」也。墨者，晦也，默也，幽也。守，《戰國策》鮑彪注「猶閉」。[1]發墨守者，發其幽閉也。發、針、起，對文，墨守、膏肓、廢疾，亦對文。何休《公羊解詁序》云：「傳春秋者非一，本據亂而作，其中多非常異義可怪之論。說者疑惑，至有倍經任意、反傳違戾者。其勢雖問，不得不廣，是以講誦師言，至於百萬，猶有不解，時加釀嘲辭，援引他經，失其句讀，以無為有，甚可閔笑者，不可勝記也。是以治古學貴文章者謂之俗儒，使賈逵緣隙奮筆，以為公羊可奪，左氏可興。」[2]故何著《公羊墨守》，乃正其時公羊家之失，即所謂「俗儒」「失其句讀，以無為有，甚可閔笑」、「使賈逵」「以為公羊可奪」者。《公羊墨守》之「墨守」，非謂墨守《公羊》經義，明矣。唯此誤解實始自徐彥。徐《疏》已言「作《墨守》以拒敵《長義》」。今考徐《疏》，引何氏《膏肓》、《廢疾》，亦引鄭氏《發墨守》，獨未嘗稱引《墨守》，殆徐氏未見《墨守》，故望文生訓也。宋末之人所著（舊題鄭樵撰，此用《四庫提要》說）《六經奧論·春秋經·三傳》云：「尊公羊者以公羊為墨守，以左氏、榖梁為膏肓、廢疾。」[3]殆亦承其誤。</p>\n<p>愚以為，經學史之屬，若蒙氏文通《經學抉原》者，可謂精矣。但取此書與蒙書相較，即曉此書難稱精矣。雖然，是書條理清楚，稱引詳贍，亦可資讀春秋者參考矣。</p>\n<p>引用文獻</p>\n<ol>\n<li>劉向. 戰國策[M]. 上海:上海古籍出版社,1978-05:610. 統一書號:11186·6</li>\n<li>阮元. 十三經注疏附校勘記:公羊注疏;榖梁注疏[M]. 臺中:藍燈文化事業公司,出版年不詳:3,4a</li>\n<li>舊題鄭樵. 六經奧論[M]. 臺北:閩南同鄉會,1976-03(民國六十五年三月):153</li>\n</ol>","date_published":"Tue, 13 Dec 2011 10:32:37 GMT","date_modified":"Sat, 26 Jul 2025 05:31:18 GMT"},{"id":"https://mmap.page/dapi/huangkanshoupifuhao/","url":"https://mmap.page/dapi/huangkanshoupifuhao/","title":"跋黃侃手批白文十三經","content_html":"<h1>跋黃侃手批白文十三經</h1>\n<p>黃侃手批白文十三經. 黃侃批校. 北京:中華書局2006年5月. ISBN 7-101-04909-5</p>\n<p>據黃焯《說明》可知，句讀根據舊注，且以一家之說爲主。如《爾雅·釋畜》有一例依郭注斷句，實則應依鄭玄《周禮注》所引斷句，黃侃雖知鄭義爲長，然於句讀則仍從郭。</p>\n<p>除斷句外，另有符識四十餘種，涉及分段、空格、乙文、訛字、衍文、脫文、四聲、異文、真書體製與篆文有異之字，等等。各經符識亦有所不同，如：《尚書》僞古文於句旁連加點者，表此類文句確有來歷，非魏晉間人所僞造；《毛詩》於句右旁加綫表興義，於上句左下角與下句左上角用綫連接表上下句於文法需連讀，於句旁加「/」表反問詞，於上下句角加「「」」表此類句爲詩人代所詠之人述之之詞，於字左旁加點表鄭箋與毛傳有異，於上下兩字用弧綫相連表倒裝句或表傳箋補足經意；《周禮》於字或句旁加綫表前人對此提出疑議，於字上加「[]」表衍文；《春秋左傳》於諸字下連續加圈表左氏之詞涉及全書條例，於句旁標直綫表君子曰或仲尼曰，於句末加三角表書法；《春秋公羊傳》、《春秋穀梁傳》於句末字旁加朱綫表疑問語，於句旁加綫表釋《春秋》書法；《論語》句旁連點表重出，字旁加三角表異文。</p>\n<p>此書八十年代上海古籍出版社曾影印出版，開本較小，小字批語辨識爲難。今中華書局改以十六開影印，分爲上下冊。</p>","date_published":"Tue, 13 Dec 2011 10:29:09 GMT","date_modified":"Sat, 23 Nov 2019 19:11:50 GMT"},{"id":"https://mmap.page/poems/exodia/","url":"https://mmap.page/poems/exodia/","content_html":"<blockquote>\n<p>Exodia was, at first, a beast of such incalculable and intimidating might,\nthat he was split up into five distinctive parts - each one of them\nbeing chained and then sealed away in a poem (hence \"The Forbidden One\").\nThis would prevent his power from ever being used again.</p>\n<p>-- from The Book of Exodia, 5:36</p>\n</blockquote>\n<p>封印されしエクゾディア (Exodia the Forbidden One)</p>\n<pre><code>功遜赤練蛇\n容愧綠萼花\n言惑嘉興粽\n德慕峨嵋霞\n</code></pre>\n<p>封印されし者の右足 (Right Leg of the Forbidden One)</p>\n<pre><code>心吞造化腸猶斷\n念起觀音目已聾\n蝴蝶夢中譏馬白\n寧為赤練不為龍\n</code></pre>\n<p>封印されし者の左足 (Left Leg of the Forbidden One)</p>\n<pre><code>耳順無聞清梵唄\n目枯未結月明珠\n掘田三尺公孫冢\n但見髑髏顏色愉\n</code></pre>\n<p>封印されし者の右腕 (Right Arm of the Forbidden One)</p>\n<pre><code>南湖小荷纔聞月\n北閣粗茶已醉人\n穎脫無由何足道\n酣眠袋裏夢游鱗\n</code></pre>\n<p>封印されし者の左腕 (Left Arm of the Forbidden One)</p>\n<pre><code>皓首一經孱\n聚糧三世瘨\n祗因不知味\n夕死口頭禪\n</code></pre>\n<blockquote>\n<p>Were the five poems remembered by nobody, the five parts of Exodia would\ndie with the poems.  After that, Exodia Necross, the deceased Exodia,\ncould be summoned via \"Contract with Exodia\".</p>\n<p>-- from The Book of Exodia, 8:28</p>\n</blockquote>\n<p>エクゾディアとの契約 (Contract with Exodia)</p>\n<pre><code>五五之年惟待化\n黃粱好夢覺時癡\n起身何急先續幻\n半片明心終善思\n</code></pre>","date_published":"Mon, 13 Jun 2011 03:31:30 GMT","date_modified":"Sat, 23 Nov 2019 19:32:54 GMT"},{"id":"https://mmap.page/dive-into/centos/","url":"https://mmap.page/dive-into/centos/","title":"CentOS server setup guide for people from debian","content_html":"<h1>CentOS server setup guide for people from debian</h1>\n<p>A basic server setup guide for people from debian to CentOS.</p>\n<h2>Software</h2>\n<p><code>yum</code> is apt-get/aptitude on CentOS.</p>\n<p>Remove not necessary software:</p>\n<pre><code>yum grouplist\nyum groupremove &#x3C;wildcards>\nyum list installed\nyum remove &#x3C;wildcards>\n</code></pre>\n<p>Upgrade system: (equivalent to <code>apt-get update &#x26;&#x26; apt-get upgrade</code> on debian)</p>\n<pre><code>yum update\n</code></pre>\n<p>Add more packages:</p>\n<p><a href=\"http://wiki.centos.org/AdditionalResources/Repositories/RPMForge\">http://wiki.centos.org/AdditionalResources/Repositories/RPMForge</a></p>\n<p>Unlike Debian, Centos's official package repo is very limited.</p>\n<h2>Services</h2>\n<p>Check what is running:</p>\n<pre><code>chkconfig --list |grep '3:on' |awk '{print $1}' |sort\n</code></pre>\n<p>Use <code>chkconfig &#x3C;service> off</code> to disable unnecessary services.</p>\n<p><code>chkconfig</code> is included as default in Centos.\nIn Debian, you can install it via <code>apt-get install chkconfig</code>,\nthough Debian people are likely to use <code>sysv-rc-conf</code> instead.</p>\n<h2>Hostname</h2>\n<p>Make sure your <code>/etc/hosts</code> file have a line like:</p>\n<pre><code>127.0.0.1               &#x3C;your-hostname>.example.com &#x3C;your-hostname> localhost.localdomain localhost\n</code></pre>\n<p>And <code>/etc/sysconfig/network</code> have a line like:</p>\n<pre><code>HOSTNAME=your-hostname.example.com\n</code></pre>\n<p>Then run <code>hostname &#x3C;your-hostname>.example.com</code></p>\n<p>Debian doesn't use <code>/etc/sysconfig/network</code>.\nIn Debian, you change hostname in <code>/etc/hostname</code>:</p>\n<pre><code>echo 'your-hostname' > /etc/hostname\n</code></pre>\n<p>Debian prefers to not include the <code>example.com</code> part.</p>\n<h2>SSH</h2>\n<p>Same to Debian.</p>\n<h2>Firewall</h2>\n<p>CentOS may enable iptables by default.\nYou may want to disable it via <code>service iptables stop</code>\nor <code>/etc/init.d/iptables stop</code>.\nAnd disable its startup at boot time via <code>chkconfig</code>.</p>\n<p>If you want to mess up with it, its configuration file is located at\n<code>/etc/sysconfig/iptables</code>, different to Debian.</p>","date_published":"Fri, 10 Jun 2011 09:28:08 GMT","date_modified":"Thu, 17 Jul 2025 14:34:57 GMT"},{"id":"https://mmap.page/dive-into/fish/","url":"https://mmap.page/dive-into/fish/","title":"Dive into Fish","content_html":"<h1>Dive into Fish</h1>\n<h2>Introduction</h2>\n<p>Fish is the Friendly Interactive Shell.\nIt also offers a relative clean syntax for shell scripting.\n(I myself find that <code>rc</code> has a more clean syntax.\nFish's tab completion is powerful.\nThough plan9 fans may say that we should implement tab completion in\nterminal emulator.)</p>\n<h2>Help</h2>\n<p><code>help command</code> or <code>command --help</code>.</p>\n<h2>Syntax overview</h2>\n<pre><code>command [argument ...]\n</code></pre>\n<p>Commands and arguments are separated by the space character ( ).\nEvery command ends with either a newline or a semicolon (;).</p>\n<h2>Quotes and escaping</h2>\n<p>Variable expansions take place in double quoted strings but\nnot in single quoted ones.</p>\n<p>Escapes in single quotes: \\' and \\.</p>\n<p>Escapes in double quotes: \\\", \\, and \\$.</p>\n<pre><code>$ - ? * ~ # ( ) { } [ ] &#x3C; > ^ &#x26; ; ' \"\n</code></pre>\n<p>These characters and the space character have special meanings in fish.\nWe need to escape them by prepending them with a backslash.\nWe escape a backslach with another backslash (\\).</p>\n<h2>IO redirection and piping</h2>\n<ul>\n<li>standard input: <code>&#x3C;SOURCE_FILE</code></li>\n<li>standard output: <code>>DESTINATION</code></li>\n<li>standard error:  <code>^DESTINATION</code></li>\n<li>standard output, appended:  <code>>>DESTINATION_FILE</code></li>\n<li>standard error, appended:  <code>^^DESTINATION_FILE</code></li>\n</ul>\n<p>DESTINATION can be one of the following:</p>\n<ul>\n<li>A filename.</li>\n<li>An ampersand (&#x26;) followed by the number of another file descriptor.</li>\n<li>An ampersand followed by a minus sign (&#x26;-). The file descriptor\nwill be closed.</li>\n</ul>\n<p>For example, redirect both standard output and standard error\nto the file <code>all_output.txt</code>:</p>\n<pre><code>echo Hello >all_output.txt ^&#x26;1\n</code></pre>\n<p>Any FD can be redirected in an arbitrary way by prefixing the redirection with the number of the FD:</p>\n<ul>\n<li><code>N&#x3C;DESTINATION</code></li>\n<li><code>N>DESTINATION</code></li>\n<li><code>N>>DESTINATION_FILE</code></li>\n</ul>\n<p>Prepend the desired FD number and then output\nredirect symbol to the pipe.  For example:</p>\n<pre><code>make fish 2>| less\n</code></pre>\n<h2>Jobs</h2>\n<ul>\n<li><code>command &#x26;</code>: run command in background.</li>\n<li><code>fg</code> and <code>bg</code>: switch between foreground and background.</li>\n<li><code>jobs</code>: list jobs.</li>\n</ul>\n<h2>Functions and conditional structure</h2>\n<p>See help page for <code>function</code>, <code>if</code>, <code>switch</code>, <code>and</code>, <code>or</code>, <code>for</code>, <code>while</code>, <code>begin</code>, <code>end</code>, etc.</p>\n<p>Notes on wrapper functions:</p>\n<ul>\n<li>Don't forget $argv.</li>\n<li>Prefix the call to the command with the word 'command'. Failing to do so will cause infinite recursion bugs.</li>\n</ul>\n<h2>Autosuggestions</h2>\n<p>fish suggests commands as you type, based on command history, completions, and valid file paths. As you type commands, you will see a completion offered after the cursor, in a muted gray color.</p>\n<p>To accept the autosuggestion (replacing the command line contents), hit right arrow or Control-E.</p>\n<h2>Tab completion</h2>\n<p>Fish tab completion list features descriptions of the completions and\nit is scrollable\nby arrow keys, page up/page keys,\nthe tab key or the space bar.\nPressing any other key will exit the list and insert\nthe pressed key into the command line.</p>\n<p>fish provides completions for:</p>\n<ul>\n<li>Builtins, functions and regular programs.</li>\n<li>Environment variable names.</li>\n<li>Usernames in tilde expansion.</li>\n<li>Filenames, even with wildcards.</li>\n<li>Job id, job name and process names in process expansion.</li>\n</ul>\n<p>fish provides a large number of program specific completions.</p>\n<p>You can write your own builtin.\nSee <code>help complete</code> and /usr/share/fish/completions.</p>\n<h2>Set variables</h2>\n<pre><code>set name value1 value2 ...\n</code></pre>\n<p>Options:</p>\n<ul>\n<li><code>--local</code></li>\n<li><code>--global</code></li>\n<li><code>--export</code></li>\n<li><code>--universal</code></li>\n</ul>\n<p>When calling a function, all current local variables temporarily disappear.</p>\n<h2>Special variables</h2>\n<ul>\n<li><code>BROWSER</code></li>\n<li><code>CDPATH</code></li>\n<li><code>fish_greeting</code></li>\n<li><code>LANG</code>, <code>LC_ALL</code>, <code>LC_COLLATE</code>, <code>LC_CTYPE</code>, <code>LC_MESSAGES</code>, <code>LC_MONETARY</code>, <code>LC_NUMERIC</code> and <code>LC_TIME</code>.</li>\n<li><code>fish_user_paths</code> (An array of directories that are prepended to PATH. This can be a universal variable.)</li>\n<li><code>PATH</code></li>\n<li><code>umask</code></li>\n<li><code>_</code>, the name of the currently running comman.</li>\n<li><code>argv</code></li>\n<li><code>history</code></li>\n<li><code>HOME</code></li>\n<li><code>PWD</code></li>\n<li><code>status</code></li>\n<li><code>USER</code></li>\n</ul>\n<h2>Command line expansions</h2>\n<p>Wildcards:</p>\n<p><code>?</code>, <code>*</code>, and <code>**</code> match non-hidden file names.</p>\n<p>Use <code>.</code> as the first character to match hidden files.</p>\n<p>Command substitution:</p>\n<pre><code>(command)\n</code></pre>\n<p>Variable expansion:</p>\n<pre><code>$variable\n$array  # --> multiple arguments\n\"$array\" # --> one argument\n</code></pre>\n<p>Brace expansion:</p>\n<pre><code>{a,b,c}\n{$USER}san # Neat, isn't it?\n</code></pre>\n<p>Home directory expansion:</p>\n<pre><code>~\n~user\n</code></pre>\n<p>Process expansion:</p>\n<pre><code>%self # shell pid\n%id  # group id\n%string\n%user # pids of processes owned by user\n</code></pre>\n<p>Arrays:</p>\n<pre><code>$PATH[3] # indices start at 1\n(seq 10)[2..5]\n(seq 10)[2..5 1..3]\n(seq 10)[-1..1]  # Reverse output\n$$foo[1] # the same as ${$foo[1]}\n</code></pre>\n<h2>History</h2>\n<p>Press 'up' and 'down' to search commands containing the string entered.\nPress Alt-up and Alt-down, match against the token under the cursor.\nPress escape to abort.</p>\n<h2>Config files</h2>\n<p>Variables definitions: <code>~/.config/fish/config.fish</code></p>\n<p>Function definitions: <code>~/.config/fish/functions/</code></p>\n<p>Completion definitions: <code>~/.config/fish/completions/</code></p>\n<p>History file: <code>~/.config/fish/fish_history</code>.</p>\n<h2>Feedback</h2>\n<p><a href=\"mailto:weakish@gmail.com\">weakish@gmail.com</a></p>\n<h2>Copyright</h2>\n<p>This work is based on the fish user documentation shipped in the fish distributions:</p>\n<p>Copyright (C) 2005 Axel Liljencrantz.\nReleased under the GNU General Public License.</p>","date_published":"Mon, 21 Feb 2011 06:22:23 GMT","date_modified":"Sun, 24 May 2020 13:58:17 GMT"}]}