<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Posts on Igor Klimer's personal site</title><link>https://klimer.eu/posts/</link><description>Recent content in Posts on Igor Klimer's personal site</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><lastBuildDate>Sat, 06 Jul 2024 22:08:50 +0000</lastBuildDate><atom:link href="https://klimer.eu/posts/index.xml" rel="self" type="application/rss+xml"/><item><title>Migrating from Create React App to Vite</title><link>https://klimer.eu/2024/07/06/migrating-from-create-react-app-to-vite/</link><pubDate>Sat, 06 Jul 2024 22:08:50 +0000</pubDate><guid>https://klimer.eu/2024/07/06/migrating-from-create-react-app-to-vite/</guid><description>&lt;p>This post is meant to document my process, thoughts and tips on the migration of my &lt;a href="https://recalendar.me/">ReCalendar&lt;/a> personal project from &lt;a href="https://create-react-app.dev/">Create React App&lt;/a> to &lt;a href="https://vitejs.dev/">Vite&lt;/a>. It&amp;rsquo;s not meant to be an exhaustive guide. I wanted primarily to document the more interesting (and often frustrating) challenges of such a migration. So that others might benefit from them when scouring random pages on the web, searching for an explanation or solution to a cryptic error message.&lt;/p></description><content>&lt;p>This post is meant to document my process, thoughts and tips on the migration of my &lt;a href="https://recalendar.me/">ReCalendar&lt;/a> personal project from &lt;a href="https://create-react-app.dev/">Create React App&lt;/a> to &lt;a href="https://vitejs.dev/">Vite&lt;/a>. It&amp;rsquo;s not meant to be an exhaustive guide. I wanted primarily to document the more interesting (and often frustrating) challenges of such a migration. So that others might benefit from them when scouring random pages on the web, searching for an explanation or solution to a cryptic error message.&lt;/p>
&lt;h2 id="why-migrate">Why migrate?&lt;/h2>
&lt;p>Create React App has been the &lt;em>de facto&lt;/em> standard when creating new React apps for years. It&amp;rsquo;s still being recommended on many blog posts. However, &lt;a href="https://github.com/facebook/create-react-app/commits/main/">it has not been actively developed for a year&lt;/a>, it has &amp;gt;1.7k open issues and 477 pull requests. Mostly to update the out of date dependencies. In short, it&amp;rsquo;s not a future-proof solution.&lt;/p>
&lt;p>As typical in the JavaScript ecosystem, there&amp;rsquo;s plethora of alternatives. I went with &lt;a href="https://vitejs.dev/">Vite&lt;/a>, because it promised speed and simplicity. &lt;a href="https://react.dev/learn/start-a-new-react-project">React.dev has a list&lt;/a> of more complex, full-stack options, if that fits your requirements. However, ReCalendar is client-side only by design, does not need any routing, state management is very simple, etc. So Vite seemed like the best choice.&lt;/p>
&lt;h2 id="simplified-migration-steps">Simplified migration steps&lt;/h2>
&lt;ul>
&lt;li>Create a new Vite project, most likely &lt;a href="https://vitejs.dev/guide/#scaffolding-your-first-vite-project">using the provided templates&lt;/a>. There&amp;rsquo;s official support for many frameworks, and &lt;a href="https://github.com/vitejs/awesome-vite#templates">the community has got you covered for the rest&lt;/a>.&lt;/li>
&lt;li>I was previously using &lt;code>yarn&lt;/code>, but for the new project, I went with &lt;code>npm&lt;/code>. My understanding is that &lt;code>npm&lt;/code> caught up with &lt;code>yarn&lt;/code> recently in terms of performance and other improvements. So no need for an additional dependency to install.&lt;/li>
&lt;li>I also went with TypeScript-enabled configuration. It&amp;rsquo;s compatible with JavaScript (which the project is currently written in), but I&amp;rsquo;m hoping to migrate it to TypeScript in the future, so this gives me that possibility.&lt;/li>
&lt;li>Copy the source code to the new project. At this point, I&amp;rsquo;m just trying to make things compile. I went with the simplest approach of just manually re-installing the needed dependencies. There&amp;rsquo;s not that many and since I switched from &lt;code>yarn&lt;/code> to &lt;code>npm&lt;/code>, it felt like a proper fresh start.&lt;/li>
&lt;/ul>
&lt;h2 id="gotchas">Gotchas&lt;/h2>
&lt;p>Overall the code did not require much changes. Most of them were related to how Vite is &lt;a href="https://vitejs.dev/guide/why.html">&amp;ldquo;leveraging new advancements in the ecosystem: the availability of native ES modules in the browser&amp;rdquo;&lt;/a>. It&amp;rsquo;s a radically different approach to Webpack and Babel that CRA is based on. Vite uses &lt;a href="https://rollupjs.org/">Rollup&lt;/a> under the hood instead.&lt;/p>
&lt;p>The majority of the work was squashed into &lt;a href="https://rollupjs.org/">this commit&lt;/a>. Two major challenges are covered in the next sections. Other than that, I&amp;rsquo;ve taken the chance to clean-up things like &lt;code>.gitignore&lt;/code> or Eslint configuration. Some other changes/differences include:&lt;/p>
&lt;ul>
&lt;li>CRA would inject the correct &lt;code>script&lt;/code> tag to the main &lt;code>HTML&lt;/code> file at compile time. In Vite, you simply reference your app&amp;rsquo;s entry point like &lt;code>[/src/index.jsx](/src/index.jsx)&lt;/code>.&lt;/li>
&lt;li>The env variables are exposed differently too. For example, &lt;code>process.env.NODE_ENV === 'development'&lt;/code> becomes &lt;code>import.meta.env.DEV&lt;/code> (which is a nice built-in boolean). &lt;a href="https://vitejs.dev/guide/env-and-mode.html">There&amp;rsquo;s plenty more options&lt;/a>, including HTML env replacement and such.&lt;/li>
&lt;li>In CRA, I had the root folder for the sources configured so that &lt;code>import&lt;/code> statements looked like &lt;code>import PdfPreview from 'components/pdf-preview';&lt;/code>. In Vite (or maybe in general now?), you&amp;rsquo;re supposed to have a clear prefix, for example: &lt;code>import PdfPreview from '~/components/pdf-preview';&lt;/code>. Which makes sense and I kinda like - local dependencies are clearly different from global/external ones.
&lt;ul>
&lt;li>I only changed the often suggested &lt;code>@&lt;/code> prefix to &lt;code>~&lt;/code>, which makes more sense to me as the &amp;ldquo;home&amp;rdquo; designation. &lt;code>~&lt;/code> is obviously inspired by *nix conventions, while &lt;code>@&lt;/code> gives me flashbacks from configuring DNS zones.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h3 id="workers">Workers&lt;/h3>
&lt;p>Since PDF generation inside the browser, on the client side, is a very compute-heavy task, it needs to be done in a worker. Otherwise, the browser would hang for up to minutes at a time. So it&amp;rsquo;s a pretty crucial part of ReCalendar. It was also the source of some frustratingly confusing and misleading errors.&lt;/p>
&lt;p>Starting with &lt;code>ReferenceError: $RefreshReg$ is not defined&lt;/code>. Or it&amp;rsquo;s close cousin, &lt;code>ReferenceError: $RefreshSig$ is not defined&lt;/code>. What was more bizarre is that it was coming from React components from the configurator. Ones that should not be needed by the worker. Turns out that I had &lt;a href="https://github.com/klimeryk/recalendar.js/blob/5a292dbb653058989af71ac1284219a97d33bb9c/src/configuration-form/itinerary.jsx#L24">some constants&lt;/a> defined in those files that were being used in the PDF worker. Because, you know, magic strings are bad. And it made sense to keep those constants with the components that use them. However, it seems Vite (Rollup?) had troubles handling that and tried to load the UI dependencies (like &lt;code>@dnd-kit/sortable&lt;/code>) that were not meant to be loaded in a worker. Resulting in the above confusing error.&lt;/p>
&lt;p>The solution was simple: move the constants to &lt;a href="https://github.com/klimeryk/recalendar.js/blob/5ab3ac71c1c3c8f7a96ed271a092fb57e3c23874/src/lib/itinerary-utils.js">a separate file&lt;/a>. Now the PDF worker had a clear and simple dependency to load.&lt;/p>
&lt;p>Next error was much simpler to figure out: &lt;code>Cannot use import statement outside a module&lt;/code>. I just had to declare the worker as an ES module:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">export&lt;/span> &lt;span style="color:#66d9ef">default&lt;/span> &lt;span style="color:#a6e22e">defineConfig&lt;/span>( {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">// ...
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span> &lt;span style="color:#a6e22e">worker&lt;/span>&lt;span style="color:#f92672">:&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">format&lt;/span>&lt;span style="color:#f92672">:&lt;/span> &lt;span style="color:#e6db74">&amp;#39;es&amp;#39;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">// ...
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span> },
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>} );
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="dayjs-dynamic-locale-loading">Day.js dynamic locale loading&lt;/h3>
&lt;p>A bit of backstory: ReCalendar has awesome community members that helped translate it into 16 languages 💖 However, there&amp;rsquo;s more that could be done! Prompted by &lt;a href="https://github.com/klimeryk/recalendar.js/issues/96">a user issue&lt;/a> requesting another language, I realized that while the configurator requires translations, most of the generated PDF is just days of the week and months. And user-provided strings (which, by definition, they &amp;ldquo;translate&amp;rdquo; themselves in whatever language/format they want).&lt;/p>
&lt;p>This &lt;a href="https://github.com/klimeryk/recalendar.js/issues/96#issuecomment-1763503687">gave me an idea&lt;/a> to simply expose &lt;a href="https://day.js.org/docs/en/i18n/i18n">all the available locales from Day.js&lt;/a>. The &lt;a href="https://github.com/klimeryk/recalendar.js/commit/f72bfeb9c6d50f258ce9f51edfdeb71d0b355884">change was quite simple&lt;/a>. However, it relied on &lt;code>require&lt;/code> to dynamically load the JS files with the selected locale. It needed a method that accepted strings generated from user input (locale selection).&lt;/p>
&lt;p>The problem: Vite is built around ES modules. &lt;code>require&lt;/code> is not available. There&amp;rsquo;s plugins to emulate it, but that&amp;rsquo;s another dependency. However, there&amp;rsquo;s &lt;code>[import()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import)&lt;/code> for loading modules asynchronously. And &lt;a href="https://vitejs.dev/guide/features.html#dynamic-import">Vite supports it&lt;/a>. Perfect, right? Not quite. &lt;a href="https://github.com/vitejs/vite/issues/14102">It does not work for files from &lt;code>node_modules&lt;/code>&lt;/a> :(&lt;/p>
&lt;p>I&amp;rsquo;ve tried many workarounds - like creating a symbolic link to maybe trick the process. Even tried copying the files to my &lt;code>src&lt;/code> folder - after all, they are small and don&amp;rsquo;t change often. However, they are not meant to be loaded from a different package like that, so that was a fail.&lt;/p>
&lt;p>What did end up working was using &lt;a href="https://vitejs.dev/guide/features.html#glob-import">glob imports&lt;/a>. Through static analysis, they generate a list of all the possible paths to include (&lt;a href="https://github.com/rollup/plugins/tree/master/packages/dynamic-import-vars#limitations">as long as you follow specific guidelines&lt;/a>) and allow you to dynamically load from that list at run time.&lt;/p>
&lt;p>That finally made the locale loading work. However, it required two more tweaks:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://github.com/klimeryk/recalendar.js/commit/3e74d934fdff3e733cd6e9be7b18c412b31d8030#diff-ec767e14d91498b5b31a4ce826c4596061eb83a47d3dee00f6cbe1078232a75cR14">Needed to move the language change event to before i18next was initialized&lt;/a>. Otherwise, language detection would run before the event handler is set up. Interesting race condition - this worked with CRA, probably due to luck/different timings.&lt;/li>
&lt;li>&lt;a href="https://github.com/klimeryk/recalendar.js/commit/3e74d934fdff3e733cd6e9be7b18c412b31d8030#diff-b9ba40695c69e31208cbf682a6f2e9a0525ca32f9b841ed921d4e3483bc454ccR37">Made the glob imports eager&lt;/a> - meaning, they are preloaded. This was an admittedly a lazy and quick workaround to imports being inherently asynchronous now. Which messes with React, as the state change (Day.js changing locale) happens outside the state it monitors. Eager loading preloads them and makes the action synchronous again. Since the locale files are quite small and simple, I figured it&amp;rsquo;s worth the trade-off to finish this migration. And gives me a clear target for optimization in the future.&lt;/li>
&lt;/ul>
&lt;h2 id="performance-comparison">Performance comparison&lt;/h2>
&lt;p>Now let&amp;rsquo;s try to ask the question: &lt;strong>was it worth it&lt;/strong>? (yes, yes it was)&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>&lt;/th>
&lt;th>Create React App&lt;/th>
&lt;th>Vite&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;a href="https://developer.chrome.com/docs/lighthouse/overview/">Lighthouse&lt;/a> metrics&lt;/td>
&lt;td>Same&lt;/td>
&lt;td>Same&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Vulnerabilities&lt;/td>
&lt;td>67 (39 moderate, 16 high, 12 critical)&lt;/td>
&lt;td>0&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>node_modules&lt;/code> size&lt;/td>
&lt;td>215 MB&lt;/td>
&lt;td>188 MB&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Number of files in &lt;code>node_modules&lt;/code>&lt;/td>
&lt;td>42670&lt;/td>
&lt;td>18154&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>DOMContentLoaded&lt;/td>
&lt;td>279 ms&lt;/td>
&lt;td>117 ms&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Total app bundle size&lt;/td>
&lt;td>3.69 MB&lt;/td>
&lt;td>3.26 MB&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>This is &lt;em>not&lt;/em> an in-depth comparison. I&amp;rsquo;ve just looked at a few key metrics. Important caveat is that CRA includes the kitchen sink and more. For example, lots of testing libraries. Which I don&amp;rsquo;t have a use for right now. Vite has &lt;a href="https://vitest.dev/">Vitest&lt;/a> as a separate dependency to add when I finally face the reality that tests are indeed useful, even if the development is mostly done by one person&amp;hellip;&lt;/p>
&lt;h3 id="page-load">Page load&lt;/h3>
&lt;p>&lt;strong>No perceptible difference&lt;/strong>. I have not tried to squeeze out the smallest bundle for this project (it&amp;rsquo;s on my TODO). So the bundle size is quite large (~3 MB). Then again, it has robust i18n, date and PDF capabilities. &lt;code>DOMContentLoaded&lt;/code> was halved, but it&amp;rsquo;s already been quite low so hard to say how perceptible it is.&lt;/p>
&lt;p>Then again, these tests were done quickly and on a modern MacBook Pro. I need to test them on lower-end machines, where these improvements could make a much more noticeable difference.&lt;/p>
&lt;h3 id="lighthouse-metrics">Lighthouse metrics&lt;/h3>
&lt;p>&lt;img src="lighthouse-score.png" alt="Lighthouse score">&lt;/p>
&lt;p>&lt;strong>Same before and after migration&lt;/strong>. Like mentioned above, there&amp;rsquo;s potential for further optimization, but that has not been the focus so far.&lt;/p>
&lt;h3 id="security-audit">Security audit&lt;/h3>
&lt;p>&lt;strong>From all sorts of vulnerabilities to zero&lt;/strong>. Because CRA has not been updated in more than a year. And even then, it had outdated dependencies. Which leads to many alerts when running a security audit (&lt;code>npm audit&lt;/code> or &lt;code>yarn audit&lt;/code>). After the migration, the number simply went to zero, which is great to see.&lt;/p>
&lt;h3 id="dependencies">Dependencies&lt;/h3>
&lt;p>&lt;strong>13% less in size, but a staggering 80% less number of files&lt;/strong>. I&amp;rsquo;d guess this is related to the fact that Vite is written in Go, but also that CRA brings in a lot of dependencies around testing and such. Which are optional for Vite. I did not dig further into verifying these assumptions, though. I&amp;rsquo;ll leave that to the reader - or future me ;)&lt;/p>
&lt;h2 id="conclusion">Conclusion&lt;/h2>
&lt;p>Based on these experiences and results, &lt;strong>would I recommend migrating from CRA to Vite? Yes, definitely&lt;/strong>. The challenges and changes were not as extensive as I feared. All metrics improved. And I feel the project has more solid and future-proof foundation now. I&amp;rsquo;m excited to start working on some new features I&amp;rsquo;ve been postponing!&lt;/p></content></item><item><title>Use Midnight Commander like a pro</title><link>https://klimer.eu/2015/05/01/use-midnight-commander-like-a-pro/</link><pubDate>Fri, 01 May 2015 17:11:00 +0000</pubDate><guid>https://klimer.eu/2015/05/01/use-midnight-commander-like-a-pro/</guid><description>&lt;p>&lt;a href="https://news.ycombinator.com/item?id=39075316">Check the discussion on Hacker News&lt;/a> about this post for a lively discourse and more tips!&lt;/p>
&lt;p>If you’ve used an &lt;code>*nix&lt;/code> system, at some point you’ve stumbled upon &lt;a href="http://www.midnight-commander.org/">Midnight Commander&lt;/a>, a file manager based on the venerable Norton Commander. You’re probably familiar with the basic operations (&lt;code>F5&lt;/code> for copying, &lt;code>F6&lt;/code> for moving, &lt;code>F8&lt;/code> for deleting, etc.) and how to switch panels (ummm, the &lt;code>Tab&lt;/code> key). But &lt;code>mc&lt;/code> offers so much more than that. This article aims to show all the useful (YMMV) shortcuts and functionalities that are often overlooked. Most of them can be accessed using the menu (&lt;code>F9&lt;/code>), but who has the time to do that?&lt;/p></description><content>&lt;p>&lt;a href="https://news.ycombinator.com/item?id=39075316">Check the discussion on Hacker News&lt;/a> about this post for a lively discourse and more tips!&lt;/p>
&lt;p>If you’ve used an &lt;code>*nix&lt;/code> system, at some point you’ve stumbled upon &lt;a href="http://www.midnight-commander.org/">Midnight Commander&lt;/a>, a file manager based on the venerable Norton Commander. You’re probably familiar with the basic operations (&lt;code>F5&lt;/code> for copying, &lt;code>F6&lt;/code> for moving, &lt;code>F8&lt;/code> for deleting, etc.) and how to switch panels (ummm, the &lt;code>Tab&lt;/code> key). But &lt;code>mc&lt;/code> offers so much more than that. This article aims to show all the useful (YMMV) shortcuts and functionalities that are often overlooked. Most of them can be accessed using the menu (&lt;code>F9&lt;/code>), but who has the time to do that?&lt;/p>
&lt;p>Before we get started, let’s establish some facts. This article was written and tested on the following software:&lt;/p>
&lt;ul>
&lt;li>Midnight Commander 4.8.13&lt;/li>
&lt;li>GNU bash 4.2.53&lt;/li>
&lt;/ul>
&lt;p>Oh, and make sure you’re running a modern and UTF-8 friendly terminal - for example, rxvt-unicode.&lt;/p>
&lt;h1 id="hold-your-horses">Hold your horses&lt;/h1>
&lt;p>There’s actually one thing I’d recommend doing before you run &lt;code>mc&lt;/code>. &lt;code>mc&lt;/code> has the ability to exit to its current directory. Meaning, you can navigate the filesystem using &lt;code>mc&lt;/code> (sometimes it’s easier than &lt;code>cd&lt;/code>ing into that one directory buried deep down &lt;em>somewhere&lt;/em>) and when you quit &lt;code>mc&lt;/code> (&lt;code>F10&lt;/code>), your shell will automagically &lt;code>cd&lt;/code> to that directory. This is done thanks to the &lt;code>mc-wrapper&lt;/code> script that should be bundled with your installation of &lt;code>mc&lt;/code>. The exact location is dependent on your distribution - in mine (Gentoo) it’s &lt;code>/usr/libexec/mc/&lt;/code>, in Ubuntu supposedly it’s in &lt;code>/usr/share/mc/bin/&lt;/code>. Once found, modify your &lt;code>~/.bashrc&lt;/code>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>alias mc&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#39;. /usr/libexec/mc/mc-wrapper.sh&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Restart your shell, launch &lt;code>mc&lt;/code>, change to another directory, exit and your shell should be set to that new directory.&lt;/p>
&lt;h1 id="selecting-files">Selecting files&lt;/h1>
&lt;ul>
&lt;li>&lt;code>Insert&lt;/code> (&lt;code>Ctrl + t&lt;/code> alternatively) - select files (for example, for copying, moving or deleting).&lt;/li>
&lt;li>&lt;code>+&lt;/code> - select files based on a pattern.&lt;/li>
&lt;li>&lt;code>\&lt;/code> -_un_select files based on a pattern.&lt;/li>
&lt;li>&lt;code>*&lt;/code> - reverse selection. If nothing was selected, all files will get selected.&lt;/li>
&lt;/ul>
&lt;h1 id="accessing-the-shell">Accessing the shell&lt;/h1>
&lt;ul>
&lt;li>There’s a shell awaiting your command at the bottom of the screen - just start typing (when no other command dialog is open, of course).&lt;/li>
&lt;li>Since &lt;code>Tab&lt;/code> is bound to switching panels (or moving the focus in dialogs), you have to use &lt;code>Esc Tab&lt;/code> to use autocompletion. Hit it twice to get all the possible completions (just like in a shell). This works in dialogs too.&lt;/li>
&lt;li>If you want inspect the output of the command, do some input or just prefer a bigger console, no need to quit &lt;code>mc&lt;/code>. Just hit &lt;code>Ctrl + o&lt;/code> - the effect will be similar to putting &lt;code>mc&lt;/code> in the background but with a nice perk. Your current working directory from &lt;code>mc&lt;/code> will be passed on to the shell… and vice versa! Hit &lt;code>Ctrl + o&lt;/code> again to return to &lt;code>mc&lt;/code>.&lt;/li>
&lt;li>&lt;code>Ctrl + Enter&lt;/code> or &lt;code>Alt + Enter&lt;/code> - copy the currently selected file’s name to the shell.&lt;/li>
&lt;li>&lt;code>Ctrl + Shift + Enter&lt;/code> - same as above, but the full path is copied.&lt;/li>
&lt;/ul>
&lt;h1 id="internal-viewer-f3-and-editor-f4">Internal viewer (&lt;code>F3&lt;/code>) and editor (&lt;code>F4&lt;/code>)&lt;/h1>
&lt;ul>
&lt;li>The internal viewer has many built in modes for “previewing” the content of the file. Try “viewing” a binary, an archive, a DOC document or an image. In some cases, external programs are needed in order for this “previewing” to work.&lt;/li>
&lt;li>If you want to preview the “raw” contents of the file, hit &lt;code>Shift + F3&lt;/code>.&lt;/li>
&lt;li>While the internal viewer and editor are powerful, sometimes you want to use your preferred software (&lt;em>cough_vim_cough&lt;/em>). You can do so by setting the &lt;code>PAGER&lt;/code> (for viewer) and &lt;code>EDITOR&lt;/code> (for editor) variables (for example, in your &lt;code>~/.bashrc&lt;/code> file). Then toggle the &lt;code>Options -&amp;gt; Configuration -&amp;gt; Use interal edit/view&lt;/code> option (access the top menu by pressing &lt;code>F9&lt;/code>).&lt;/li>
&lt;/ul>
&lt;h1 id="panels">Panels&lt;/h1>
&lt;ul>
&lt;li>&lt;code>Alt + ,&lt;/code> - switch &lt;code>mc&lt;/code>’s layout from left-right to top-bottom. Mind = blown. Useful for operating on files with long names.&lt;/li>
&lt;li>&lt;code>Alt + t&lt;/code> - switch the panel’s listing mode in a loop: default, brief, long, user-defined. “long” is especially useful, because it maximises one panel so that it takes full width of the window and longer filenames fit on screen.&lt;/li>
&lt;li>&lt;code>Alt + i&lt;/code> - synchronize the active panel with the other panel. That is, show the current directory in the other panel.&lt;/li>
&lt;li>&lt;code>Ctrl + u&lt;/code> - swap panels.&lt;/li>
&lt;li>&lt;code>Alt + o&lt;/code> - if the currently selected file is a directory, load that directory on the other panel and move the selection to the next file. If the currently selected file is not a directory, load the parent directory on the other panel and moves the selection to the next file. This is useful for quick checking the contents of a list of directories.&lt;/li>
&lt;li>&lt;code>Ctrl + PgUp&lt;/code> (or just left arrow, if you’ve enabled &lt;code>Lynx-like motion&lt;/code>, see later) - move to the parent directory.&lt;/li>
&lt;li>&lt;code>Alt + Shift + h&lt;/code> - show the directory history. Might be easier to navigate than going back one entry at a time.&lt;/li>
&lt;li>&lt;code>Alt + y&lt;/code> - move to the previous directory in history.&lt;/li>
&lt;li>&lt;code>Alt + u&lt;/code> - move to the next directory in history.&lt;/li>
&lt;/ul>
&lt;h1 id="searching-files">Searching files&lt;/h1>
&lt;ul>
&lt;li>&lt;code>Alt + ?&lt;/code> - shows the full Find dialog.&lt;/li>
&lt;li>&lt;code>Alt + s&lt;/code> or &lt;code>Ctrl + s&lt;/code> - quick search mode. Start typing and the selection will move to the first matching file. Press the shortcut again to jump to another match. Use wildcards (&lt;code>*&lt;/code>, &lt;code>?&lt;/code>) for easier matching.&lt;/li>
&lt;/ul>
&lt;h1 id="common-actions">Common actions&lt;/h1>
&lt;ul>
&lt;li>&lt;code>Ctrl + Space&lt;/code> - calculate the size of the selected directories. Press this shortcut when the selection is on &lt;code>..&lt;/code> to calculate the size of all the directories in the current directory.&lt;/li>
&lt;li>&lt;code>Ctrl + x s&lt;/code> (that is press &lt;code>Ctrl + x&lt;/code>, &lt;a href="https://www.youtube.com/watch?v=L0MK7qz13bU">let it go&lt;/a> and then press &lt;code>s&lt;/code>) - create a symbolic link (change &lt;code>s&lt;/code> to &lt;code>l&lt;/code> for a hardlink). I find it very useful and intuitive - the link will, of course, be created in the other panel. You can change it’s destination and name, like with any other file operation.&lt;/li>
&lt;li>&lt;code>Ctrl + x c&lt;/code> - open the &lt;code>chmod&lt;/code> dialog.&lt;/li>
&lt;li>&lt;code>Ctrl + x o&lt;/code> - open the &lt;code>chown&lt;/code> dialog.&lt;/li>
&lt;/ul>
&lt;h1 id="virtual-file-system-vfs">Virtual File System (VFS)&lt;/h1>
&lt;p>&lt;code>mc&lt;/code> has a concept known as Virtual File System. Try “entering” an archive (&lt;code>*.tar.gz&lt;/code>, &lt;code>*.rpm&lt;/code> or even &lt;code>*.jar&lt;/code>) - you’ll be able to browse the contents of the archive like a normal folder, without unpacking it first. You extract selected files from the archive by just copying them to the other panel. Bonus points: try “entering” a… &lt;code>*.patch&lt;/code> file.&lt;/p>
&lt;p>This concept is even more powerful when you realize that remote locations can be viewed the same way. A quick way to browse an FTP location is to just &lt;code>cd&lt;/code> to it: &lt;code>cd ftp://mirrors.tera-byte.com/pub/gentoo&lt;/code> (first Gentoo FTP mirror I found). You’ll be able to interact with files as you normally do. To exit this remote location, &lt;code>cd&lt;/code> to a local directory. Just typing &lt;code>cd&lt;/code> will suffice as it will take you to your home directory.&lt;/p>
&lt;p>VFS works for SFTP and Samba shares too. Check the manpages for more information on how to specify user/pass, etc.&lt;/p>
&lt;h1 id="useful-options">Useful options&lt;/h1>
&lt;ul>
&lt;li>&lt;strong>Configuration&lt;/strong>
&lt;ul>
&lt;li>&lt;code>Verbose operation&lt;/code> and &lt;code>Compute totals&lt;/code> - so that operations like copy/move have a more detailed progress dialogs.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>Layout&lt;/strong>
&lt;ul>
&lt;li>&lt;code>Equal split&lt;/code> - uncheck to define your own ratio for panels. Maybe you prefer one panel bigger than the other? Useful especially if you keep one of the panels in tree mode (or maybe info/quick view, too).&lt;/li>
&lt;li>Uncheck &lt;code>Hintbar visible&lt;/code> - one more line available, one less line of noise.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>Panel options&lt;/strong>
&lt;ul>
&lt;li>&lt;code>Show backup files&lt;/code> and &lt;code>Show hidden files&lt;/code> - I keep both enabled, as I often work with configuration files, etc.&lt;/li>
&lt;li>&lt;code>Lynx-like motion&lt;/code> - mentioned above, makes left arrow go to parent directory, while the right arrow enters the directory under selection. Faster than &lt;code>Home&lt;/code>, &lt;code>Enter&lt;/code>, &lt;code>Home&lt;/code>, &lt;code>Enter&lt;/code>, etc. This options is quite smart, that is if the shell command line is not empty, the arrows work as usual and allow moving the cursor in the command line.&lt;/li>
&lt;li>&lt;code>File highlight&lt;/code> -&amp;gt; &lt;code>File types&lt;/code> is useful, as it uses a different color for example for executable files. &lt;code>Permissions&lt;/code>, for me, is not that useful, but I can definitely see it’s use, for example, for sysadmins.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>Appearance&lt;/strong>
&lt;ul>
&lt;li>Only one option here, &lt;code>Skins&lt;/code>. You can check out different skins shipped with &lt;code>mc&lt;/code> - just select one from the list. I prefer &lt;code>gotar&lt;/code>, because it plays well with my &lt;a href="http://ethanschoonover.com/solarized">solarized&lt;/a> terminal colors.&lt;/li>
&lt;li>Useful tip - set up a different skin when logged in as the &lt;code>root&lt;/code> user. It’ll be easier to differentiate between root’s and normal user’s session, when you’re swapping between them (as is often the case).&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h1 id="bonus-assignments">Bonus assignments&lt;/h1>
&lt;ul>
&lt;li>Define your own listing mode (&lt;code>Right/Left&lt;/code> -&amp;gt; &lt;code>Listing mode...&lt;/code> -&amp;gt; &lt;code>User defined&lt;/code>). Hit &lt;code>F1&lt;/code> to see available columns and options.&lt;/li>
&lt;li>Play around in tree mode: &lt;code>Right/Left&lt;/code> -&amp;gt; &lt;code>Tree&lt;/code> or &lt;code>Command&lt;/code> -&amp;gt; &lt;code>Directory tree&lt;/code>.&lt;/li>
&lt;li>Compare directories (&lt;code>Ctrl + x d&lt;/code>)&lt;/li>
&lt;li>Fill up the directory hotlist (&lt;code>Ctrl + \&lt;/code>)&lt;/li>
&lt;/ul>
&lt;p>Well, that was a lot to take in. Of course, this list is not complete (that’s what &lt;code>man mc&lt;/code> is there for), but I’ve selected the commands and functionalities that are the most useful to &lt;em>me&lt;/em>. Embrace the ones you find useful, forget the rest and learn about the other ones I’ve missed!&lt;/p>
&lt;p>Happy browsing!&lt;/p></content></item><item><title>Activities, places and the visitor pattern</title><link>https://klimer.eu/2014/09/22/activities-places-and-the-visitor-pattern/</link><pubDate>Mon, 22 Sep 2014 17:01:00 +0000</pubDate><guid>https://klimer.eu/2014/09/22/activities-places-and-the-visitor-pattern/</guid><description>&lt;p>If you’re writing a GWT application you are most likely following the MVP pattern. With GWT 2.1 the &lt;a href="http://www.gwtproject.org/doc/latest/DevGuideMvpActivitiesAndPlaces.html">Activities and Places API&lt;/a> was introduced and while it’s not strictly an MVP framework, it’s a good base for the architecture of your application.&lt;/p>
&lt;p>A core component of Activities and Places is the &lt;a href="http://www.gwtproject.org/javadoc/latest/com/google/gwt/activity/shared/ActivityMapper.html">&lt;code>ActivityMapper&lt;/code>&lt;/a> interface. Its role is simple - you get a &lt;code>Place&lt;/code> and based on it an appropriate &lt;code>Activity&lt;/code> should be returned. There’s one problem - you most likely will want to choose the &lt;code>Activity&lt;/code> based on the type of the provided &lt;code>Place&lt;/code>. The usual approach (mentioned even in the official documentation) is a long chain of &lt;code>if (place instanceof CustomPlace) else if (place instanceof CustomPlace2)&lt;/code>… etc. You might have a similar &lt;code>if/else&lt;/code> chain somewhere else in your application where you want to react to a &lt;code>PlaceChangedEvent&lt;/code>. If you add a new &lt;code>Place&lt;/code>, you have to remember to add (another…) &lt;code>if else&lt;/code> in all those places.&lt;/p></description><content>&lt;p>If you’re writing a GWT application you are most likely following the MVP pattern. With GWT 2.1 the &lt;a href="http://www.gwtproject.org/doc/latest/DevGuideMvpActivitiesAndPlaces.html">Activities and Places API&lt;/a> was introduced and while it’s not strictly an MVP framework, it’s a good base for the architecture of your application.&lt;/p>
&lt;p>A core component of Activities and Places is the &lt;a href="http://www.gwtproject.org/javadoc/latest/com/google/gwt/activity/shared/ActivityMapper.html">&lt;code>ActivityMapper&lt;/code>&lt;/a> interface. Its role is simple - you get a &lt;code>Place&lt;/code> and based on it an appropriate &lt;code>Activity&lt;/code> should be returned. There’s one problem - you most likely will want to choose the &lt;code>Activity&lt;/code> based on the type of the provided &lt;code>Place&lt;/code>. The usual approach (mentioned even in the official documentation) is a long chain of &lt;code>if (place instanceof CustomPlace) else if (place instanceof CustomPlace2)&lt;/code>… etc. You might have a similar &lt;code>if/else&lt;/code> chain somewhere else in your application where you want to react to a &lt;code>PlaceChangedEvent&lt;/code>. If you add a new &lt;code>Place&lt;/code>, you have to remember to add (another…) &lt;code>if else&lt;/code> in all those places.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">AppActivityMapper&lt;/span> &lt;span style="color:#66d9ef">implements&lt;/span> ActivityMapper {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">@Override&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> Activity &lt;span style="color:#a6e22e">getActivity&lt;/span>(Place place) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> activity &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#66d9ef">null&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">if&lt;/span> (place &lt;span style="color:#66d9ef">instanceof&lt;/span> StartPlace) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#66d9ef">new&lt;/span> StartActivity();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> } &lt;span style="color:#66d9ef">else&lt;/span> &lt;span style="color:#66d9ef">if&lt;/span> (place &lt;span style="color:#66d9ef">instanceof&lt;/span> SearchPlace) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#66d9ef">new&lt;/span> SearchActivity();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> } &lt;span style="color:#66d9ef">else&lt;/span> &lt;span style="color:#66d9ef">if&lt;/span> (place &lt;span style="color:#66d9ef">instanceof&lt;/span> CustomerPlace) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#66d9ef">new&lt;/span> CustomerActivity();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#66d9ef">null&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>There’s gotta a be a better way!&lt;/p>
&lt;p>And there is: &lt;a href="http://en.wikipedia.org/wiki/Visitor_pattern">the visitor pattern&lt;/a>.&lt;/p>
&lt;blockquote>
&lt;p>A way of separating an algorithm from an object structure on which it operates. A practical result of this separation is the ability to add new operations to existing object structures without modifying those structures.&lt;/p>
&lt;/blockquote>
&lt;p>Sounds exactly like something we need! If the details are unclear at this point, don’t worry. It’s best to see it in action and how it fits with our needs.&lt;/p>
&lt;p>Let’s say we have three custom &lt;code>Place&lt;/code>s in our application: &lt;code>StartPlace&lt;/code>, &lt;code>SearchPlace&lt;/code> and &lt;code>CustomerPlace&lt;/code>. They can be with parameters/tokens or not - it doesn’t matter.&lt;/p>
&lt;p>Now, we’ll define the interface of our visitor. This visitor will be able to “visit” every place that “accepts” it and invoke some place-specific method.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">interface&lt;/span> &lt;span style="color:#a6e22e">PlaceVisitor&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">void&lt;/span> &lt;span style="color:#a6e22e">visitStartPlace&lt;/span>(StartPlace place);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">void&lt;/span> &lt;span style="color:#a6e22e">visitSearchPlace&lt;/span>(SearchPlace place);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">void&lt;/span> &lt;span style="color:#a6e22e">visitCustomerPlace&lt;/span>(CustomerPlace place);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>As you can see, we have a method for each of our custom places. Every method takes a place as a parameter and returns nothing. We could return an &lt;code>Activity&lt;/code> but as we’ll see further on, it limits the usage of this interface and is actually against the visitor pattern.&lt;/p>
&lt;p>Now, let’s add a new base class for all of our custom places. It could be an interface, but since we always have to extend the &lt;code>Place&lt;/code> class, we might as well extend it and add our method:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">abstract&lt;/span> &lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">AppPlace&lt;/span> &lt;span style="color:#66d9ef">extends&lt;/span> Place {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">abstract&lt;/span> &lt;span style="color:#66d9ef">void&lt;/span> &lt;span style="color:#a6e22e">accept&lt;/span>(PlaceVisitor visitor);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>We only need to add one method - one that “accepts” the visitor. We leave the implementation to the specific place - that’s the whole point. We can now modify our &lt;code>Place&lt;/code> to extend our &lt;code>AppPlace&lt;/code> instead of just &lt;code>Place&lt;/code>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">StartPlace&lt;/span> &lt;span style="color:#66d9ef">extends&lt;/span> AppPlace {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">@Override&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">void&lt;/span> &lt;span style="color:#a6e22e">accept&lt;/span>(PlaceVisitor visitor) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> visitor.&lt;span style="color:#a6e22e">visitStartPlace&lt;/span>(&lt;span style="color:#66d9ef">this&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">SearchPlace&lt;/span> &lt;span style="color:#66d9ef">extends&lt;/span> AppPlace {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">@Override&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">void&lt;/span> &lt;span style="color:#a6e22e">accept&lt;/span>(PlaceVisitor visitor) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> visitor.&lt;span style="color:#a6e22e">visitSearchPlace&lt;/span>(&lt;span style="color:#66d9ef">this&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">CustomerPlace&lt;/span> &lt;span style="color:#66d9ef">extends&lt;/span> AppPlace {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">@Override&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">void&lt;/span> &lt;span style="color:#a6e22e">accept&lt;/span>(PlaceVisitor visitor) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> visitor.&lt;span style="color:#a6e22e">visitCustomerPlace&lt;/span>(&lt;span style="color:#66d9ef">this&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The pieces should start falling into place now - we can see above that it’s the place that decides to invoke a specific method on the visitor. This way, the visitor doesn’t know what place is accepting it, but the place can tell it: “Hey, you’re visiting a &lt;code>SearchPlace&lt;/code>, act accordingly”.&lt;/p>
&lt;p>We can now replace our long &lt;code>ActivityMapper&lt;/code> implementation with a much simpler one:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">AppActivityMapper&lt;/span> &lt;span style="color:#66d9ef">implements&lt;/span> ActivityMapper, PlaceVisitor {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">private&lt;/span> Activity activity;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">@Override&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> Activity &lt;span style="color:#a6e22e">getActivity&lt;/span>(Place place) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> activity &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#66d9ef">null&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">if&lt;/span> (place &lt;span style="color:#66d9ef">instanceof&lt;/span> AppPlace) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ((AppPlace) place).&lt;span style="color:#a6e22e">accept&lt;/span>(&lt;span style="color:#66d9ef">this&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> activity;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">@Override&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">void&lt;/span> &lt;span style="color:#a6e22e">visitStartPlace&lt;/span>(StartPlace place) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> activity &lt;span style="color:#f92672">=&lt;/span> injector.&lt;span style="color:#a6e22e">getStartActivity&lt;/span>();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">@Override&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">void&lt;/span> &lt;span style="color:#a6e22e">visitSearchPlace&lt;/span>(SearchPlace place) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> activity &lt;span style="color:#f92672">=&lt;/span> injector.&lt;span style="color:#a6e22e">getSearchActivity&lt;/span>();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">@Override&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">void&lt;/span> &lt;span style="color:#a6e22e">visitCustomerPlace&lt;/span>(CustomerPlace place) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> activity &lt;span style="color:#f92672">=&lt;/span> injector.&lt;span style="color:#a6e22e">getCustomerActivity&lt;/span>();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Now, whenever we add a new &lt;code>Place&lt;/code>, we make it extend &lt;code>AppPlace&lt;/code>, this makes us provide the implementation for the &lt;code>accept&lt;/code> method which in turn causes us to add a new method to the &lt;code>PlaceVisitor&lt;/code> interface. Now, say we have a &lt;code>PlaceChangedEvent&lt;/code>’s handler somewhere we can re-use the &lt;code>PlaceVisitor&lt;/code>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">RootPresenter&lt;/span> ... &lt;span style="color:#66d9ef">implements&lt;/span> PlaceVisitor {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#a6e22e">RootPresenter&lt;/span>(...) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> eventBus.&lt;span style="color:#a6e22e">addHandler&lt;/span>(PlaceChangeEvent.&lt;span style="color:#a6e22e">TYPE&lt;/span>, &lt;span style="color:#66d9ef">new&lt;/span> PlaceChangeEvent.&lt;span style="color:#a6e22e">Handler&lt;/span>() {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">@Override&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">void&lt;/span> &lt;span style="color:#a6e22e">onPlaceChange&lt;/span>(PlaceChangeEvent event) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Place place &lt;span style="color:#f92672">=&lt;/span> event.&lt;span style="color:#a6e22e">getNewPlace&lt;/span>();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">if&lt;/span> (place &lt;span style="color:#66d9ef">instanceof&lt;/span> AppPlace) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ((AppPlace) place).&lt;span style="color:#a6e22e">accept&lt;/span>(RootPresenter.&lt;span style="color:#a6e22e">this&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> });
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">@Override&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">void&lt;/span> &lt;span style="color:#a6e22e">visitStartPlace&lt;/span>(StartPlace place) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> view.&lt;span style="color:#a6e22e">getStartButton&lt;/span>.&lt;span style="color:#a6e22e">setActive&lt;/span>(&lt;span style="color:#66d9ef">true&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">// Or whatever else&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">// etc...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Whenever we add a new &lt;code>Place&lt;/code> we have to add a new method to the &lt;code>PlaceVisitor&lt;/code> which in turn flags any class that implements it with an error - now it’s impossible to miss handling a new &lt;code>Place&lt;/code> somewhere in your code.&lt;/p>
&lt;p>One more point worth mentioning - in the last snippet you can see that making the &lt;code>visit*&lt;/code> methods return an &lt;code>Activity&lt;/code> directly wouldn’t be a good idea - while it would be useful in the &lt;code>ActivityManager&lt;/code>’s implementation, it would be useless in &lt;code>RootPresenter&lt;/code>.&lt;/p>
&lt;p>I highly recommend reading the appropriate chapter from the great &lt;a href="http://en.wikipedia.org/wiki/Design_Patterns">Design Patterns&lt;/a> book from &lt;a href="http://c2.com/cgi/wiki?GangOfFour">the Gang of Four&lt;/a>. The visitor pattern is a very useful one and the chapter gives examples when it’s good to use and when a different approach is better.&lt;/p>
&lt;p>Happy coding!&lt;/p></content></item><item><title>Testing asynchronous GWT-RPC services</title><link>https://klimer.eu/2014/08/28/testing-asynchronous-gwt-rpc-services/</link><pubDate>Thu, 28 Aug 2014 17:01:00 +0000</pubDate><guid>https://klimer.eu/2014/08/28/testing-asynchronous-gwt-rpc-services/</guid><description>&lt;p>Continuing the theme of testing with gwtmockito, I’d like to show you a neat class that’s bundled with gwtmockito that allows for easy mocking of GWT-RPC asynchronous services.&lt;/p>
&lt;p>The class I’m talking about is &lt;a href="http://google.github.io/gwtmockito/javadoc/com/google/gwtmockito/AsyncAnswers.html">AsyncAnswers&lt;/a>. It’s meant to be used with the &lt;a href="http://docs.mockito.googlecode.com/hg/org/mockito/Mockito.html#doAnswer(org.mockito.stubbing.Answer)">doAnswer&lt;/a> stubber.&lt;/p>
&lt;p>Supposing we have a &lt;code>LoginServiceAsync&lt;/code> class:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">interface&lt;/span> &lt;span style="color:#a6e22e">LoginServiceAsync&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">void&lt;/span> &lt;span style="color:#a6e22e">login&lt;/span>(String login, String password, AsyncCallback&lt;span style="color:#f92672">&amp;lt;&lt;/span>SomePojo&lt;span style="color:#f92672">&amp;gt;&lt;/span> callback);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Assuming &lt;code>service&lt;/code> is a mock for &lt;code>LoginServiceAsync&lt;/code>, we could simulate a successful trip to the server with:&lt;/p></description><content>&lt;p>Continuing the theme of testing with gwtmockito, I’d like to show you a neat class that’s bundled with gwtmockito that allows for easy mocking of GWT-RPC asynchronous services.&lt;/p>
&lt;p>The class I’m talking about is &lt;a href="http://google.github.io/gwtmockito/javadoc/com/google/gwtmockito/AsyncAnswers.html">AsyncAnswers&lt;/a>. It’s meant to be used with the &lt;a href="http://docs.mockito.googlecode.com/hg/org/mockito/Mockito.html#doAnswer(org.mockito.stubbing.Answer)">doAnswer&lt;/a> stubber.&lt;/p>
&lt;p>Supposing we have a &lt;code>LoginServiceAsync&lt;/code> class:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">interface&lt;/span> &lt;span style="color:#a6e22e">LoginServiceAsync&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">void&lt;/span> &lt;span style="color:#a6e22e">login&lt;/span>(String login, String password, AsyncCallback&lt;span style="color:#f92672">&amp;lt;&lt;/span>SomePojo&lt;span style="color:#f92672">&amp;gt;&lt;/span> callback);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Assuming &lt;code>service&lt;/code> is a mock for &lt;code>LoginServiceAsync&lt;/code>, we could simulate a successful trip to the server with:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>doAnswer(AsyncAnswers.&lt;span style="color:#a6e22e">returnSuccess&lt;/span>(somePojoInstance)).&lt;span style="color:#a6e22e">when&lt;/span>(service).&lt;span style="color:#a6e22e">login&lt;/span>(eq(login), eq(password), Matchers.&lt;span style="color:#f92672">&amp;lt;&lt;/span>AsyncCallback&lt;span style="color:#f92672">&amp;lt;&lt;/span>SomePojo&lt;span style="color:#f92672">&amp;gt;&amp;gt;&lt;/span>.&lt;span style="color:#a6e22e">any&lt;/span>());
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Similarly, we can simulate that a failure occurred:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>doAnswer(AsyncAnswers.&lt;span style="color:#a6e22e">returnFailure&lt;/span>(&lt;span style="color:#66d9ef">new&lt;/span> LoginException(&lt;span style="color:#e6db74">&amp;#34;Unknown user&amp;#34;&lt;/span>))).&lt;span style="color:#a6e22e">when&lt;/span>(service).&lt;span style="color:#a6e22e">login&lt;/span>(eq(login), eq(password), Matchers.&lt;span style="color:#f92672">&amp;lt;&lt;/span>AsyncCallback&lt;span style="color:#f92672">&amp;lt;&lt;/span>SomePojo&lt;span style="color:#f92672">&amp;gt;&amp;gt;&lt;/span>.&lt;span style="color:#a6e22e">any&lt;/span>());
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Everything should be working, but that line is a bit too long. For starters, we can &lt;code>import static&lt;/code> &lt;code>AsyncAnswers&lt;/code>. But the biggest sore in the eye is the &lt;code>any()&lt;/code> call. We need to explicitly set the type parameters, and for that to happen we can’t rely on static imports - we have to use the &lt;code>Matchers&lt;/code> class directly. Let’s fix that by introducing a new &lt;code>ArgumentMatcher&lt;/code>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">AnyAsyncCallback&lt;/span>&lt;span style="color:#f92672">&amp;lt;&lt;/span>T&lt;span style="color:#f92672">&amp;gt;&lt;/span> &lt;span style="color:#66d9ef">extends&lt;/span> ArgumentMatcher&lt;span style="color:#f92672">&amp;lt;&lt;/span>AsyncCallback&lt;span style="color:#f92672">&amp;lt;&lt;/span>T&lt;span style="color:#f92672">&amp;gt;&amp;gt;&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#a6e22e">AnyAsyncCallback&lt;/span>() {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">@Override&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">boolean&lt;/span> &lt;span style="color:#a6e22e">matches&lt;/span>(Object argument) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> argument &lt;span style="color:#66d9ef">instanceof&lt;/span> AsyncCallback;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Now, to use it like &lt;code>any&lt;/code> or &lt;code>anyCollection&lt;/code>, put this method somewhere, like in your base test class:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">protected&lt;/span> &lt;span style="color:#66d9ef">static&lt;/span> &lt;span style="color:#f92672">&amp;lt;&lt;/span>T&lt;span style="color:#f92672">&amp;gt;&lt;/span> AsyncCallback&lt;span style="color:#f92672">&amp;lt;&lt;/span>T&lt;span style="color:#f92672">&amp;gt;&lt;/span> &lt;span style="color:#a6e22e">anyAsyncCallback&lt;/span>(Class&lt;span style="color:#f92672">&amp;lt;&lt;/span>T&lt;span style="color:#f92672">&amp;gt;&lt;/span> clazz) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> Matchers.&lt;span style="color:#a6e22e">argThat&lt;/span>(&lt;span style="color:#66d9ef">new&lt;/span> AnyAsyncCallback&lt;span style="color:#f92672">&amp;lt;&lt;/span>T&lt;span style="color:#f92672">&amp;gt;&lt;/span>());
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>We pass around that &lt;code>&amp;lt;T&amp;gt;&lt;/code> and &lt;code>Class&amp;lt;T&amp;gt;&lt;/code> for type safety - no need for casts or &lt;code>@SuppressWarning&lt;/code>s. Now it looks less verbose and more to the point:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>doAnswer(returnSuccess(somePojoInstance)).&lt;span style="color:#a6e22e">when&lt;/span>(service).&lt;span style="color:#a6e22e">login&lt;/span>(eq(login), eq(password), anyAsyncCallback(SomPojo.&lt;span style="color:#a6e22e">class&lt;/span>));
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Happy testing!&lt;/p></content></item><item><title>Testing gwteventbinder with gwtmockito</title><link>https://klimer.eu/2014/08/27/testing-gwteventbinder-with-gwtmockito/</link><pubDate>Wed, 27 Aug 2014 21:46:00 +0000</pubDate><guid>https://klimer.eu/2014/08/27/testing-gwteventbinder-with-gwtmockito/</guid><description>&lt;p>&lt;a href="https://github.com/google/gwteventbinder">gwteventbinder&lt;/a> and &lt;a href="https://github.com/google/gwtmockito">gwtmockito&lt;/a> are great projects that are esential if you’re writing applications in Google Web Toolkit/GWT. So it was a surprise to me that they don’t play together well “out of the box”.&lt;/p>
&lt;p>See, the problem is that gwtmockito injects it’s own (safe, not using any code that requires running a browser) mocks when it encounters &lt;code>GWT.create&lt;/code> in your code. That’s very cool, but when using gwteventbinder, you need to call the &lt;code>bindEventHandlers&lt;/code> method to, well, bind the event handler. And the mock, obviously, doesn’t do that.&lt;/p></description><content>&lt;p>&lt;a href="https://github.com/google/gwteventbinder">gwteventbinder&lt;/a> and &lt;a href="https://github.com/google/gwtmockito">gwtmockito&lt;/a> are great projects that are esential if you’re writing applications in Google Web Toolkit/GWT. So it was a surprise to me that they don’t play together well “out of the box”.&lt;/p>
&lt;p>See, the problem is that gwtmockito injects it’s own (safe, not using any code that requires running a browser) mocks when it encounters &lt;code>GWT.create&lt;/code> in your code. That’s very cool, but when using gwteventbinder, you need to call the &lt;code>bindEventHandlers&lt;/code> method to, well, bind the event handler. And the mock, obviously, doesn’t do that.&lt;/p>
&lt;p>However, there’s a solution - &lt;code>FakeProvider&lt;/code>s. By registering one for the &lt;code>EventBinder&lt;/code> interface, it will be used for providing instances of &lt;code>EventBinder&lt;/code> &lt;em>and&lt;/em> its subclasses. Unfortunately, &lt;code>EventBinder&lt;/code> uses a GWT Generator for it’s implementation, and to “emulate” that during our tests, we have to resort to Java Reflection.&lt;/p>
&lt;p>The following implementation is inspired by comments and suggestions from &lt;a href="https://github.com/google/gwteventbinder/issues/17">an issue&lt;/a> raised on gwteventbinder’s tracker. You can find alternative solutions there, too.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">FakeEventBinderProvider&lt;/span> &lt;span style="color:#66d9ef">implements&lt;/span> FakeProvider&lt;span style="color:#f92672">&amp;lt;&lt;/span>EventBinder&lt;span style="color:#f92672">&amp;lt;?&amp;gt;&amp;gt;&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">@Override&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> EventBinder&lt;span style="color:#f92672">&amp;lt;?&amp;gt;&lt;/span> getFake(Class&lt;span style="color:#f92672">&amp;lt;?&amp;gt;&lt;/span> type) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> (EventBinder&lt;span style="color:#f92672">&amp;lt;?&amp;gt;&lt;/span>) Proxy.&lt;span style="color:#a6e22e">newProxyInstance&lt;/span>(FakeEventBinderProvider.&lt;span style="color:#a6e22e">class&lt;/span>.&lt;span style="color:#a6e22e">getClassLoader&lt;/span>(), &lt;span style="color:#66d9ef">new&lt;/span> Class&lt;span style="color:#f92672">&amp;lt;?&amp;gt;&lt;/span>&lt;span style="color:#960050;background-color:#1e0010">\&lt;/span>&lt;span style="color:#f92672">[&lt;/span>&lt;span style="color:#960050;background-color:#1e0010">\&lt;/span>&lt;span style="color:#f92672">]&lt;/span> { type }, &lt;span style="color:#66d9ef">new&lt;/span> InvocationHandler() {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">@Override&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> Object &lt;span style="color:#a6e22e">invoke&lt;/span>(Object proxy, Method method, &lt;span style="color:#66d9ef">final&lt;/span> Object&lt;span style="color:#960050;background-color:#1e0010">\&lt;/span>&lt;span style="color:#f92672">[&lt;/span>&lt;span style="color:#960050;background-color:#1e0010">\&lt;/span>&lt;span style="color:#f92672">]&lt;/span> args) &lt;span style="color:#66d9ef">throws&lt;/span> Throwable {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> String methodName &lt;span style="color:#f92672">=&lt;/span> method.&lt;span style="color:#a6e22e">getName&lt;/span>();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">assert&lt;/span> methodName.&lt;span style="color:#a6e22e">equals&lt;/span>(&lt;span style="color:#e6db74">&amp;#34;bindEventHandlers&amp;#34;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">final&lt;/span> List&lt;span style="color:#f92672">&amp;lt;&lt;/span>HandlerRegistration&lt;span style="color:#f92672">&amp;gt;&lt;/span> registrations &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#66d9ef">new&lt;/span> LinkedList&lt;span style="color:#f92672">&amp;lt;&lt;/span>HandlerRegistration&lt;span style="color:#f92672">&amp;gt;&lt;/span>();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> EventBus eventBus &lt;span style="color:#f92672">=&lt;/span> (EventBus) args&lt;span style="color:#960050;background-color:#1e0010">\&lt;/span>&lt;span style="color:#f92672">[&lt;/span>1&lt;span style="color:#960050;background-color:#1e0010">\&lt;/span>&lt;span style="color:#f92672">]&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> List&lt;span style="color:#f92672">&amp;lt;&lt;/span>Method&lt;span style="color:#f92672">&amp;gt;&lt;/span> presenterMethods &lt;span style="color:#f92672">=&lt;/span> getAllMethods(args&lt;span style="color:#960050;background-color:#1e0010">\&lt;/span>&lt;span style="color:#f92672">[&lt;/span>0&lt;span style="color:#960050;background-color:#1e0010">\&lt;/span>&lt;span style="color:#f92672">]&lt;/span>.&lt;span style="color:#a6e22e">getClass&lt;/span>());
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">for&lt;/span> (&lt;span style="color:#66d9ef">final&lt;/span> Method presenterMethod : presenterMethods) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">if&lt;/span> (presenterMethod.&lt;span style="color:#a6e22e">isAnnotationPresent&lt;/span>(EventHandler.&lt;span style="color:#a6e22e">class&lt;/span>)) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">@SuppressWarnings&lt;/span>(&lt;span style="color:#e6db74">&amp;#34;unchecked&amp;#34;&lt;/span>) &lt;span style="color:#75715e">// Should always be ok, since the Generator for EventBinder should do all the safe-checking &lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Class&lt;span style="color:#f92672">&amp;lt;?&lt;/span> &lt;span style="color:#66d9ef">extends&lt;/span> GenericEvent&lt;span style="color:#f92672">&amp;gt;&lt;/span> eventType &lt;span style="color:#f92672">=&lt;/span> (Class&lt;span style="color:#f92672">&amp;lt;?&lt;/span> &lt;span style="color:#66d9ef">extends&lt;/span> GenericEvent&lt;span style="color:#f92672">&amp;gt;&lt;/span>) (presenterMethod.&lt;span style="color:#a6e22e">getParameterTypes&lt;/span>())&lt;span style="color:#960050;background-color:#1e0010">\&lt;/span>&lt;span style="color:#f92672">[&lt;/span>0&lt;span style="color:#960050;background-color:#1e0010">\&lt;/span>&lt;span style="color:#f92672">]&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> registrations.&lt;span style="color:#a6e22e">add&lt;/span>(eventBus.&lt;span style="color:#a6e22e">addHandler&lt;/span>(GenericEventType.&lt;span style="color:#a6e22e">getTypeOf&lt;/span>(eventType), &lt;span style="color:#66d9ef">new&lt;/span> GenericEventHandler() {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">@Override&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">void&lt;/span> &lt;span style="color:#a6e22e">handleEvent&lt;/span>(GenericEvent event) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">try&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> presenterMethod.&lt;span style="color:#a6e22e">setAccessible&lt;/span>(&lt;span style="color:#66d9ef">true&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> presenterMethod.&lt;span style="color:#a6e22e">invoke&lt;/span>(args&lt;span style="color:#960050;background-color:#1e0010">\&lt;/span>&lt;span style="color:#f92672">[&lt;/span>0&lt;span style="color:#960050;background-color:#1e0010">\&lt;/span>&lt;span style="color:#f92672">]&lt;/span>, event);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> } &lt;span style="color:#66d9ef">catch&lt;/span> (IllegalAccessException &lt;span style="color:#f92672">|&lt;/span> IllegalArgumentException &lt;span style="color:#f92672">|&lt;/span> InvocationTargetException e) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">throw&lt;/span> &lt;span style="color:#66d9ef">new&lt;/span> RuntimeException(e);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }));
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#66d9ef">new&lt;/span> HandlerRegistration() {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">@Override&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">void&lt;/span> &lt;span style="color:#a6e22e">removeHandler&lt;/span>() {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">for&lt;/span> (HandlerRegistration registration : registrations) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> registration.&lt;span style="color:#a6e22e">removeHandler&lt;/span>();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> registrations.&lt;span style="color:#a6e22e">clear&lt;/span>();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> };
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> });
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">private&lt;/span> List&lt;span style="color:#f92672">&amp;lt;&lt;/span>Method&lt;span style="color:#f92672">&amp;gt;&lt;/span> &lt;span style="color:#a6e22e">getAllMethods&lt;/span>(Class&lt;span style="color:#f92672">&amp;lt;?&amp;gt;&lt;/span> type) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> List&lt;span style="color:#f92672">&amp;lt;&lt;/span>Method&lt;span style="color:#f92672">&amp;gt;&lt;/span> methods &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#66d9ef">new&lt;/span> LinkedList&lt;span style="color:#f92672">&amp;lt;&lt;/span>Method&lt;span style="color:#f92672">&amp;gt;&lt;/span>();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> methods.&lt;span style="color:#a6e22e">addAll&lt;/span>(Arrays.&lt;span style="color:#a6e22e">asList&lt;/span>(type.&lt;span style="color:#a6e22e">getDeclaredMethods&lt;/span>()));
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">if&lt;/span> (type.&lt;span style="color:#a6e22e">getSuperclass&lt;/span>() &lt;span style="color:#f92672">!=&lt;/span> &lt;span style="color:#66d9ef">null&lt;/span>) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> methods.&lt;span style="color:#a6e22e">addAll&lt;/span>(getAllMethods(type.&lt;span style="color:#a6e22e">getSuperclass&lt;/span>()));
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> methods;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>It’s not as bad as it seems. When you get rid of the Java Reflection cruft, it boils down to:&lt;/p>
&lt;ol>
&lt;li>Find all the methods on the presenter that are annotated with &lt;code>EventHandler&lt;/code>.&lt;/li>
&lt;li>Register a new handler that invokes the callback method for the event specified as it’s first argument.&lt;/li>
&lt;li>Return a &lt;code>HandlerRegistration&lt;/code> instance that on call to &lt;code>removeHandler&lt;/code> removes all the handlers added in the previous point (this behavior is copied from the actual implementation of gwteventbinder).&lt;/li>
&lt;/ol>
&lt;p>You might note that I don’t do any safe-checks… Well, assuming that you’ve run your code before, using (Super)DevMode, the EventBinder’s generator already checked that your code is sane and within the requirements of gwteventbinder.&lt;/p>
&lt;p>Now, all that’s left is to register this provider, for example in your &lt;code>@Before&lt;/code> method:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">@Before&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">void&lt;/span> &lt;span style="color:#a6e22e">setUpEventBindery&lt;/span>() {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> GwtMockito.&lt;span style="color:#a6e22e">useProviderForType&lt;/span>(EventBinder.&lt;span style="color:#a6e22e">class&lt;/span>, &lt;span style="color:#66d9ef">new&lt;/span> FakeEventBinderProvider());
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Like I’ve already mentioned, you only need to do this for the base interface, &lt;code>EventBinder&lt;/code>, since as the documentation for &lt;code>GwtMockito.useProviderForType&lt;/code> says:&lt;/p>
&lt;blockquote>
&lt;p>(..) the given provider should be used to GWT.create instances of the given type and &lt;strong>its subclasses&lt;/strong>.&lt;/p>
&lt;/blockquote>
&lt;p>Happy testing!&lt;/p></content></item><item><title>Avoiding Kernel Modules When External Firmware Is Needed</title><link>https://klimer.eu/2014/05/05/avoiding-kernel-modules-when-external-firmware-is-needed/</link><pubDate>Mon, 05 May 2014 21:41:00 +0000</pubDate><guid>https://klimer.eu/2014/05/05/avoiding-kernel-modules-when-external-firmware-is-needed/</guid><description>&lt;p>If you’re just interested in keeping your kernel module-free and be able to watch funny cat videos on youtube, skip to the &lt;a href="https://klimer.eu/2014/05/05/avoiding-kernel-modules-when-external-firmware-is-needed/#modules-solution">solution&lt;/a>.&lt;/p>
&lt;p>I’m an avid user of the &lt;a href="http:/www.gentoo.org/">Gentoo&lt;/a> flavour of Linux, specifically the &lt;a href="http://wiki.gentoo.org/wiki/Hardened_Gentoo">Hardened profile&lt;/a>. As you can imagine, I like to think of myself as a security-aware user. With that in mind, I prefer to keep my kernel module-free (by actually disabling the ability to load kernel modules), building in every driver that I need and keeping all the rest out. The reason for this, from a security point of view, is that loading a malicious kernel module is very often [citation needed] the second step after a successful privilege escalation. I don’t need module loading – I know my hardware, it doesn’t change that often.&lt;/p></description><content>&lt;p>If you’re just interested in keeping your kernel module-free and be able to watch funny cat videos on youtube, skip to the &lt;a href="https://klimer.eu/2014/05/05/avoiding-kernel-modules-when-external-firmware-is-needed/#modules-solution">solution&lt;/a>.&lt;/p>
&lt;p>I’m an avid user of the &lt;a href="http:/www.gentoo.org/">Gentoo&lt;/a> flavour of Linux, specifically the &lt;a href="http://wiki.gentoo.org/wiki/Hardened_Gentoo">Hardened profile&lt;/a>. As you can imagine, I like to think of myself as a security-aware user. With that in mind, I prefer to keep my kernel module-free (by actually disabling the ability to load kernel modules), building in every driver that I need and keeping all the rest out. The reason for this, from a security point of view, is that loading a malicious kernel module is very often [citation needed] the second step after a successful privilege escalation. I don’t need module loading – I know my hardware, it doesn’t change that often.&lt;/p>
&lt;p>So imagine my disdain, when I was setting up my laptop, a (t)rusty Lenovo ThinkPad X220, and it turned out that the WIFI card (an Intel Centrino something, supported by the iwlwifi driver) needed to load external firmware (residing in /lib/firmware) upon load. Unfortunately, this did not work when the driver was built in into the kernel – I presume that /lib/firmware is simply not available when the driver loads. A possible solution would be to create an initrd image and put the firmware there… but that seemed too much hassle. So I built the driver as module and wept in the corner that night…&lt;/p>
&lt;p>Fast forward to today, when I was setting up another ThinkPad (E540, for my parents) and I’ve stumbled upon the same situation – an Intel WIFI card (Intel Wireless-N 7260) that needed external firmware. But this time I’ve decided to be a man-, nay – a professional!, and tackle this problem. I mean, this the Linux Kernel, we don’t need to take this shit!&lt;/p>
&lt;p>The solution was far easier than I thought, requiring no hacks or custom scripts. Didn’t need to Google even, just looked at the available options. Here are the steps:&lt;/p>
&lt;ul>
&lt;li>Let’s assume you have a working WIFI card, the firmware is in &lt;code>/lib/firmware&lt;/code> and is named &lt;code>iwlwifi-7260-8.ucode&lt;/code>. If not, install the appropriate package from your distro’s package manager or download the firmware directly (for example, for Intel cards, from &lt;a href="http://wireless.kernel.org/en/users/Drivers/iwlwifi">http://wireless.kernel.org/en/users/Drivers/iwlwifi&lt;/a>).&lt;/li>
&lt;li>Head on to your kernel’s sources (you do build your own kernel, right?), usually &lt;code>/usr/src/linux&lt;/code>.&lt;/li>
&lt;li>&lt;code>make menuconfig&lt;/code>&lt;/li>
&lt;li>Let’s start off with building in the driver we’ll be including the firmware for. For me, it was &lt;strong>Intel Wireless WiFi Next Gen AGN - Wireless-N/Advanced-N/Ultimate-N (iwlwifi)&lt;/strong> (&lt;code>CONFIG_IWLWIFI&lt;/code>).&lt;/li>
&lt;li>Now, the options we are interested in reside in &lt;strong>Device Drivers -&amp;gt; Generic Driver Options&lt;/strong>.&lt;/li>
&lt;li>You probably have &lt;strong>Userspace firmware loading support&lt;/strong> (&lt;code>CONFIG_FW_LOADER&lt;/code>) enabled already (your WIFI driver should autoselect it), if not – enable it.&lt;/li>
&lt;li>Under it, select the &lt;strong>External firmware blobs to build into the kernel binary&lt;/strong> (&lt;code>CONFIG_EXTRA_FIRMWARE&lt;/code>) option. As the help says: This option allows firmware to be built into the kernel for the case where the user either cannot or doesn’t want to provide it from userspace at runtime. (…) This option is a string and takes the (space-separated) names of the firmware files.&lt;/li>
&lt;li>So, let’s do as the f…reaking manual tells us to do, set the value to your firmware’s filename (separating the files with spaces, if more than one). For our example, I’ve set it to &lt;code>iwlwifi-7260-8.ucode&lt;/code>.&lt;/li>
&lt;li>Setting this value enabled another option beneath it: &lt;strong>Firmware blobs root directory&lt;/strong> (&lt;code>CONFIG_EXTRA_FIRMWARE_DIR&lt;/code>). This is the dir that will be searched for the firmware files we’ve specified above. It defaults to the firmware directory in the kernel’s source tree. The easiest way is to point it to &lt;code>/lib/firmware&lt;/code> (as I’ve done), just remember that a future kernel upgrade might mean that you’ll need to update the firmware files as well. Keeping the firmware files in the kernel’s source tree is safer, but requires you to remember (OH NOES!) to copy over (or download updated versions) every time you compile a new version of the kernel.&lt;/li>
&lt;li>Save configuration, execute &lt;code>make -j4&lt;/code> (where 4 is the number of CPU cores you have, to speed things up a bit), etc.&lt;/li>
&lt;li>Reboot and check in dmesg that the firmware has indeed been successfully loaded.&lt;/li>
&lt;li>Bonus points: disable the module loading altogether in &lt;strong>Enable loadable module support&lt;/strong> (&lt;code>CONFIG_MODULES&lt;/code>).&lt;/li>
&lt;/ul>
&lt;p>Hope this helped someone and happy hacking!&lt;/p></content></item></channel></rss>