BlogInternet and Technology.https://erickguan.me/
K-Nearest Neighbor Classification in Scikit Learn<p>K-Nearest Neighbor (k-NN) presents a a simple straightforward instance-based
learning. Often, a simple strategy produces a good result as well as acting as
baseline performance.</p>
<p>This article doesn’t deliver new knowledge but an interpretation and bridge to
others’ work. The reader need to understand the very basic of Machine Learning.
Especially, code is done with <code class="highlighter-rouge">scikit-learn</code>.</p>
<p>In particular, KNN can be used in classification. The training data is vector
in a multidimensional space with a class label. <code class="highlighter-rouge">k</code> is an user-defined constant.
A test sample is classified based on a distance metric with <code class="highlighter-rouge">k</code> nearest samples from
the training data. That distance metric can be Euclidean distance for continuous
variables. As of discrete data, Hamming distance is a good choice.</p>
<p>In Scholarpedia, it was visualized with Voronoi tessellation:</p>
<blockquote>
<p>The k-nearest-neighbor classifier is commonly based on the Euclidean distance between a test sample and the specified training samples. Let <script type="math/tex">\mathbf{x}_i</script> be an input sample with <script type="math/tex">p</script> features <script type="math/tex">(\mathbf{x}_{i1},\mathbf{x}_{i2},\ldots,\mathbf{x}_{ip})</script>, <script type="math/tex">n</script> be the total number of input samples <script type="math/tex">(i=1,2,\ldots,n)</script> and <script type="math/tex">p</script> the total number of features <script type="math/tex">(j=1,2,\ldots,p)</script>. The Euclidean distance between sample <script type="math/tex">\mathbf{x}_i</script> and <script type="math/tex">\mathbf{x}_l (l=1,2,\ldots,n)</script> is defined as</p>
<p><script type="math/tex">d(\mathbf{x}_i,\mathbf{x}_l)=\sqrt{(x_{i1}−x_{l1})^2+(x_{i2}−x_{l2})^2+\cdots+(x_{ip}−x_{lp})^2}</script>.</p>
<p><img src="/assets/images/2017/knn-voronoi.png" alt="Voronoi tessellation showing Voronoi cells of 19 samples marked with a &quot;+&quot;. The Voronoi tessellation reflects two characteristics of the example 2-dimensional coordinate system: i) all possible points within a sample's Voronoi cell are the nearest neighboring points for that sample, and ii) for any sample, the nearest sample is determined by the closest Voronoi cell edge." /></p>
<p>A graphic depiction of the nearest neighbor concept is illustrated in the Voronoi tessellation (Voronoi, 1907) shown in Figure. The tessellation shows 19 samples marked with a “+”, and the Voronoi cell, R , surrounding each sample. A Voronoi cell encapsulates all neighboring points that are nearest to each sample and is defined as</p>
<p><script type="math/tex">R_i=\{\mathbf{x}\in\mathbb{R}^p:d(\mathbf{x},\mathbf{x}_i) \leq d(x,x_m),\forall i \neq m\}</script>,</p>
<p>where <script type="math/tex">R_i</script> is the Voronoi cell for sample <script type="math/tex">\mathbf{x}_i</script>, and <script type="math/tex">x</script> represents all possible points within Voronoi cell <script type="math/tex">R_i</script>. Voronoi tessellations primarily reflect two characteristics of a coordinate system: i) all possible points within a sample’s Voronoi cell are the nearest neighboring points for that sample, and ii) for any sample, the nearest sample is determined by the closest Voronoi cell edge. Using the latter characteristic, the k-nearest-neighbor classification rule is to assign to a test sample the majority category label of its k nearest training samples. In practice, k is usually chosen to be odd, so as to avoid ties. The k = 1 rule is generally called the nearest-neighbor classification rule.</p>
</blockquote>
<p>This is a great description of understanding. However I found out it’s misleading
as visualization emphasizes too much on Voronoi instead of KNN itself.</p>
<h2 id="how-it-works">How it works</h2>
<p>It all comes out with the code. As in <code class="highlighter-rouge">scikit-learn</code>, the <code class="highlighter-rouge">neighbors.KNeighborsClassifier(n_neighbors, algorithm='brute')</code> implements the most simple way to use KNN. The class comprises of 4 mixins:</p>
<ul>
<li><code class="highlighter-rouge">SupervisedIntegerMixin</code>: a helper checks parameters and invoke real function.</li>
<li><code class="highlighter-rouge">ClassifierMixin</code>: also a helper</li>
<li><code class="highlighter-rouge">NeighborsBase</code>: this mixin choose the optimal algorithm for efficient computing</li>
<li><code class="highlighter-rouge">KNeighborsMixin</code>: brute method is implemented here.</li>
</ul>
<p>We only have to see how the brute with euclidean distance works to understand it.</p>
<p><code class="highlighter-rouge">X</code> is the input here. <code class="highlighter-rouge">self._fit_X</code> is training data.</p>
<div class="language-python highlighter-rouge"><pre class="highlight"><code><span class="n">n_samples</span><span class="p">,</span> <span class="n">_</span> <span class="o">=</span> <span class="n">X</span><span class="o">.</span><span class="n">shape</span>
<span class="n">sample_range</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">arange</span><span class="p">(</span><span class="n">n_samples</span><span class="p">)[:,</span> <span class="bp">None</span><span class="p">]</span>
<span class="n">dist</span> <span class="o">=</span> <span class="n">pairwise_distances</span><span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">_fit_X</span><span class="p">,</span> <span class="s">'euclidean'</span><span class="p">)</span>
<span class="c"># here X is compared with all training samples.</span>
<span class="c"># dist is like a matrix of distance from X to training samples.</span>
<span class="c"># Example: `array([[1, 3, 2, 4]])`, 1 sample with 4 training data.</span>
<span class="n">neigh_ind</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">argpartition</span><span class="p">(</span><span class="n">dist</span><span class="p">,</span> <span class="n">n_neighbors</span> <span class="o">-</span> <span class="mi">1</span><span class="p">,</span> <span class="n">axis</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
<span class="c"># sort until `n_neighbors - 1`. When return, on the left side</span>
<span class="c"># it should be smaller than this data point</span>
<span class="n">neigh_ind</span> <span class="o">=</span> <span class="n">neigh_ind</span><span class="p">[:,</span> <span class="p">:</span><span class="n">n_neighbors</span><span class="p">]</span>
<span class="c"># argpartition doesn't guarantee sorted order, so we sort again</span>
<span class="n">neigh_ind</span> <span class="o">=</span> <span class="n">neigh_ind</span><span class="p">[</span>
<span class="n">sample_range</span><span class="p">,</span> <span class="n">np</span><span class="o">.</span><span class="n">argsort</span><span class="p">(</span><span class="n">dist</span><span class="p">[</span><span class="n">sample_range</span><span class="p">,</span> <span class="n">neigh_ind</span><span class="p">])]</span>
<span class="n">result</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">sqrt</span><span class="p">(</span><span class="n">dist</span><span class="p">[</span><span class="n">sample_range</span><span class="p">,</span> <span class="n">neigh_ind</span><span class="p">]),</span> <span class="n">neigh_ind</span>
</code></pre>
</div>
<p>Staring from <code class="highlighter-rouge">neigh_ind</code> are some lines only used to sort result.
At last, a distance result and the order of distance to training
data is returned.</p>
<p>If you ever tried <a href="http://scikit-learn.org/stable/modules/neighbors.html#nearest-neighbors-classification">the sample code</a>, you would notice the
choice of <code class="highlighter-rouge">k</code> affects the result a lot upon iris dataset.</p>
<p>Plus, the weight metric and <code class="highlighter-rouge">RadiusNeighborsClassifier</code> is a
further enhancement.</p>
<h2 id="conclusion">Conclusion</h2>
<p>KNN is a really simple nearest neighbor classification or
regression tool. It’s nothing fancy but with weight and algorithm
you can tweak.</p>
Thu, 02 Nov 2017 00:00:00 +0100https://erickguan.me/2017/k-nearest-neighbour-in-scikit-learn
https://erickguan.me/2017/k-nearest-neighbour-in-scikit-learnThe Surprising Number in JavaScript<p>Did you know you can not have a number larger than <script type="math/tex">2^{53}-1</script> in JavaScript?</p>
<p>You might try this in Chrome Developer Console and want to tell me that it works in Chrome.</p>
<p>It works because you are lucky.</p>
<h2 id="what-is-a-number">What is a Number?</h2>
<p>Let’s take a step back and review what is a number. Is <script type="math/tex">2^{53}</script> a number in JavaScript?</p>
<div class="language-js highlighter-rouge"><pre class="highlight"><code><span class="nb">Number</span><span class="p">.</span><span class="nx">isInteger</span><span class="p">(</span><span class="mi">2</span><span class="o">**</span><span class="mi">53</span><span class="p">)</span> <span class="c1">// true</span>
</code></pre>
</div>
<p>It works out right. But can there be potential issues?</p>
<p>Yes, it’s not <em>safe</em>.
It’s not safe because the number you hold
may lose its precision if it’s larger than the magical <script type="math/tex">2^{53}</script>.</p>
<p>Your user may complain they lose their money when they type a large number.
<code class="highlighter-rouge">9007199254740992</code>. You may lose your rocket in the sky because its position goes wrong.</p>
<p>That’s why you don’t trust the input and the reason you remember to check.</p>
<div class="language-js highlighter-rouge"><pre class="highlight"><code><span class="nb">Number</span><span class="p">.</span><span class="nx">isSafeInteger</span><span class="p">(</span><span class="mi">2</span><span class="o">**</span><span class="mi">53</span><span class="p">)</span> <span class="c1">// false</span>
</code></pre>
</div>
<p>Chrome can represent a integer more than ECMAScript required. That is unique for Chrome
. You are not allowed to rely on such undefined behavior by its implementation V8 engine.
It’s not portable and error prone.</p>
<p>If you read the great MDN, you’ll find:</p>
<blockquote>
<p>According to the ECMAScript standard, there is only one number type: the double-precision 64-bit binary format IEEE 754 value (number between <script type="math/tex">-(2^{53}-1)</script> and <script type="math/tex">2^{53}-1</script>). There is no specific type for integers. In addition to being able to represent floating-point numbers, the number type has three symbolic values: +Infinity, -Infinity, and NaN (not-a-number).</p>
</blockquote>
<p>You are not using Python, C/C++ or Ruby but JavaScript. There isn’t a type for integer in JavaScript.
Your integer at your hand
is just a <code class="highlighter-rouge">Number</code> in JavaScript. JavaScript is weak in its type system opposing to other
dynamic languages in which allow you to represent the infinite large number.</p>
<p>The ECMAScript standard says the number representation limits to the IEEE 754 value.
The standard defined that there isn’t a integer type so it’s a tangible mistake to do it.</p>
<p>If you use Python and Ruby, you pay the price when you use large number which probably you rarely make use of. So does the copy on right (CoW) in string to C++. But you are benefit to know
such information. It indicates you optimize for the right direction.
You don’t optimize for the extreme large number if you don’t encounter it frequently.
You optimize string view rather than CoW in C++17.
But in JavaScript, Python and Ruby. You enjoyed the fact that they have a type (class or object).</p>
<p>Such OO concept helps you encapsulate logic or anything.</p>
<p>In JavaScript, you also have bizarre pieces like <code class="highlighter-rouge">+Infinity</code>, <code class="highlighter-rouge">-Infinity</code>, <code class="highlighter-rouge">NaN</code> and our famous equality table along with the <code class="highlighter-rouge">Number</code> object.</p>
<p><img src="/assets/images/2017/js-equality-table.png" /></p>
<h3 id="grown-designed">Grown? Designed?</h3>
<p>Why is that?</p>
<p>JavaScript starts as a prototype project and designed by one person in 1995.</p>
<p>It was the browser war time. So there is
Netscape (former Mozilla), Microsoft and hackers (KHTML &amp; WebKit). In particular, Brendan Eich was recruited by Netscape and
assigned the task to design the language with the goal of embedding Scheme.
Netscape believed it would be important. And here came the other major vendors.
With the collaboration with Sun, the language in development should looks like Java to compete with Microsoft.</p>
<p>Such an important job is not held by a group of professors as you might imagine.
The designer at the time was only Brendan Eich. He invented the
prototype in 10 days, in May 1995.</p>
<h4 id="a-story-from-make">A story from make</h4>
<p>Let’s have some perspective. It’s 1995. Web is little to be known. People talk about Java, C++, Unix, internet, HTML etc.</p>
<p>It was different.</p>
<p>You have an
internet community and your lovely package manager like npm and bundler nowadays.
Everything are done for you and you believed there is somebody who will take care
something. You can talk about projects and think about the faults that your fellow
made so that you can fix in your new project.</p>
<p>Non of that happens for Brendan Eich.</p>
<p>I’m about to get the point but let’s talk about <code class="highlighter-rouge">make</code> instead.
Do you know what we still suffer in making a C/C++ project? The answer is that we
still use Makefile. <code class="highlighter-rouge">make</code> was a program in Unix to define how the dependency of
objects file should be resolved.
It was written by one person and intended
to be shared with friends.
The inventor went on ahead and starts command with tab without think too much.
The tab in a makefile is treat differently rather than spaces.
It’s a fine choice at the time and they came up the idea to include it into the standard UNIX package. Would that be wonderful, right?</p>
<p>So wrong. We suffer because of those ten guys.</p>
<p>The code aged but you can not revert time. The code is the logic that you don’t want to redo. It becomes dominant then you couldn’t change it without breaking things.
C++ pays the price for compatibility. Python pays the price too. They pay it differently.</p>
<p>People can’t love what they don’t know. People want to be part of something.</p>
<p>From JavaScript 1.0 to ECMAScript 2017, the JavaScript could not be redesigned
because it was put on the market for way too long.
It’s grown to this position. It was designed but it can not be designed now to gain
the same dominance.</p>
<h4 id="javascript">JavaScript</h4>
<p>Douglas Crockford, the creator of JSON said,</p>
<blockquote>
<p>JavaScript is built on some very good ideas and a few very bad ones.</p>
</blockquote>
<p>A committee of experts in programming language may still deliver obscure syntax
for a programming language.
Could you blame JavaScript for a 10-day one man project?</p>
<p>But why we suffer from this? Can we reboot it like Python 3? Probably no.
We just don’t have a choice. It’s bundled with the browser and DOM.
We live in an aftermath with survival like Chrome, Firefox and Safari.
Chrome shows the power of programming in user browser and we can never go back.
Node.js is on the market for years.</p>
<p>JavaScript has grown. It evolves through years.</p>
<h2 id="its-terrible-the-take-away">It’s terrible? The take away</h2>
<p>Lie on your back. LOOK at how it’s successful as a language. It’s universal now.</p>
<p>We all know there is no perfect language. JavaScript is no different.
JavaScript can be really surprised
in types. But don’t you happy with the first-class functions? Closures? Object literals? And performance?</p>
<p>So as a programmer, why not setup your linter if you have committed the very same
mistakes many times.
Just do more coding.</p>
<p>And don’t design without thinking. Do think twice when you design. Someone may suffer. You may suffer.</p>
<p><em>Thanks my friend @lextm for reviewing the draft.</em></p>
Wed, 23 Aug 2017 00:00:00 +0200https://erickguan.me/2017/the-surprise-number-in-javascript
https://erickguan.me/2017/the-surprise-number-in-javascriptCopy and Paste Bookmarklet<p>Inspired by <a href="https://github.com/jswanner/DontFuckWithPaste">DontFuckWithPaste</a>.</p>
<p>But why you ever need an extension taking your 100MB memory when you can have a nice and neat bookmarklet?</p>
<p><a style="padding: 10px; border: 1px dashed #777; background-image: none;" href="javascript:(function()%7Bconst%20allowCopyAndPaste%20%3D%20(e)%3D%3E%20%7Be.stopImmediatePropagation()%3Breturn%20true%3B%7D%3B%5B'copy'%2C'paste'%5D.forEach(a%20%3D%3E%20%7Bdocument.addEventListener(a%2C%20allowCopyAndPaste%2C%20true)%3B%7D)%7D)()">&gt; Copy &amp; Paste</a></p>
<ol>
<li>Drag the bookmarklet above into your bookmark bar. If you disable the bookmark bar, right click besides the link bar to get it back.</li>
<li>Click when you need copy and paste.</li>
<li>It’s a fake step. You are done.</li>
</ol>
Thu, 27 Jul 2017 00:00:00 +0200https://erickguan.me/2017/copy-and-paste-bookmarklet
https://erickguan.me/2017/copy-and-paste-bookmarkletBridging ICU with Ruby<p>Chinese Discourse users have more complains to the text problems. A community
software induce users to read and write which certainly deals with texts.
Numerous efforts are made along the way such as tokenizers for Chinese. Maintaining
a project is not easy.
One of feature request for Discourse is Unicode username. A core technical problem
is visually confusing username. Discourse community may be in a multilingual
community. This is certainly important to deal with. Although username is the
core identify of the user representation. It’s more than Unicode.</p>
<h2 id="motivation-and-goals">Motivation and goals</h2>
<p>Somehow, Ruby community doesn’t have much tools for Unicode processing. Unicode
normalization is implemented in the core library in 2.2. And what about <a href="http://unicode.org/reports/tr36/">Unicode
security problems</a>? I don’t want to reinvent the
wheel.
<a href="http://site.icu-project.org/">ICU (International Components for Unicode)</a> is an old and battle-tested
library for the Unicode. A binding with it would worth it. It should have
high performance, easy to maintain and can be deployed with MRI.</p>
<p>There are already some gems.</p>
<ul>
<li><a href="https://github.com/twitter/twitter-cldr-rb"><code class="highlighter-rouge">twitter-cldr-rb</code> gem</a> is a pure
Ruby implementation based on <a href="http://cldr.unicode.org/">Unicode CLDR</a>. Adding
feature means implementing algorithm on the unicode document.</li>
<li>Some existing gems are obsolete.</li>
<li>The binding with ICU is <a href="https://bugs.ruby-lang.org/issues/2034">discussed in MRI tracker</a>.</li>
</ul>
<h2 id="do-it-right">Do it right</h2>
<p>Ruby is really different than other programing languages in terms of its string
implementation. <a href="http://yokolet.blogspot.se/2009/07/design-and-implementation-of-ruby-m17n.html">The <em>Code Set Independent</em> (CSI) model</a>
doesn’t set a common internal encoding but stores the bytes presentation
with encoding information. It allows Ruby convert encodings when it involves I/O operations.
Also, Ruby holds the external encoding <code class="highlighter-rouge">Encoding.default_external</code> which is how Ruby
reads from an IO object. The <code class="highlighter-rouge">IO</code> object is typically a file (<code class="highlighter-rouge">File</code> is a subclass of IO).
The <code class="highlighter-rouge">Encoding.default_internal</code> for new created string is usually UTF-8 from the environment.
<a href="http://nuclearsquid.com/writings/ruby-1-9-encodings/">This starts from Ruby 1.9</a>.</p>
<p>ICU provides <a href="http://userguide.icu-project.org/i18n">many internationalization features</a>. It operates with strings.
So the most operations happen in memory. But ICU <a href="http://userguide.icu-project.org/strings">uses UTF-16 internally</a>. The conversion will happen if
UTF-8 is used as the default encoding.</p>
<p>Also, ICU’s C API uses callback function for error reporting.</p>
<p>A gem with C code can easily access byte arrays. And the conversion in C will be faster
than MRI implementation.</p>
<h2 id="design">Design</h2>
<p>ICU binding should be as transparent as possible. The user only uses the equivalent Ruby
API of ICU. Its module holds a optional internal encoding for the
returning result (usually a string). Since ruby’s string can be any encodings, it have
to be converted to UTF-16 for feeding ICU.</p>
<p>Along the way, <a href="https://silverhammermba.github.io/emberb/examples/"><em>The Definitive Guide to Ruby’s C API</em></a> helps me quite a lot. It’s the most clear reference for Ruby’s C API I’ve seen.</p>
Tue, 14 Mar 2017 00:00:00 +0100https://erickguan.me/2017/bridging-icu-with-ruby
https://erickguan.me/2017/bridging-icu-with-rubyUnicode is more than encoding<p>Nowadays, the average users don’t have to work with encodings generally and
don’t need to know Unicode. Better software, better library and better understanding
contributes a lot. The most basic operations we leant as an programmer is manipulating
characters and strings. By writing the simplest hello world program in different
scripts requires understanding encodings or relies on the programing language structure.</p>
<p>There are some recommend readings:</p>
<ul>
<li><a href="https://blog.codinghorror.com/there-aint-no-such-thing-as-plain-text/">There Ain’t No Such Thing as Plain Text
</a> by
Coding Horror
which shows a email and web encoding case in 2005.</li>
<li><a href="https://www.joelonsoftware.com/2003/10/08/the-absolute-minimum-every-software-developer-absolutely-positively-must-know-about-unicode-and-character-sets-no-excuses/">The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)
</a> by Joel Spolsky told the
Unicode story from the old C char type in 2003.</li>
<li><a href="https://en.wikipedia.org/wiki/Unicode">Unicode on Wikipedia</a> gives the general
ideas about it.</li>
<li><a href="http://reedbeta.com/blog/programmers-intro-to-unicode/">A Programmer’s Introduction to Unicode</a> by Nathan Reed visualizes
the Unicode code point plans and explains it with encodings and combining marks.</li>
</ul>
<h2 id="encodings-is-not-the-unicode">Encodings is not the Unicode</h2>
<p>Unicode works on character-level for the world’s writing system. It doesn’t help
you deal with the language, such as searching Chinese which isn’t separated by
the blank. But it reveals the relation between the encodings and characters.</p>
<p>Simply remember:</p>
<p><strong>There isn’t a string without encoding.</strong></p>
<p>If you ever forgot that or not understood, you won’t know why a same string
can’t be the same in the byte array.</p>
<p>Many programing languages make use of UTF-x encoding now. It isn’t the whole
story. Ruby uses <em>Code Set Independent</em> system for storing strings which basically
stores the encoding with the string. While most programming language mainly uses a
UTF-x to represent the string which is already encoded. The most scary thing
happens as the string may comes from a database, a JSON from HTTP response,
writing to a file and
your javascript literals. Now the string involves with I/O and I/O operates on
byte level. It must related with the encoding. Being arrogant and ignore the
fact that libraries, the operating system and your programing language handles
the encoding in a way, it will eventually bite you.</p>
<h2 id="unicode-regulates-more-than-code-points">Unicode regulates more than code points</h2>
<p>A common programming is comparing the string. This problem has
two aspects, one is with encoding above explained. The other is Unicode standard.
Unicode intends to represent character in the writing system. A single code point can
be represented by a series of code points. The abstract layers in the software
also wants to make it easy for the programmers. So now it’s time to remind you
for another thing.</p>
<blockquote>
<p>For example, the Vietnamese letter “ệ” can be expressed in five different ways:</p>
<ul>
<li>Fully precomposed: U+1EC7 “ệ”</li>
<li>Partially precomposed: U+1EB9 “ẹ” + U+0302 “◌̂”</li>
<li>Partially precomposed: U+00EA “ê” + U+0323 “◌̣”</li>
<li>Fully decomposed: U+0065 “e” + U+0323 “◌̣” + U+0302 “◌̂”</li>
<li>Fully decomposed: U+0065 “e” + U+0302 “◌̂” + U+0323 “◌̣”</li>
</ul>
</blockquote>
<p>– <em>A Programmer’s Introduction to Unicode</em>, Nathan Reed</p>
<p><strong>A character have different representation even with the same encoding.</strong></p>
<p>I won’t elaborate more. Here is some further directions to read.</p>
<p>Unicode website offers many readings for the problem and intention. And ICU
has a C/C++/Java implementation for these problems.</p>
Mon, 13 Mar 2017 00:00:00 +0100https://erickguan.me/2017/unicode-what-changes
https://erickguan.me/2017/unicode-what-changesHooray, Webhooks<p>Webhooks are “user-defined HTTP callbacks” <a href="http://progrium.com/blog/2007/05/03/web-hooks-to-revolutionize-the-web/">brought by Jeff Lindsay</a>. While it’s <a href="http://timothyfitz.com/2009/02/09/what-webhooks-are-and-why-you-should-care/">augmented</a> for some time, it comes to my sight because of continuous integration like Travis CI at GitHub. Later, Slack made it fancy as every services could pop up messages in the channel as if I was in Enterprise bridge:</p>
<p><img src="/assets/images/old/USS_Enterprise_(alternate_reality)_bridge.jpg" alt="Enterprise bridge" /></p>
<p>It’s also interesting to discover how it can be implemented on Ruby on Rails.</p>
<h2 id="case-study-webhooks-at-github-and-slack">Case Study: Webhooks at GitHub and Slack</h2>
<p>Since GitHub and Slack build great webhooks, it’s a good practice to see how they build the service.</p>
<h3 id="github">GitHub</h3>
<p>GitHub runs central repositories for git and origination services. It offers <a href="https://developer.github.com/webhooks/">webhooks</a> on organization level and repositories level where user can manage webhooks in the admin panel. GitHub allow users to create “up to 20 webhooks for each event on each installation target”. has an <a href="https://github.com/integrations">Integrations Directory</a></p>
<p>Events are triggered on certain scenario: (highlight)</p>
<table>
<thead>
<tr>
<th>Name</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>*</code></td>
<td>Any time any event is triggered. <a href="#wildcard-event">Wildcard Event</a> overwrites other events.</td>
</tr>
<tr>
<td><code>commit_comment</code></td>
<td>Any time a Commit is commented on.</td>
</tr>
<tr>
<td><code>push</code></td>
<td>Any Git push to a Repository. <strong>default event.</strong>
</td>
</tr>
</tbody>
</table>
<p>Illustrated in adding webhook page on the admin panel:</p>
<p><img src="/assets/images/github-add-webhooks.png" alt="Adding webhooks at GitHub" /></p>
<p>With pre-set configuration, GitHub is responsible for sending payload (JSON) based on <a href="https://developer.github.com/v3/activity/events/types/">event type</a>.</p>
<p>However, the payload size will be small than 5MB, otherwise, it will be discarded. It’s user’s responsibility to monitor payload size.</p>
<p>A HTTP header of webhooks includes event name, unique ID and signature by HMAC hex digest of the payload which uses hook’s secret as a key if secret is set.</p>
<p>GitHub build a great API. Webhook can be managed by its API. For testing reason, GitHub provides a <a href="https://developer.github.com/webhooks/#ping-event">Ping event to test a hook</a>, <a href="https://developer.github.com/v3/repos/hooks/#test-a-push-hook">hook’s test endpoint</a>.</p>
<p>Service hooks are defined sets of webhooks by the <a href="https://github.com/github/github-services">third party at github-services repo</a>. However, GitHub no longer accepts new service instead of urging new integration service to build OAuth application help managing webhooks. Be noted, GitHub integrations directory is different than services. It’s just a directory to help redirecting to third party services who manage webhooks.</p>
<h4 id="pubsubhubbub">PubSubHubbub</h4>
<p><a href="https://github.com/pubsubhubbub/PubSubHubbub">This crazy name (PubSubHubbub)</a> belongs to an open protocol for distributed publish/subscribe communication on the Internet. Their <a href="http://pubsubhubbub.github.io/PubSubHubbub/pubsubhubbub-core-0.4.html">specification</a> defines a decoupled flow for webhooks.</p>
<p><a href="https://wordpress.org/plugins/pubsubhubbub/">A Wordpress plugin</a> helps you announce new blog post. And GitHub can <a href="https://developer.github.com/v3/repos/hooks/#pubsubhubbub">serve as a PubSubHubbub hub</a> for all repositories.</p>
<p>It’s designed to <a href="https://github.com/pubsubhubbub/PubSubHubbub/wiki/Why-Polling-Sucks">overcome polling for getting feed updates</a>. GitHub will create a webhook if you request the hub.</p>
<h3 id="slack">Slack</h3>
<p>Slack builds the fancy messaging app for teams. Many integrations and bots are just favorable.</p>
<p>Basically, Slack offers incoming and outgoing webhooks. Slash commands is built on these two webhooks.</p>
<p>In terms of <a href="https://api.slack.com/incoming-webhooks">incoming webhooks</a>, sending a JSON payload and plain text to a hashed url would trigger a message with defined name and icon. Simple as that.
<a href="https://api.slack.com/outgoing-webhooks">Outgoing webhooks</a> come with receiving payload of messages. A payload will be sent when triggered by keywords or a new message on the channel. The integrated services can reply back if they want.</p>
<p>As an extension of outgoing webhooks, slash commands send payload to server and reply messages back to the channel. However, bots are separated from other webhooks. They build upon <a href="https://api.slack.com/web">Slack API</a> and <a href="https://api.slack.com/rtm">realtime API</a>.</p>
<h2 id="considerations">Considerations</h2>
<p>Webhooks are highly application-specific. Event payloads would be transported in secure (HTTPS) or plaintext (Don’t care) manner according to the content. Therefore, signature (symmetric key) or a token can be used as a way to authentication. For ambitious applications, they offers a way to package webhooks as a service to minimize the deployment cost of webhooks.</p>
Mon, 14 Mar 2016 00:00:00 +0100https://erickguan.me/2016/hooray-webhooks
https://erickguan.me/2016/hooray-webhooksEnsuring the file uploaded by Refile<p><a href="https://github.com/refile/refile">Refile</a> is an neat and simple file upload library for Ruby applications. It can be easily to integrated into Rails app. Be advised, I am on its git version <code class="highlighter-rouge">6a25a24059</code>.</p>
<p>Recently, I ran into trouble to validate the file exists or uploaded. I went through the AR layer, the model is <a href="https://github.com/refile/refile/blob/6a25a24059/lib/refile/attachment/active_record.rb#L24-L26">set at <code class="highlighter-rouge">before_save</code> hook</a>. There is no way to check the file is uploaded.</p>
<p>Thanks to its simple abstraction, <code class="highlighter-rouge">attacher</code> will <a href="https://github.com/refile/refile/blob/6a25a24059/lib/refile/attachment/active_record.rb#L12-L15">present</a> when the file is uploaded.</p>
<p>Then the final resolution is straightforward. For example:</p>
<div class="highlighter-rouge"><pre class="highlight"><code>class UserValidator &lt; ActiveModel::Validator
def validate(record)
unless record.send(:avatar).present?
attacher = "avatar_attacher"
record.errors.add(:avatar, :blank, options) unless record.send(attacher).present?
end
end
end
</code></pre>
</div>
<p>Only if the file is uploaded, the attcher will <a href="https://github.com/refile/refile/blob/6a25a24059/lib/refile/attacher.rb#L150-L152">be present</a>.</p>
Thu, 19 Mar 2015 00:00:00 +0100https://erickguan.me/2015/ensure-the-file-uploaded-by-refile
https://erickguan.me/2015/ensure-the-file-uploaded-by-refileBinding ACE editor with Rails form helper<p>ACE editor only can bind with a <code class="highlighter-rouge">div</code> container which means rails form helper can’t help when you want to bind with an attribute.
I am going to work through my solution.</p>
<h3 id="text_area"><code class="highlighter-rouge">text_area</code></h3>
<p><code class="highlighter-rouge">text_area</code> genererates <code class="highlighter-rouge">&lt;textarea&gt;</code> which people can edit its content without any js. And this helper helps you forget about binding with model.</p>
<p>I will get the content from it for ACE. When the js can’t work, we can still get a functional editor.</p>
<h3 id="binding-with-ace">Binding with ACE</h3>
<p>HTML:</p>
<pre><code class="language-HTML">&lt;div class="source-editor" data-mode="markdown"&gt;
&lt;textarea&gt;&lt;/textarea&gt;
&lt;/div&gt;
</code></pre>
<p>Script is easy. Work though all the <code class="highlighter-rouge">source-editor</code>, create a div and bind ACE within it. Then save back to textarea when submit.</p>
<p>You should set css for <code class="highlighter-rouge">textarea</code> just like the <code class="highlighter-rouge">div</code> in the ACE tutorial.</p>
<div class="language-js highlighter-rouge"><pre class="highlight"><code><span class="nx">$</span><span class="p">(</span><span class="s1">'.source-editor'</span><span class="p">).</span><span class="nx">each</span><span class="p">(</span><span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">container</span> <span class="o">=</span> <span class="nx">$</span><span class="p">(</span><span class="k">this</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">mode</span> <span class="o">=</span> <span class="nx">container</span><span class="p">.</span><span class="nx">data</span><span class="p">(</span><span class="s1">'mode'</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">editorArea</span> <span class="o">=</span> <span class="nx">container</span><span class="p">.</span><span class="nx">find</span><span class="p">(</span><span class="s1">'textarea'</span><span class="p">);</span>
<span class="c1">// build a edit div for ACE since ACE can't load in a textarea</span>
<span class="kd">var</span> <span class="nx">editDiv</span> <span class="o">=</span> <span class="nx">$</span><span class="p">(</span><span class="s1">'&lt;div&gt;'</span><span class="p">,</span> <span class="p">{</span>
<span class="na">position</span><span class="p">:</span> <span class="s1">'absolute'</span><span class="p">,</span>
<span class="na">width</span><span class="p">:</span> <span class="nx">editorArea</span><span class="p">.</span><span class="nx">width</span><span class="p">(),</span>
<span class="na">height</span><span class="p">:</span> <span class="nx">editorArea</span><span class="p">.</span><span class="nx">height</span><span class="p">(),</span>
<span class="s1">'class'</span><span class="p">:</span> <span class="nx">editorArea</span><span class="p">.</span><span class="nx">attr</span><span class="p">(</span><span class="s1">'class'</span><span class="p">)</span>
<span class="p">}).</span><span class="nx">insertBefore</span><span class="p">(</span><span class="nx">editorArea</span><span class="p">);</span>
<span class="c1">// no need to display textarea</span>
<span class="nx">editorArea</span><span class="p">.</span><span class="nx">css</span><span class="p">(</span><span class="s1">'display'</span><span class="p">,</span> <span class="s1">'none'</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">editor</span> <span class="o">=</span> <span class="nx">ace</span><span class="p">.</span><span class="nx">edit</span><span class="p">(</span><span class="nx">editDiv</span><span class="p">[</span><span class="mi">0</span><span class="p">]);</span>
<span class="nx">editor</span><span class="p">.</span><span class="nx">setFontSize</span><span class="p">(</span><span class="s1">'14px'</span><span class="p">);</span>
<span class="nx">editor</span><span class="p">.</span><span class="nx">setTheme</span><span class="p">(</span><span class="s1">'ace/theme/yesterday'</span><span class="p">);</span>
<span class="nx">editor</span><span class="p">.</span><span class="nx">getSession</span><span class="p">().</span><span class="nx">setMode</span><span class="p">(</span><span class="s1">'ace/mode/'</span> <span class="o">+</span> <span class="nx">mode</span><span class="p">);</span>
<span class="nx">editor</span><span class="p">.</span><span class="nx">getSession</span><span class="p">().</span><span class="nx">setValue</span><span class="p">(</span><span class="nx">editorArea</span><span class="p">.</span><span class="nx">val</span><span class="p">());</span>
<span class="c1">// save back to the textarea when submit</span>
<span class="nx">editorArea</span><span class="p">.</span><span class="nx">closest</span><span class="p">(</span><span class="s1">'form'</span><span class="p">).</span><span class="nx">submit</span><span class="p">(</span><span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="nx">editorArea</span><span class="p">.</span><span class="nx">val</span><span class="p">(</span><span class="nx">editor</span><span class="p">.</span><span class="nx">getSession</span><span class="p">().</span><span class="nx">getValue</span><span class="p">());</span>
<span class="p">});</span>
<span class="p">});</span>
</code></pre>
</div>
<h3 id="more-complicated-templates">More complicated templates</h3>
<p>Actually I forged Github-liked toolbar for the ACE editor which needs more HTML structures.</p>
<p>This can be done by Rails view partials. Separated HTML and passing form helper as a parameter. Then write its control logic in the component js.
No need for customized helpers, simple is the best.</p>
<div class="language-haml highlighter-rouge"><pre class="highlight"><code><span class="p">=</span> <span class="n">render</span> <span class="ss">partial: </span><span class="s1">'components/source_editor'</span><span class="p">,</span> <span class="se"> |
</span> <span class="ss">locals: </span><span class="p">{</span> <span class="se"> |
</span> <span class="ss">preview_url: </span><span class="s1">''</span><span class="p">,</span> <span class="se"> |
</span> <span class="ss">ace_mode: </span><span class="s1">'markdown'</span><span class="p">,</span> <span class="se"> |
</span> <span class="ss">indent_width: </span><span class="sx">%w(2 4 8)</span><span class="p">,</span> <span class="se"> |
</span> <span class="ss">tab_label: </span><span class="s1">'Edit content'</span><span class="p">,</span> <span class="se"> |
</span> <span class="ss">preview_label: </span><span class="s1">'Preview'</span><span class="p">,</span> <span class="se"> |
</span> <span class="ss">attribute: </span><span class="n">f</span><span class="p">.</span><span class="nf">text_area</span><span class="p">(</span><span class="ss">:raw</span><span class="p">)</span> <span class="p">}</span> <span class="se"> |
</span></code></pre>
</div>
Tue, 23 Dec 2014 00:00:00 +0100https://erickguan.me/2014/binding-ace-editor-with-rails-from-helper
https://erickguan.me/2014/binding-ace-editor-with-rails-from-helperBundle install without VPN in China<p>EDIT: Recommended mirror site updated in the end.</p>
<p><a href="https://rubygems.org">RubyGems</a> got blocked by GFW which blocks everytime you do <code class="highlighter-rouge">bundle install</code>. It’s because some of Amazon S3 are blocked by gov.</p>
<p>In the mainland China, we can just use mirror provided by Taobao. It’s fast. It sync with RubyGems every fifteen minutes.</p>
<p>The mirror <a href="https://ruby.taobao.org">ruby.taobao.org</a> has a detail usage guide. Here I want to demonstrate how to use it as a mirror instead of gem source.</p>
<h2 id="mirror">Mirror</h2>
<p>Sometime you’ll find you can’t remove rubygems source or change <code class="highlighter-rouge">Gemfile</code>. What you can do is to simply add a mirror for bundler.</p>
<p><code class="highlighter-rouge">bundle config mirror.https://rubygems.org https://ruby.taobao.org</code></p>
<p>You can find Bundler mirror documentation <a href="http://bundler.io/v1.7/bundle_config.html">here</a>.</p>
<h2 id="updated-mirror">Updated mirror</h2>
<p>Taobao mirror has troubles becaus of security policies that only employees can access servers which is needed for maintenance work at Taobao. Core maintainers left Taobao recent years which cause all kinds of troubles.</p>
<p>Therefore, a new mirror is considered to operate separately under control of serveral core members at <a href="https://ruby-china.org/">Ruby China</a>. QCloud will sponsor servers and CDN from Tencent. It’s going to offer “realtime” synchronization, 400+ global CDNs and two servers operated outside China which ensures CDN server can query the data.</p>
<p>Here is some related links (in Chinese of course):</p>
<ul>
<li>Issues: <a href="https://ruby-china.org/topics/29250">https://ruby-china.org/topics/29250</a></li>
<li>Github: <a href="https://github.com/ruby-china/rubygems-mirror">https://github.com/ruby-china/rubygems-mirror</a></li>
<li>Mirror site: <a href="http://gems.ruby-china.org/">http://gems.ruby-china.org/</a></li>
</ul>
<h3 id="commands">Commands</h3>
<p><code class="highlighter-rouge">gem sources --add https://gems.ruby-china.org/ --remove https://rubygems.org/</code></p>
<p><code class="highlighter-rouge">bundle config mirror.https://rubygems.org https://gems.ruby-china.org</code></p>
Sun, 14 Sep 2014 00:00:00 +0200https://erickguan.me/2014/bundle-install-without-vpn-in-china
https://erickguan.me/2014/bundle-install-without-vpn-in-chinaAdding a system call to Linux 3.14<p>There are plenty of blog posts about adding a system call to Linux 2.6, but they are out of date now. Here is a article about adding a system call to Linux 3.14. I assume you can easily add the system call for further kernel. Shane wrote a <a href="https://shanetully.com/2014/04/adding-a-syscall-to-linux-3-14/">great post</a> about it.</p>
<h2 id="system-call">System call</h2>
<p><strong>System call</strong> is how a user space application request a service from an operating system. Many libraries, even C standard library, are an wrapper with additional functions.</p>
<h2 id="environment">Environment</h2>
<p>Gentoo Linux(amd64): aufs-sources:3.14.5</p>
<p>If you are not a Gentoo user, you can get the kernel source from your package manager and <a href="http://kernel.org/">The Linux Kernel</a>.</p>
<h2 id="adding-a-system-call">Adding a system call</h2>
<p>A system call is defined in the system call entry table, a system call function prototype and actual implementation for the system call.</p>
<h3 id="syscall-table">syscall table</h3>
<p>The syscall table is located in the <code class="highlighter-rouge">arch/x86/syscalls/syscall_64.tbl</code>.</p>
<h4 id="format">Format</h4>
<p><code class="highlighter-rouge">&lt;numver&gt; &lt;abi&gt; &lt;name&gt; &lt;entry point&gt;</code></p>
<ul>
<li><code class="highlighter-rouge">number</code>: All syscalls are identified by a unique number. In order to call a syscall, we tell the kernel to call the syscall by its number rather than by its name.</li>
<li><code class="highlighter-rouge">abi</code>: The ABI, or application binary interface, to use. Either 64, x32, or common for both.</li>
<li><code class="highlighter-rouge">name</code>: This is simply the name of the syscall.</li>
<li><code class="highlighter-rouge">entry point</code>: The entry point is the name of the function to call in order to handle the syscall. The naming convention for this function is the name of the syscall prefixed with <code class="highlighter-rouge">sys_</code>. For example, the <code class="highlighter-rouge">read</code> syscall’s entry point is <code class="highlighter-rouge">sys_read</code>.</li>
</ul>
<h4 id="how-to">How-to</h4>
<p>Skipping the table, you’ll find a series of x86 system calls starting with 512. I’ll add the system call in the end after table right above that part.</p>
<p>For 3.14, the last system call is <code class="highlighter-rouge">315 common sched_getattr sys_sched_getattr</code>. So I add the new one as 316. It look like this:
<code class="highlighter-rouge">316 common set_root sys_set_root</code></p>
<h3 id="system-call-function-prototype">System call function prototype</h3>
<p>We need to define the function prototype in the <code class="highlighter-rouge">include/linux/syscalls.h</code> file.</p>
<p>Simply adding a line: <code class="highlighter-rouge">asmlinkage long sys_set_root(void);</code></p>
<p>We’ll add a system call takes no argument.</p>
<p><code class="highlighter-rouge">asmlinkage</code> is a modifier. This macro tells the compiler that the function should not expect to find any of its arguments in registers (a common optimization), but only on the CPU’s stack. You can find more in <a href="http://kernelnewbies.org/FAQ/asmlinkage">FAQ</a>.</p>
<h3 id="system-call-implementation">System call implementation</h3>
<p>Now, just create a new file <code class="highlighter-rouge">kernel/set_root.c</code>. Kernel style guild requires 8 space tab for indentation. But I will insist 4 space here.</p>
<div class="highlighter-rouge"><pre class="highlight"><code>#include &lt;linux/kernel.h&gt;
#include &lt;linux/init.h&gt;
#include &lt;linux/sched.h&gt;
#include &lt;linux/syscalls.h&gt;
asmlinkage long sys_set_root(void)
{
struct user_namespace *ns = current_user_ns();
struct cred *new;
kuid_t kuid = make_kuid(ns, 0);
kgid_t kgid = make_kgid(ns, 0);
if (!uid_valid(kuid)) {
return -EINVAL;
}
new = prepare_creds();
if (new != NULL) {
new-&gt;uid = kuid;
new-&gt;gid = kgid;
new-&gt;euid = kuid;
new-&gt;egid = kgid;
new-&gt;suid = kuid;
new-&gt;sgid = kgid;
new--&gt;fsuid = kuid;
new-&gt;fsgid = kgid;
return commit_creds(new);
} else {
abort_creds(new);
return -ENOMEM;
}
}
</code></pre>
</div>
<p>The code set the user program as root unconditionally. DO NOT USE THIS KERNEL after the experiment, or you’re in trouble.</p>
<h3 id="adding-our-implementation-to-makefile">Adding our implementation to Makefile</h3>
<p>Adding <code class="highlighter-rouge">set_root.o</code> to the end of <code class="highlighter-rouge">obj-y</code> line in the <code class="highlighter-rouge">kernel/Makefile</code>.</p>
<h3 id="patch-about-the-kernel">Patch about the kernel</h3>
<div class="highlighter-rouge"><pre class="highlight"><code><span class="gh">diff --git a/arch/x86/syscalls/syscall_64.tbl b/arch/x86/syscalls/syscall_64.tbl
index a12bddc..413209b 100644
</span><span class="gd">--- a/arch/x86/syscalls/syscall_64.tbl
</span><span class="gi">+++ b/arch/x86/syscalls/syscall_64.tbl
</span><span class="gu">@@ -322,6 +322,7 @@
</span>313 common finit_module sys_finit_module
314 common sched_setattr sys_sched_setattr
315 common sched_getattr sys_sched_getattr
<span class="gi">+316 common set_root sys_set_root
</span>
#
# x32-specific system call numbers start at 512 to avoid cache impact
<span class="gh">diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index a747a77..c9f7c3c 100644
</span><span class="gd">--- a/include/linux/syscalls.h
</span><span class="gi">+++ b/include/linux/syscalls.h
</span><span class="gu">@@ -855,4 +855,6 @@ asmlinkage long sys_process_vm_writev(pid_t pid,
</span>asmlinkage long sys_kcmp(pid_t pid1, pid_t pid2, int type,
unsigned long idx1, unsigned long idx2);
asmlinkage long sys_finit_module(int fd, const char __user *uargs, int flags);
<span class="gi">+asmlinkage long sys_set_root(void);
+
</span>#endif
<span class="gh">diff --git a/kernel/Makefile b/kernel/Makefile
index bc010ee..def272b 100644
</span><span class="gd">--- a/kernel/Makefile
</span><span class="gi">+++ b/kernel/Makefile
</span><span class="gu">@@ -10,7 +10,7 @@ obj-y = fork.o exec_domain.o panic.o
</span> kthread.o sys_ni.o posix-cpu-timers.o
hrtimer.o nsproxy.o
notifier.o ksysfs.o cred.o reboot.o
<span class="gd">- async.o range.o groups.o smpboot.o
</span><span class="gi">+ async.o range.o groups.o smpboot.o set_root.o
</span>
ifdef CONFIG_FUNCTION_TRACER
# Do not trace debug files and internal ftrace files
<span class="gh">diff --git a/kernel/set_root.c b/kernel/set_root.c
</span>new file mode 100644
<span class="gh">index 0000000..97fab9b
</span><span class="gd">--- /dev/null
</span><span class="gi">+++ b/kernel/set_root.c
</span><span class="gu">@@ -0,0 +1,38 @@
</span><span class="gi">+#include &lt;linux/kernel.h&gt;
+#include &lt;linux/init.h&gt;
+#include &lt;linux/sched.h&gt;
+#include &lt;linux/syscalls.h&gt;
+
+asmlinkage long sys_set_root(void)
+{
+ struct user_namespace *ns = current_user_ns();
+ struct cred *new;
+
+ kuid_t kuid = make_kuid(ns, 0);
+ kgid_t kgid = make_kgid(ns, 0);
+
+ if (!uid_valid(kuid)) {
+ return -EINVAL;
+ }
+
+ new = prepare_creds();
+
+ if (new != NULL) {
+ new-&gt;uid = kuid;
+ new-&gt;gid = kgid;
+
+ new-&gt;euid = kuid;
+ new-&gt;egid = kgid;
+
+ new-&gt;suid = kuid;
+ new-&gt;sgid = kgid;
+
+ new-&gt;fsuid = kuid;
+ new-&gt;fsgid = kgid;
+
+ return commit_creds(new);
+ } else {
+ abort_creds(new);
+ return -ENOMEM;
+ }
+}
</span></code></pre>
</div>
<h2 id="testing-by-invoking-system-call-in-a-c-program">Testing by invoking system call in a C program</h2>
<p>You may want to know <a href="http://www.tldp.org/LDP/khg/HyperNews/get/syscall/syscall86.html">how system call works</a>.</p>
<p>But here is only the code according to GNU whoami. The standard library provide the system call wrapper.</p>
<div class="highlighter-rouge"><pre class="highlight"><code>#include &lt;stdio.h&gt;
#include &lt;unistd.h&gt;
#include &lt;sys/types.h&gt;
#include &lt;pwd.h&gt;
#include &lt;string.h&gt;
#include &lt;errno.h&gt;
#define SYS_SET_ROOT 316
void whoami(void);
int main()
{
whoami();
if (syscall(SYS_SET_ROOT) == -1) {
fprintf(stderr, "Error calling syscall: %s\n", strerror(errno));
return 1;
}
whoami();
return 0;
}
void whoami()
{
// Code modified from GNU whoami source
// http://git.savannah.gnu.org/gitweb/?p=coreutils.git;a=blob;f=src/whoami.c;h=7301abb146418e36785801ff57a3946068b69fc5;hb=HEAD
uid_t uid = geteuid();
struct passwd *pw = getpwuid(uid);
if (pw != NULL) {
puts(pw-&gt;pw_name);
}
}
</code></pre>
</div>
Wed, 10 Sep 2014 00:00:00 +0200https://erickguan.me/2014/add-a-system-call-to-linux-3-14
https://erickguan.me/2014/add-a-system-call-to-linux-3-14