<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>{ blog.sunix.org }</title>
    <description>Sunix&apos;s personal blog site about Java, Cloud, and Open Source Software Development.</description>
    <link>https://sunix.github.io/</link>
    <atom:link href="https://sunix.github.io/zfeed.xml" rel="self" type="application/rss+xml"/>
    <pubDate>Sat, 14 Feb 2026 11:49:24 +0000</pubDate>
    <lastBuildDate>Sat, 14 Feb 2026 11:49:24 +0000</lastBuildDate>
    <generator>Jekyll v3.10.0</generator>
    
      <item>
        <title>Feeling Powerful with Just a Browser: Working Around a Broken Tennis Booking System</title>
        <description>&lt;p&gt;I don’t get many chances to play tennis.&lt;/p&gt;

&lt;p&gt;Between work, everyday constraints, and lately some pretty uncooperative weather, court time is rare and valuable. So when I finally found a slot that worked — and the booking system refused to give it back — frustration set in fast.&lt;/p&gt;

&lt;!-- more --&gt;

&lt;h2 id=&quot;a-slot-that-existed-but-didnt&quot;&gt;A Slot That Existed… but Didn’t&lt;/h2&gt;

&lt;p&gt;After canceling a reservation by mistake, I tried to book the same court again.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;global search page&lt;/strong&gt; clearly showed &lt;strong&gt;one available slot&lt;/strong&gt; for that day.&lt;/p&gt;

&lt;p&gt;But when I clicked through to the &lt;strong&gt;court page&lt;/strong&gt;, instead of seeing the list of available time slots and a “Reserve” button, I got this message:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;em&gt;Sorry, there is no court available for the selected date and criteria.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So the platform was telling me two contradictory things:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Search results said the slot existed&lt;/li&gt;
  &lt;li&gt;The court page claimed there were no slots at all for that day&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When you already don’t have much time to play, that kind of bug is incredibly frustrating.&lt;/p&gt;

&lt;h2 id=&quot;when-you-stop-trusting-the-ui&quot;&gt;When You Stop Trusting the UI&lt;/h2&gt;

&lt;p&gt;Refreshing didn’t help.
Navigating back and forth didn’t help.
The slot stayed visible in search, but the court page refused to display it.&lt;/p&gt;

&lt;p&gt;At that point, I stopped trusting the interface.&lt;/p&gt;

&lt;p&gt;If the system was able to &lt;strong&gt;count&lt;/strong&gt; the availability, then the data had to exist somewhere — even if the UI failed to render it.&lt;/p&gt;

&lt;h2 id=&quot;watching-the-site-talk-to-itself&quot;&gt;Watching the Site Talk to Itself&lt;/h2&gt;

&lt;p&gt;I opened &lt;strong&gt;Chrome DevTools&lt;/strong&gt; and switched to the &lt;strong&gt;Network&lt;/strong&gt; tab.&lt;/p&gt;

&lt;p&gt;I replayed the booking flow and watched the HTTP requests being made.&lt;/p&gt;

&lt;p&gt;One thing stood out:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The &lt;strong&gt;same court&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;At the &lt;strong&gt;same time&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;Worked perfectly on the &lt;strong&gt;previous day&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Clicking “Reserve” for that earlier date led straight to the reservation confirmation page.&lt;/p&gt;

&lt;p&gt;So I captured that request.&lt;/p&gt;

&lt;p&gt;Right-click → &lt;strong&gt;Copy as fetch&lt;/strong&gt; → paste into the console.&lt;/p&gt;

&lt;h2 id=&quot;the-request-sanitized-but-structurally-identical&quot;&gt;The Request (Sanitized but Structurally Identical)&lt;/h2&gt;

&lt;p&gt;Below is the request &lt;strong&gt;as captured&lt;/strong&gt;, with:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;A fake domain&lt;/li&gt;
  &lt;li&gt;A &lt;strong&gt;clearly fake anti-bot token&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;Everything else left untouched to preserve realism&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;https://tennisresa.fake/tennis/Portal.jsp?page=reservation&amp;amp;view=reservation_captcha&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;accept&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;accept-language&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;fr-FR,fr;q=0.9,en-US;q=0.8,en;q=0.7&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;cache-control&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;max-age=0&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;content-type&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;application/x-www-form-urlencoded&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;priority&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;u=0, i&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;sec-ch-ua&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Chromium&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;;v=&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;134&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Not:A-Brand&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;;v=&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;24&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Google Chrome&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;;v=&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;134&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;sec-ch-ua-mobile&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;?0&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;sec-ch-ua-platform&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Windows&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;sec-fetch-dest&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;sec-fetch-mode&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;navigate&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;sec-fetch-site&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;same-origin&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;sec-fetch-user&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;?1&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;upgrade-insecure-requests&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;referrer&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;https://tennisresa.fake/tennis/Portal.jsp?page=recherche&amp;amp;view=rechercher_creneau&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;referrerPolicy&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;strict-origin-when-cross-origin&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;equipmentId=320&amp;amp;courtId=3012&amp;amp;startDate=2026%2F01%2F14+12%3A00%3A00&amp;amp;endDate=2026%2F01%2F14+13%3A00%3A00&amp;amp;cancelling=false&amp;amp;li-antibot-token=FAKE.JWT.TOKEN_FOR_BLOG_POST_ONLY&amp;amp;li-antibot-token-code=100&amp;amp;captchaRequestId=FAKE-CAPTCHA-ID-123456&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;POST&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;cors&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;credentials&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;what-i-changed-almost-nothing&quot;&gt;What I Changed (Almost Nothing)&lt;/h2&gt;

&lt;p&gt;This is the key point.&lt;/p&gt;

&lt;p&gt;I &lt;strong&gt;did not&lt;/strong&gt; attempt to:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Forge a new request&lt;/li&gt;
  &lt;li&gt;Bypass authentication&lt;/li&gt;
  &lt;li&gt;Remove the anti-bot mechanism&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I deliberately &lt;strong&gt;kept the request exactly as generated by the site&lt;/strong&gt;, because it already contained important context:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Session cookies&lt;/li&gt;
  &lt;li&gt;Headers&lt;/li&gt;
  &lt;li&gt;Anti-bot token&lt;/li&gt;
  &lt;li&gt;Navigation intent&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I changed &lt;strong&gt;only two parameters&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;startDate&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;endDate&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s it.&lt;/p&gt;

&lt;p&gt;It’s essentially the same as &lt;strong&gt;refreshing a POST-based page&lt;/strong&gt;, but with slightly modified input — like correcting a date in a form the UI refused to let me submit.&lt;/p&gt;

&lt;h2 id=&quot;the-result&quot;&gt;The Result&lt;/h2&gt;

&lt;p&gt;After canceling any pending attempt, I executed the modified request in the console.&lt;/p&gt;

&lt;p&gt;I refreshed the page.&lt;/p&gt;

&lt;p&gt;And suddenly, I was on the &lt;strong&gt;reservation confirmation page&lt;/strong&gt; — for the exact slot that the UI had claimed didn’t exist.&lt;/p&gt;

&lt;p&gt;The backend accepted it.&lt;/p&gt;

&lt;p&gt;The booking went through.&lt;/p&gt;

&lt;h2 id=&quot;that-feeling-of-power&quot;&gt;That Feeling of Power&lt;/h2&gt;

&lt;p&gt;I didn’t exploit a vulnerability.
I didn’t defeat the anti-bot system.
I didn’t “hack” anything in the dramatic sense.&lt;/p&gt;

&lt;p&gt;But in that moment, I felt powerful.&lt;/p&gt;

&lt;p&gt;With:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;A browser&lt;/li&gt;
  &lt;li&gt;Chrome DevTools&lt;/li&gt;
  &lt;li&gt;And minimal technical knowledge&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;…I worked around a system bug that blocked a rare, real-life moment.&lt;/p&gt;

&lt;h2 id=&quot;what-this-really-shows&quot;&gt;What This Really Shows&lt;/h2&gt;

&lt;p&gt;This wasn’t about hacking.&lt;/p&gt;

&lt;p&gt;It was about:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;UI and backend desynchronization&lt;/li&gt;
  &lt;li&gt;Cached or inconsistent availability state&lt;/li&gt;
  &lt;li&gt;A backend that trusted valid requests more than its own interface&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The UI said “no”.
The backend said “yes”.&lt;/p&gt;

&lt;p&gt;I simply spoke the backend’s language.&lt;/p&gt;

&lt;h2 id=&quot;final-thoughts&quot;&gt;Final Thoughts&lt;/h2&gt;

&lt;p&gt;Websites are just software.
Software has bugs.
And sometimes, those bugs stand between us and the things we enjoy.&lt;/p&gt;

&lt;p&gt;Knowing how to open DevTools doesn’t make you dangerous —
it makes you &lt;strong&gt;less powerless&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That day, I didn’t just book a tennis court.&lt;/p&gt;

&lt;p&gt;I took back control. 🎾&lt;/p&gt;
</description>
        <pubDate>Sun, 11 Jan 2026 00:00:00 +0000</pubDate>
        <link>https://sunix.github.io/articles/howto/2026/01/11/feeling-powerful-with-just-a-browser.html</link>
        <guid isPermaLink="true">https://sunix.github.io/articles/howto/2026/01/11/feeling-powerful-with-just-a-browser.html</guid>
        
        <category>DevTools</category>
        
        <category>Browser</category>
        
        <category>Web Development</category>
        
        <category>Problem Solving</category>
        
        <category>Tennis</category>
        
        
        <category>articles</category>
        
        <category>Howto</category>
        
      </item>
    
      <item>
        <title>Building a Gift Card Management App with GitHub Copilot: My First Completed Side Project</title>
        <description>&lt;p&gt;Like many developers, my life is littered with unfinished side projects. But this time was different. This time, I had GitHub Copilot as my coding companion, and I actually finished. Let me tell you how AI-assisted development helped me build a &lt;a href=&quot;https://sunix.github.io/gift-card/&quot;&gt;gift card management application&lt;/a&gt; that I actually use every day — and I did it almost entirely without opening an IDE.&lt;/p&gt;

&lt;!-- more --&gt;

&lt;h2 id=&quot;the-problem-managing-gift-cards-in-the-real-world&quot;&gt;The Problem: Managing Gift Cards in the Real World&lt;/h2&gt;

&lt;p&gt;My wife works at Red Hat, and like many companies, they offer a CSE (Comité Social et Économique) benefit program. One of the perks is getting gift cards with discounts — including a nice 5% discount at a major supermarket chain. Sounds great, right?&lt;/p&gt;

&lt;p&gt;Here’s the catch: I was using Google Wallet on my mobile to track these cards, but I could never keep the balance updated. After each shopping trip, I’d forget to update it. Then I’d be at the checkout, unsure if I had enough on the card or not. It was frustrating enough that I decided to build something better — a simple app where I could display the barcode to be scanned at the store and manually update the balance right there.&lt;/p&gt;

&lt;h2 id=&quot;another-side-project-or-is-it&quot;&gt;Another Side Project… Or Is It?&lt;/h2&gt;

&lt;p&gt;“Alright, here we go again,” I thought. Another side project that I’d start enthusiastically and abandon halfway through. My digital graveyard of unfinished projects was already pretty crowded.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/side-project-comic.png&quot; alt=&quot;Side projects comic strip&quot; /&gt;
&lt;em&gt;&lt;a href=&quot;https://www.commitstrip.com/en/2014/11/25/west-side-project-story/?setLocale=1&quot;&gt;Source: CommitStrip.com&lt;/a&gt; - A story we all know too well.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;But this time felt different. I had been experimenting with AI tools. I had recently used ChatGPT to build a sample website for a tennis club in just a few days. The speed was incredible. Before starting this gift card app, I even consulted ChatGPT about the technology stack — should I build a PWA (Progressive Web App) or go native with Kotlin? Based on the advice, I decided on a PWA for its cross-platform benefits and easier maintenance.&lt;/p&gt;

&lt;p&gt;Still, I was skeptical. Would I actually finish this one?&lt;/p&gt;

&lt;h2 id=&quot;the-game-changer-discovering-github-copilot-workspace&quot;&gt;The Game Changer: Discovering GitHub Copilot Workspace&lt;/h2&gt;

&lt;p&gt;Then I stumbled upon something that changed everything: the ability to assign entire projects to GitHub Copilot directly in GitHub. Not just code completion or suggestions, but actual project creation and feature development.&lt;/p&gt;

&lt;p&gt;I decided to give it a shot. I created an issue with my requirements and assigned it to Copilot. My first prompt was straightforward:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;“Create a Progressive Web App for managing gift cards. The app should allow users to:&lt;/p&gt;
  &lt;ul&gt;
    &lt;li&gt;Store gift card information (name, barcode number)&lt;/li&gt;
    &lt;li&gt;Generate and display barcodes to be scanned at stores&lt;/li&gt;
    &lt;li&gt;Track and update card balances&lt;/li&gt;
    &lt;li&gt;Work offline&lt;/li&gt;
    &lt;li&gt;Install as a mobile app”&lt;/li&gt;
  &lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;img src=&quot;/images/copilot-issue-assignment.png&quot; alt=&quot;Assigning an issue to Copilot&quot; /&gt;
&lt;em&gt;When you assign an issue to Copilot, it immediately creates a “[WIP]” Pull Request and starts working.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;And then… I waited. Copilot started working. It created a project structure, set up the PWA infrastructure, implemented the basic features, and even opened a Pull Request. It was like having a junior developer who worked incredibly fast but needed guidance.&lt;/p&gt;

&lt;h2 id=&quot;the-reality-check-when-ai-needs-direction&quot;&gt;The Reality Check: When AI Needs Direction&lt;/h2&gt;

&lt;p&gt;Of course, it wasn’t perfect. The barcode generation system Copilot created was problematic. Instead of using an existing library, Copilot tried to reimplement Code128 barcode generation from scratch. While the generated barcodes looked right visually, they weren’t compatible with the actual barcode readers at stores. There are nuances to barcode standards — Code128, Code39, EAN-13, and others — each with specific encoding rules that need to be precise down to the pixel.&lt;/p&gt;

&lt;p&gt;I created an issue to fix it, but the improvements weren’t quite right either. I got frustrated and did what any developer would do: I asked ChatGPT for help separately, opened up my IDE, started debugging manually. Eventually, I discovered &lt;a href=&quot;https://github.com/metafloor/bwip-js&quot;&gt;bwip-js&lt;/a&gt;, a reliable barcode generation library that handles all the complexity correctly. I manually amended &lt;a href=&quot;https://github.com/sunix/gift-card/pull/3&quot;&gt;Copilot’s PR&lt;/a&gt; to integrate bwip-js, and finally, the barcodes worked perfectly at the store.&lt;/p&gt;

&lt;p&gt;Only later did I discover what I should have done from the start: just mention &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@copilot&lt;/code&gt; in the issue comments! When you need Copilot to adjust something, iterate on a feature, or fix a problem, you don’t need to spin up a whole new workflow. Just comment on the issue or PR, mention @copilot, and it will respond and make the necessary changes. This was a game-changer for me.&lt;/p&gt;

&lt;h2 id=&quot;finding-my-rhythm-the-perfect-workflow&quot;&gt;Finding My Rhythm: The Perfect Workflow&lt;/h2&gt;

&lt;p&gt;Once I understood how to work with Copilot effectively, I developed a rhythm that actually worked:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Create an issue&lt;/strong&gt; - Write down what I want in clear, specific terms&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Assign it to @copilot&lt;/strong&gt; - Let it do the heavy lifting&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Review the PR&lt;/strong&gt; - Look at what Copilot created&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Provide feedback&lt;/strong&gt; - Use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@copilot&lt;/code&gt; mentions in comments for adjustments&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Iterate&lt;/strong&gt; - Repeat steps 3-4 until satisfied&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Merge and move on&lt;/strong&gt; - Deploy and create the next issue&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;What I loved most was the visibility into Copilot’s “thinking” process. I could see the session logs, watch it reason through problems, and even see screenshots it took when testing with Playwright. It was like pair programming with someone who documents everything they do.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/copilot-checklist.png&quot; alt=&quot;Copilot&apos;s checklist of steps&quot; /&gt;
&lt;em&gt;Copilot shows you exactly what steps it’s taking, with checkboxes showing progress. You can see the original prompt and watch it work through each task.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/copilot-pr-diff.png&quot; alt=&quot;Code changes by Copilot&quot; /&gt;
&lt;em&gt;The Pull Request shows all the changes Copilot made, just like any other PR. You can review the diff and request changes.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The workflow became almost meditative. I’d create issues during my coffee break, assign them to Copilot, and come back later to review and comment. No pressure to sit down for a long coding session. No context-switching overhead. Just incremental progress, issue by issue.&lt;/p&gt;

&lt;h2 id=&quot;the-result-a-finished-project&quot;&gt;The Result: A Finished Project&lt;/h2&gt;

&lt;p&gt;After several iterations over a few weeks, I had a working app. Not just a proof of concept, but something I actually deployed and use regularly:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;📱 &lt;strong&gt;Progressive Web App&lt;/strong&gt; that installs on my phone&lt;/li&gt;
  &lt;li&gt;📊 &lt;strong&gt;Barcode generation&lt;/strong&gt; using bwip-js that works reliably with store scanners&lt;/li&gt;
  &lt;li&gt;💰 &lt;strong&gt;Balance tracking&lt;/strong&gt; that I can update on the go&lt;/li&gt;
  &lt;li&gt;🔒 &lt;strong&gt;Offline support&lt;/strong&gt; so it works everywhere&lt;/li&gt;
  &lt;li&gt;🎨 &lt;strong&gt;Clean UI&lt;/strong&gt; that’s simple and functional&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can check out the code on &lt;a href=&quot;https://github.com/sunix/gift-card&quot;&gt;GitHub&lt;/a&gt; and try the &lt;a href=&quot;https://sunix.github.io/gift-card/&quot;&gt;live application&lt;/a&gt; yourself.&lt;/p&gt;

&lt;p&gt;But here’s what really matters: &lt;strong&gt;I finished it&lt;/strong&gt;. For the first time in years, I completed a side project from start to finish. It’s deployed. It’s in use. It solves my actual problem.&lt;/p&gt;

&lt;h2 id=&quot;lessons-learned&quot;&gt;Lessons Learned&lt;/h2&gt;

&lt;p&gt;Working with GitHub Copilot taught me several things:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;AI is a collaborator, not a replacement&lt;/strong&gt; - You still need to guide, review, and make decisions&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Clear communication matters&lt;/strong&gt; - The better your issue descriptions, the better the results&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Iteration is key&lt;/strong&gt; - Don’t expect perfection on the first try; embrace the feedback loop&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Learn the tools&lt;/strong&gt; - Understanding features like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@copilot&lt;/code&gt; mentions saves tons of time&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Small steps win&lt;/strong&gt; - Breaking work into issues and letting AI handle them one by one actually works&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;the-cherry-on-top&quot;&gt;The Cherry on Top&lt;/h2&gt;

&lt;p&gt;Want to know something funny? This blog post itself was generated with the help of Copilot. I created an issue asking for a blog post about the experience, provided the structure I wanted (following classical rhetoric: exordium, narration, argumentation, refutation, and peroration), and iterated on the draft with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@copilot&lt;/code&gt; mentions until it captured my voice and experience.&lt;/p&gt;

&lt;p&gt;It’s turtles all the way down.&lt;/p&gt;

&lt;h2 id=&quot;final-thoughts&quot;&gt;Final Thoughts&lt;/h2&gt;

&lt;p&gt;I’m genuinely excited about this new way of building things. GitHub Copilot didn’t just help me finish a project — it changed how I approach side projects entirely. Instead of thinking “I need to set aside a weekend to code this,” I think “I can break this into issues and make progress during coffee breaks.”&lt;/p&gt;

&lt;p&gt;The barrier to finishing projects isn’t just time or skill anymore. It’s about having the right collaboration model. For me, that model is now: me plus AI, working asynchronously, iterating on issues, and actually shipping.&lt;/p&gt;

&lt;p&gt;If you’ve been putting off that side project, maybe give GitHub Copilot a try. Create an issue. Assign it to @copilot. See what happens. You might just finish something for once.&lt;/p&gt;

&lt;p&gt;And when you do, it feels pretty great.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;em&gt;Have you used GitHub Copilot or other AI coding assistants for your projects? What’s your experience been? I’d love to hear about it in the comments below.&lt;/em&gt;&lt;/p&gt;
</description>
        <pubDate>Fri, 14 Nov 2025 00:00:00 +0000</pubDate>
        <link>https://sunix.github.io/articles/howto/2025/11/14/building-gift-card-app-with-github-copilot.html</link>
        <guid isPermaLink="true">https://sunix.github.io/articles/howto/2025/11/14/building-gift-card-app-with-github-copilot.html</guid>
        
        <category>GitHub Copilot</category>
        
        <category>AI-Assisted Development</category>
        
        <category>PWA</category>
        
        <category>Side Projects</category>
        
        <category>Developer Productivity</category>
        
        
        <category>articles</category>
        
        <category>Howto</category>
        
      </item>
    
      <item>
        <title>Why I Think Git Flow Doesn&apos;t Fit Most Projects Anymore</title>
        <description>&lt;p&gt;I’ve used &lt;strong&gt;Git Flow&lt;/strong&gt; on quite a few projects over the years — and honestly, I’ve reached a point where I don’t think it’s the right choice for most modern teams anymore.&lt;/p&gt;

&lt;p&gt;It’s not that Git Flow was bad. In fact, when Vincent Driessen came up with it back in 2010, it made a lot of sense. We didn’t have solid CI/CD pipelines yet. Releases were manual. Teams were smaller and slower. Having a clean branching model for “features,” “releases,” and “hotfixes” was a huge step forward at the time.&lt;/p&gt;

&lt;p&gt;But now? It just feels outdated.&lt;/p&gt;

&lt;!-- more --&gt;

&lt;h2 id=&quot;the-problems-i-keep-running-into&quot;&gt;The Problems I Keep Running Into&lt;/h2&gt;

&lt;p&gt;Every time I see Git Flow used in a modern setup — with automated testing, continuous integration, and frequent releases — it causes more friction than it solves.&lt;/p&gt;

&lt;p&gt;Here’s why:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Too much complexity.&lt;/strong&gt; The number of branches you have to maintain (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;develop&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;release&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hotfix&lt;/code&gt;, etc.) adds unnecessary overhead. Everyone ends up spending time managing branches instead of shipping code.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Messy history.&lt;/strong&gt; With all the merges going back and forth, the Git history becomes unreadable. You lose the nice, linear flow that helps understand what actually happened.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Outdated assumptions.&lt;/strong&gt; Git Flow was built for a world of scheduled releases. But with CI/CD, we can deploy anytime — sometimes multiple times a day. The model doesn’t fit that reality.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Long-lived branches and circular merges.&lt;/strong&gt; These “living” branches constantly merging into each other create confusion and technical debt. It’s too easy to break things accidentally.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Rigid structure.&lt;/strong&gt; Modern development needs flexibility. You want to be able to test, experiment, and integrate quickly. Git Flow gets in the way of that.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;what-works-better-for-me&quot;&gt;What Works Better for Me&lt;/h2&gt;

&lt;p&gt;I’ve had much better results using &lt;strong&gt;Trunk-Based Development&lt;/strong&gt;.
Everyone works off &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;main&lt;/code&gt; (or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;master&lt;/code&gt;), creates short-lived branches, and merges back quickly — ideally after just a day or two. It keeps things simple and stable.&lt;/p&gt;

&lt;p&gt;A few key practices that help:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Use &lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git rebase&lt;/code&gt;&lt;/strong&gt; instead of merging in your Pull Requests. It keeps the history linear and easy to read.&lt;/li&gt;
  &lt;li&gt;Create &lt;strong&gt;maintenance branches&lt;/strong&gt; only when you really need them — for example, to patch already released versions. When that happens, just use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git cherry-pick&lt;/code&gt; to backport fixes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This setup keeps your main branch always production-ready, while still letting you move fast.&lt;/p&gt;

&lt;h2 id=&quot;the-shift-left-connection&quot;&gt;The “Shift Left” Connection&lt;/h2&gt;

&lt;p&gt;If your team has already shifted left — meaning you test, review, and automate early in the process — you don’t need extra “safety” branches like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;develop&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;release&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;CI runs your tests before merging. You can spin up preview environments for every Pull Request. Your main branch stays stable by design.&lt;/p&gt;

&lt;p&gt;That’s the world we live in now, and it makes Git Flow’s complexity unnecessary.&lt;/p&gt;

&lt;h2 id=&quot;so-what-do-you-think&quot;&gt;So… What Do You Think?&lt;/h2&gt;

&lt;p&gt;I know this might sound opinionated, and I’m not saying Git Flow should &lt;em&gt;never&lt;/em&gt; be used. There are still cases — maybe in projects with slow release cycles or strict approval gates — where it can make sense.&lt;/p&gt;

&lt;p&gt;But for most modern teams? I think it’s time to move on.&lt;/p&gt;

&lt;p&gt;I’d really like to hear from others:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Are you still using Git Flow?&lt;/li&gt;
  &lt;li&gt;Have you switched to something simpler like Trunk-Based Development or GitHub Flow?&lt;/li&gt;
  &lt;li&gt;What’s worked (or failed) for your team?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s talk about it — I’m genuinely curious how others see this shift.&lt;/p&gt;
</description>
        <pubDate>Fri, 07 Nov 2025 00:00:00 +0000</pubDate>
        <link>https://sunix.github.io/articles/howto/2025/11/07/git-flow-doesnt-fit-anymore.html</link>
        <guid isPermaLink="true">https://sunix.github.io/articles/howto/2025/11/07/git-flow-doesnt-fit-anymore.html</guid>
        
        <category>Git</category>
        
        <category>Git Flow</category>
        
        <category>Trunk-Based Development</category>
        
        <category>CI/CD</category>
        
        <category>Software Development</category>
        
        <category>DevOps</category>
        
        
        <category>articles</category>
        
        <category>Howto</category>
        
      </item>
    
      <item>
        <title>Recovering My Frozen Fedora Laptop</title>
        <description>&lt;p&gt;I left Red Hat a few months ago and joined Sciam, but I had to return my corporate laptop. To maintain my workstation setup, I decided to reuse my old Dell XPS and migrate my data from one laptop to another. After installing a fresh Fedora system on the XPS, everything seemed fine initially, but some unexpected issues arose afterward.&lt;/p&gt;

&lt;!-- more --&gt;

&lt;h3 id=&quot;the-initial-problem-intermittent-freezing&quot;&gt;The Initial Problem: Intermittent Freezing&lt;/h3&gt;

&lt;p&gt;After transferring my corporate laptop data to the older machine, I restored my home directory using Deja-Dup. While the backup and restoration process worked smoothly, a significant issue arose: my Fedora system began freezing approximately every 10 seconds for 3 seconds at a time, rendering it almost unusable.&lt;/p&gt;

&lt;h4 id=&quot;diagnosing-the-issue&quot;&gt;Diagnosing the Issue&lt;/h4&gt;

&lt;p&gt;I started by isolating the problem to see if it was related to the system itself. Here’s what I did:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;✨ &lt;strong&gt;Created a New User:&lt;/strong&gt; I created a new user account on Fedora and tested the system. To my surprise, it worked flawlessly without any freezes.&lt;/li&gt;
  &lt;li&gt;🔍 &lt;strong&gt;Narrowing Down the Cause:&lt;/strong&gt; This indicated that the issue lay within my home directory. I began moving folders to a backup directory to pinpoint the culprit. When I moved the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.config&lt;/code&gt; directory and relogged, the freezing stopped. Narrowing it down further, I discovered that the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.config/dconf/user&lt;/code&gt; file was the source of the problem.&lt;/li&gt;
&lt;/ol&gt;

&lt;h4 id=&quot;the-solution&quot;&gt;The Solution&lt;/h4&gt;

&lt;p&gt;To resolve the issue, I moved the problematic &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dconf&lt;/code&gt; file to a backup directory:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;mv&lt;/span&gt; ~/.config/dconf/user ~/backup/dconf/user
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This completely resolved the freezing issue. It appeared that the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dconf&lt;/code&gt; database had become corrupted or contained conflicting settings. By removing it, the system regenerated a new, clean &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dconf&lt;/code&gt; database.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lesson Learned:&lt;/strong&gt; A corrupted &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dconf&lt;/code&gt; database can severely impact performance. Resetting it is an effective troubleshooting step.&lt;/p&gt;

&lt;hr /&gt;

&lt;h3 id=&quot;troubleshooting-dconf-readwrite-errors&quot;&gt;Troubleshooting dconf Read/Write Errors&lt;/h3&gt;

&lt;p&gt;Hoping to retain my configurations, I attempted to back up and restore the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dconf&lt;/code&gt; database:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;💾 &lt;strong&gt;Backup:&lt;/strong&gt;
    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;dconf dump / &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; dconf-backup.txt
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;🔄 &lt;strong&gt;Restore:&lt;/strong&gt;
    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;dconf load / &amp;lt; dconf-backup.txt
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;However, when I tried to restore the settings, I encountered the following error:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;The operation attempted to modify one or more non-writable keys
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To identify the problematic keys, I wrote a script to check the readability of each key in the backup file. Surprisingly, all keys were readable. Despite this, the restoration process failed. Ultimately, I chose to manually rebuild my configuration rather than continuing to debug the permissions issue.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lesson Learned:&lt;/strong&gt; When restoring dconf settings proves too difficult, rebuilding configurations manually can be faster and more reliable.&lt;/p&gt;

&lt;hr /&gt;

&lt;h3 id=&quot;resetting-deja-dup-configuration&quot;&gt;Resetting Deja-Dup Configuration&lt;/h3&gt;

&lt;p&gt;While investigating the issue, I noticed log entries related to Deja-Dup in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;journalctl&lt;/code&gt;. This raised the possibility that frequent backup operations were causing the freezes. To rule this out, I decided to reset the Deja-Dup configuration.&lt;/p&gt;

&lt;p&gt;Using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dconf-editor&lt;/code&gt; didn’t provide an obvious way to remove or reset Deja-Dup settings. Instead, I took a brute-force approach by deleting the configuration files and reconfiguring the backup settings manually. This resolved any potential conflicts quickly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lesson Learned:&lt;/strong&gt; Sometimes, deleting and starting fresh is the most efficient way to troubleshoot persistent issues.&lt;/p&gt;

&lt;hr /&gt;

&lt;h3 id=&quot;adjusting-trackpad-settings&quot;&gt;Adjusting Trackpad Settings&lt;/h3&gt;

&lt;p&gt;After resetting the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dconf&lt;/code&gt; database, I noticed changes in my trackpad’s behavior. I had to manually adjust its sensitivity and gestures to restore my preferred setup. While this was straightforward, it served as a reminder of how many small customizations accumulate over time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lesson Learned:&lt;/strong&gt; Keep a record of your preferred configurations to streamline recovery after resets or migrations.&lt;/p&gt;

&lt;hr /&gt;

&lt;h3 id=&quot;resolving-guake-shortcut-issues&quot;&gt;Resolving Guake Shortcut Issues&lt;/h3&gt;

&lt;p&gt;One of the lingering problems after resetting my settings was with Guake, my dropdown terminal. The shortcut I used to toggle Guake’s visibility (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Ctrl+Down&lt;/code&gt;) no longer worked. Attempting to rebind it in the Guake Preferences dialog resulted in the following error:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Guake Terminal: A problem happened when binding Control+Down key. Please use Guake Preferences dialog to choose another key.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Ironically, this error occurred while using the Preferences dialog itself! After some trial and error, I stumbled upon a workaround:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;💡 In a terminal, I typed &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;guake&lt;/code&gt; followed by the Tab key, which revealed a command called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;guake-toggle&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;⚙️ I went to GNOME Settings &amp;gt; Keyboard &amp;gt; Shortcuts and created a custom shortcut.&lt;/li&gt;
  &lt;li&gt;⌨️ I set the command to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;guake-toggle&lt;/code&gt; and bound it to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Ctrl+Down&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This approach worked perfectly, restoring the desired functionality.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lesson Learned:&lt;/strong&gt; When standard UI methods fail, alternative commands and workarounds can save the day.&lt;/p&gt;

&lt;hr /&gt;

&lt;h3 id=&quot;final-thoughts&quot;&gt;Final Thoughts&lt;/h3&gt;

&lt;p&gt;Despite the challenges, I am genuinely happy to return to Fedora Linux. Over the past few months, I had been using macOS and Windows, but it’s clear to me that I’m a Linux user at heart. Fedora feels like home—it’s where I’m most comfortable and productive.&lt;/p&gt;

&lt;p&gt;Although it wasn’t easy to troubleshoot and resolve these issues, I managed to overcome them and recover an almost perfect clone of my previous laptop settings. This experience reinforced my appreciation for Fedora’s flexibility and the vast potential it offers for customization and experimentation.&lt;/p&gt;

</description>
        <pubDate>Tue, 31 Dec 2024 00:00:00 +0000</pubDate>
        <link>https://sunix.github.io/articles/2024/12/31/recovering-frozen-fedora-laptop.html</link>
        <guid isPermaLink="true">https://sunix.github.io/articles/2024/12/31/recovering-frozen-fedora-laptop.html</guid>
        
        <category>fedora</category>
        
        <category>linux</category>
        
        
        <category>articles</category>
        
      </item>
    
      <item>
        <title>Why We Estimate: The True Value of Estimation in Agile Development</title>
        <description>&lt;p&gt;Reading the article &lt;a href=&quot;https://web.archive.org/web/20200419145539/https://tech.transferwise.com/4-fallacious-reasons-why-we-estimate/&quot;&gt;“4 Fallacious Reasons Why We Estimate”&lt;/a&gt;, I felt it missed the most important part of why we estimate. The article seemed to suggest that estimation is only fraught with drawbacks and is ultimately useless. However, from my experience working with various teams at Red Hat, I believe that estimation holds significant value, albeit for reasons that might not be immediately apparent. In this blog post, I will delve into why we estimate, addressing misconceptions and highlighting the true value of this practice.
&lt;!-- more --&gt;&lt;/p&gt;

&lt;h3 id=&quot;no-visible-progress-endless-issues-and-frustration&quot;&gt;No Visible Progress, Endless Issues, and Frustration&lt;/h3&gt;

&lt;p&gt;In one of our sprints, we assigned one task per developer. However, because no one finished their task, we moved all the ‘in progress’ issues to the next sprint. This lack of visible progress can be problematic and frustrating for everyone involved:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Project Manager (PM):&lt;/strong&gt; The PM is frustrated because they cannot see progress and have no idea if tasks will be delivered in the current sprint, the next one, or even three months down the line.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Team Members:&lt;/strong&gt; Other team members are frustrated because they want to understand where the team stands in terms of achieving common goals. As a team, everyone wants to reach their objectives together.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Individual Developers:&lt;/strong&gt; It is frustrating for developers not to be able to finish tasks despite making progress. Marking tasks as done provides a sense of accomplishment, which is crucial for maintaining motivation during the sprint.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;splitting-issues&quot;&gt;Splitting Issues&lt;/h3&gt;

&lt;p&gt;Let’s consider one of my assigned issues: “Make the factories work with Theia IDE.” One major component was implementing the import of projects defined in the factory definition. This issue could take one or two sprints to complete, but without clear estimation, it was challenging to gauge the time required accurately.&lt;/p&gt;

&lt;p&gt;Any task that takes more than a week can be frustrating for the reasons mentioned above. Therefore, my first step was to split the issue into smaller, more manageable tasks that could be “delivered.” Initially, I split the issue into two parts, but I remained open to further splitting if necessary. However, sometimes splitting issues isn’t enough to create clear and concise tasks that can be resolved quickly.&lt;/p&gt;

&lt;h3 id=&quot;ending-up-with-results&quot;&gt;Ending Up with Results&lt;/h3&gt;

&lt;p&gt;To ensure tasks can be solved within a short period, each task should have a clear definition of done, which could be delivering something, documentation, etc. Here are some examples:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Spike:&lt;/strong&gt; This could result in more issues or a Proof of Concept (PoC).&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Demo Scripts and Acceptance Criteria:&lt;/strong&gt; These should be defined before estimating issues. Acceptance criteria, following the Given-When-Then pattern, help validate the task’s completion.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For instance, the issue described in &lt;a href=&quot;https://github.com/eclipse-jkube/jkube/issues/2465&quot;&gt;GitHub issue #2465&lt;/a&gt; can be easily estimated because the steps to completion are well-defined.&lt;/p&gt;

&lt;h3 id=&quot;how-we-should-estimate&quot;&gt;How We Should Estimate&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Define the Goal and Clear Definition of Done:&lt;/strong&gt; Include a demo at the end and/or acceptance criteria.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Maximum 5 Days:&lt;/strong&gt; If a task is estimated to take longer, it should be split into smaller tasks.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Explain the Time Estimate:&lt;/strong&gt; Provide implementation details and reasoning.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Use Relative Sizing:&lt;/strong&gt; In previous teams, we estimated using trivial/small/medium/large to avoid discussing specific timeframes.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Collaborative Estimation:&lt;/strong&gt; Estimating with team members forces you to think through the implementation. Explaining your estimates can reveal hidden complexities.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;experiments-and-spikes&quot;&gt;Experiments and Spikes&lt;/h3&gt;

&lt;p&gt;Spike issues involve investigating a technology or figuring out an implementation approach. For example, I spent time figuring out how to implement the import functionality. A spike should result in a PoC or a clear understanding of the task. After a spike, you can create and estimate new tasks more accurately.&lt;/p&gt;

&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;While some may view estimation as an exercise in futility, my experience has shown that it provides essential visibility and structure to the development process. Estimations help manage expectations, break down complex tasks, and maintain team morale by showing incremental progress. By understanding and implementing effective estimation practices, we can harness their true value, making our development cycles more predictable and our goals more achievable.&lt;/p&gt;
</description>
        <pubDate>Tue, 23 Jul 2024 00:00:00 +0000</pubDate>
        <link>https://sunix.github.io/articles/howto/2024/07/23/why-we-estimate.html</link>
        <guid isPermaLink="true">https://sunix.github.io/articles/howto/2024/07/23/why-we-estimate.html</guid>
        
        <category>Agile Development</category>
        
        <category>Project Management</category>
        
        <category>Task Estimation</category>
        
        <category>Sprint Planning</category>
        
        
        <category>articles</category>
        
        <category>Howto</category>
        
      </item>
    
      <item>
        <title>Migrating Gmail from One Account to Another: A Comprehensive Guide</title>
        <description>&lt;p&gt;Migrating emails from one Gmail account to another can be a daunting task, especially when you need to ensure that no emails are lost, and all tags (labels) are accurately transferred. This guide will walk you through the process, highlighting the common challenges and the tools you can use to make the migration smoother.
&lt;!-- more --&gt;&lt;/p&gt;
&lt;h2 id=&quot;why-backup-your-gmail&quot;&gt;Why Backup Your Gmail?&lt;/h2&gt;

&lt;p&gt;Imagine you’re leaving your job, and a colleague needs an important email from a customer that you no longer have. Or perhaps you need to consolidate multiple email accounts for better management. Backing up and migrating your emails can prevent data loss and ensure continuity in communication.&lt;/p&gt;

&lt;h2 id=&quot;challenges-in-migrating-gmail-accounts&quot;&gt;Challenges in Migrating Gmail Accounts&lt;/h2&gt;

&lt;p&gt;When I first attempted to migrate my emails using IMAP with Thunderbird, I encountered several issues:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Inefficiency&lt;/strong&gt;: The process was slow and could not detect duplicate emails.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Crashes&lt;/strong&gt;: Thunderbird crashed frequently, and resuming the migration from the last point was not straightforward.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Label Issues&lt;/strong&gt;: Gmail labels are seen as folders in IMAP, but folders are not labels. If an email had multiple Gmail labels, it appeared as multiple emails in different folders in IMAP.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;the-solution-using-mnimapsync-by-marc-nuri&quot;&gt;The Solution: Using mnIMAPSync by Marc Nuri&lt;/h2&gt;

&lt;p&gt;After struggling with Thunderbird, I turned to a tool developed by my colleague, Marc Nuri: &lt;a href=&quot;https://github.com/manusa/mnIMAPSync&quot;&gt;mnIMAPSync&lt;/a&gt;. This Java-based IMAP Server syncing tool proved to be much more efficient for the task.&lt;/p&gt;

&lt;h3 id=&quot;steps-to-migrate-gmail-accounts-using-mnimapsync&quot;&gt;Steps to Migrate Gmail Accounts Using mnIMAPSync&lt;/h3&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Enable IMAP in Both Accounts&lt;/strong&gt;:
    &lt;ul&gt;
      &lt;li&gt;In both the source and destination Gmail accounts, go to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Settings&lt;/code&gt; &amp;gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;See all settings&lt;/code&gt; &amp;gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Forwarding and POP/IMAP&lt;/code&gt; and enable IMAP.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Show All Labels in IMAP&lt;/strong&gt;:
    &lt;ul&gt;
      &lt;li&gt;Ensure that all labels you want to sync are shown in IMAP. In &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Settings&lt;/code&gt;, navigate to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Labels&lt;/code&gt; tab and select “Show in IMAP” for each label, except for “All Mail”.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Enable Sign-In with App Passwords&lt;/strong&gt;:
    &lt;ul&gt;
      &lt;li&gt;Follow Google’s instructions to &lt;a href=&quot;https://support.google.com/accounts/answer/185833?hl=en&quot;&gt;enable sign-in with app passwords&lt;/a&gt;. This is crucial for the tool to authenticate with your Gmail accounts.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Using Docker for mnIMAPSync&lt;/strong&gt;:
    &lt;ul&gt;
      &lt;li&gt;If you don’t have the right version of Java to run the tool, use the provided Docker image. Ensure Docker is installed on your machine.&lt;/li&gt;
      &lt;li&gt;Run the following Docker command, replacing the placeholder values with your actual account details:
        &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;docker run marcnuri/mnimapsync &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--host1&lt;/span&gt; imap.gmail.com &lt;span class=&quot;nt&quot;&gt;--port1&lt;/span&gt; 993 &lt;span class=&quot;nt&quot;&gt;--user1&lt;/span&gt; source-email@gmail.com &lt;span class=&quot;nt&quot;&gt;--password1&lt;/span&gt; apppassword1 &lt;span class=&quot;nt&quot;&gt;--ssl1&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--host2&lt;/span&gt; imap.gmail.com &lt;span class=&quot;nt&quot;&gt;--port2&lt;/span&gt; 993 &lt;span class=&quot;nt&quot;&gt;--user2&lt;/span&gt; destination-email@gmail.com &lt;span class=&quot;nt&quot;&gt;--password2&lt;/span&gt; apppassword2 &lt;span class=&quot;nt&quot;&gt;--ssl2&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--threads&lt;/span&gt; 9 &lt;span class=&quot;nt&quot;&gt;--delete&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;        &lt;/div&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;troubleshooting-common-issues&quot;&gt;Troubleshooting Common Issues&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Labels with Special Characters&lt;/strong&gt;:
    &lt;ul&gt;
      &lt;li&gt;If labels contain special characters (e.g., &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/&lt;/code&gt;), the tool might crash. Rename these labels without special characters and rerun the sync.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Syncing Large Labels&lt;/strong&gt;:
    &lt;ul&gt;
      &lt;li&gt;Untick “Show in IMAP” for the “All Mail” label to speed up the process. Alternatively, be patient, as syncing large labels can take time.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Tool Crashes&lt;/strong&gt;:
    &lt;ul&gt;
      &lt;li&gt;If the tool crashes at any point, simply rerun it. The tool is designed to pick up where it left off.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Migrating emails between Gmail accounts can be a complex task, but using the right tools and following a structured approach can significantly simplify the process. mnIMAPSync by Marc Nuri offers a reliable solution for syncing emails, overcoming many of the limitations faced with other methods.&lt;/p&gt;

&lt;p&gt;Remember, this is a task you might need to run periodically, especially if you’re dealing with ongoing email migrations. By following this guide, you can ensure a smooth and efficient transition of your emails from one Gmail account to another.&lt;/p&gt;
</description>
        <pubDate>Tue, 09 Jul 2024 00:00:00 +0000</pubDate>
        <link>https://sunix.github.io/articles/howto/2024/07/09/email-migration.html</link>
        <guid isPermaLink="true">https://sunix.github.io/articles/howto/2024/07/09/email-migration.html</guid>
        
        <category>gmail</category>
        
        <category>migration</category>
        
        <category>imap</category>
        
        
        <category>articles</category>
        
        <category>Howto</category>
        
      </item>
    
      <item>
        <title>News from Eclipse Che Google Summer of Code 2016 Projects</title>
        <description>&lt;p&gt;Summer is heating up in the Eclipse Che ecosystem. More contributors, including Red Hat and SAP, are joining the Che adventure. Everyone is working hard on Che improvements, such as implementing the Language Server Protocol and multi-container workspaces.&lt;/p&gt;

&lt;p&gt;But they are not the only ones working this summer.&lt;/p&gt;

&lt;p&gt;Earlier this year, Florent and I submitted a few ideas to the Google Summer of Code (GSoC). The GSoC is a program organized by Google to encourage students to be more involved in open-source projects. Students get a well-paid summer job, and open-source projects gain promising new contributors. As part of the Eclipse Foundation, Eclipse Che is participating in this year’s Google Summer of Code. Codenvy and Serli are also participating as Eclipse Che GSoC project mentors for 2016.&lt;/p&gt;

&lt;!-- more --&gt;

&lt;h2 id=&quot;unit-tests-in-che&quot;&gt;Unit Tests in Che&lt;/h2&gt;

&lt;p&gt;In Che, Java unit test execution is possible out of the box thanks to Maven. To execute a test class opened in the editor, you can simply create a Maven command in Che:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;clean test -Dtest=${current.class.fqn}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You can even connect the debugger to it:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;clean test -Dtest=${current.class.fqn} -Dmaven.surefire.debug
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;However, this is not as good as the unit test UI we have in the classic Eclipse IDE.&lt;/p&gt;

&lt;p&gt;As part of the GSoC program, Mirage Abeysekara, a student from Sri Lanka, started implementing a Che extension for unit test execution:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Context menu for running test cases&lt;/strong&gt;: In the project explorer, right-clicking on a Java test class should show a menu item to run that test class.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Main menu item for running all tests&lt;/strong&gt;: The main menu bar contains a menu item for running all the test classes in the project.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;GUI for showing test runner state&lt;/strong&gt;: After launching the tests, the test runner window will open and show the current status of the test runner: launching, waiting for results, and finished.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;View the details of a failing test&lt;/strong&gt;: A window will display the failing test cases, including the stack trace and the differences in assertions.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Navigation to the failing class&lt;/strong&gt;: In the details window, there must be an action to let you jump to the failing test class.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Extendable framework&lt;/strong&gt;: The test runner plugin must provide an extendable framework for adding new test runner implementations without modifying the REST services and the GUI.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So far, Mirage is in his final steps. You can check out his work at &lt;a href=&quot;https://github.com/Mirage20/che/tree/che-java-test-runner-updated/plugins/plugin-java-test-runner&quot;&gt;GitHub&lt;/a&gt; and view an overview of his online demo on &lt;a href=&quot;https://www.youtube.com/watch?v=NgksCjhA9SY&quot;&gt;YouTube&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;pair-programming&quot;&gt;Pair Programming&lt;/h2&gt;

&lt;p&gt;Separately, Randika Navagamuwa is working on improving an existing prototype for pair programming within Che. This prototype was demoed during the last EclipseCon: &lt;a href=&quot;https://www.infoq.com/presentations/pair-programming-cloud&quot;&gt;InfoQ Presentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The prototype shows multiple Che editors connected to the same workspace and modifying the same file. All the editors receive live updates, just like in Google Docs.&lt;/p&gt;

&lt;p&gt;Randika is adding new features to the existing prototype and improving the code quality. There’s still a lot to do, but he has already implemented the display of other participants’ cursors. To do this, he had to get involved in two other Eclipse Foundation projects:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Eclipse Orion&lt;/strong&gt;: Che uses Orion as an embedded editor. Randika made a first demo just with Orion to display additional cursors using annotations.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Eclipse Flux&lt;/strong&gt;: Used to exchange messages during the pair programming session. Exchanging cursor positions involved registering a new message type in Flux.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Randika is currently refactoring the extension to simplify the implementation of new protocols used for the pair programming session.&lt;/p&gt;

&lt;p&gt;A video demo of his work can be found here: &lt;a href=&quot;https://youtu.be/OZNceE-sWto&quot;&gt;YouTube Demo&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For this first GSoC experience, we used Gitter for student/mentor daily communication. Che has also opened a Gitter channel (&lt;a href=&quot;https://gitter.im/eclipse/che&quot;&gt;Eclipse Che Gitter&lt;/a&gt;). We preferred this option to IRC, as IRC may be blocked by company firewalls. Generic questions go to the main Che Gitter channel, and specific questions related to the GSoC project go to mentors through direct messages.&lt;/p&gt;

&lt;p&gt;We’ve also tried to blog as much as we could about what we were doing during this program.&lt;/p&gt;

&lt;p&gt;Randika and I did a lot of instant messaging sessions when things were unclear. We organized video calls when necessary. We even used Che’s pair programming extension for our own pair programming sessions! It works pretty well, even with the Che server running in the US (AWS) and with two clients running in Sri Lanka and France.&lt;/p&gt;

&lt;p&gt;I wish all the best to the two students who are very close to their final evaluation! I hope they will continue to contribute to Che even after this GSoC program.&lt;/p&gt;
</description>
        <pubDate>Wed, 24 Aug 2016 00:00:00 +0000</pubDate>
        <link>https://sunix.github.io/articles/2016/08/24/google_summer_of_code.html</link>
        <guid isPermaLink="true">https://sunix.github.io/articles/2016/08/24/google_summer_of_code.html</guid>
        
        <category>eclipseche</category>
        
        <category>gsoc</category>
        
        <category>pairprogramming</category>
        
        <category>unittest</category>
        
        
        <category>articles</category>
        
      </item>
    
      <item>
        <title>EclipseCon France 2016: Language Server Protocol, Eclipse Che, and Commit Strip</title>
        <description>&lt;p&gt;This blog post will soon be available in French on the &lt;a href=&quot;http://www.serli.com/blog/articles&quot;&gt;Serli blog site&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Once again, I spent a fantastic week at EclipseCon France in Toulouse. A huge thank you to the Eclipse Foundation for organizing this amazing event! This year, I learned a lot and had many interesting discussions about Eclipse technologies.&lt;/p&gt;

&lt;!-- more --&gt;

&lt;h3 id=&quot;language-server-protocol&quot;&gt;Language Server Protocol&lt;/h3&gt;

&lt;p&gt;To me, the star of the conference was the Language Server Protocol (LSP), introduced by Microsoft’s TypeScript and its Language Server. It was featured in three presentations:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.eclipsecon.org/france2016/session/xtext%E2%80%99s-new-adventures-che&quot;&gt;Xtext’s New Adventures with Che&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.eclipsecon.org/france2016/session/jsdt-20&quot;&gt;JSDT 2.0&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.eclipsecon.org/france2016/session/typescript-feedback-real-life-project-within-typescript-and-future-javascript-sponsored&quot;&gt;TypeScript: Feedback from a Real-Life Project within TypeScript and the Future of JavaScript&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;language-server-protocol-1&quot;&gt;Language Server Protocol&lt;/h4&gt;

&lt;p&gt;During the Xtext on Che presentation, Sven described providing Xtext to Eclipse Che. Initially, implementing Xtext for another new editor seemed overwhelming due to the rapid emergence of new editors. Instead, he introduced the &lt;a href=&quot;https://github.com/Microsoft/language-server-protocol&quot;&gt;TypeScript/VSCode Language Server Protocol&lt;/a&gt;, which offers a standardized API reusable by any editor, not just Microsoft’s VSCode.&lt;/p&gt;

&lt;p&gt;This approach has two main benefits:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;Xtext developers won’t need to create and maintain implementations for each editor.&lt;/li&gt;
  &lt;li&gt;Eclipse Che will benefit from languages that implement the Language Service SPI.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In his talk, Sven outlined two main initiatives:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Providing an XText implementation of the Language Service SPI&lt;/li&gt;
  &lt;li&gt;Making Eclipse Che compatible with the Language Server Protocol&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;During the JSDT talk by Ilya Buziuk and the TypeScript talk by Sebastien Pertus, they highlighted the Eclipse plugin from Angelo Zerr, which uses the Language Server Protocol. This means existing Eclipse JavaScript plugins can be replaced by this new approach.&lt;/p&gt;

&lt;h3 id=&quot;eclipse-che&quot;&gt;Eclipse Che&lt;/h3&gt;

&lt;p&gt;Eclipse Che was another hot topic at the conference, featured in four sessions:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.eclipsecon.org/france2016/session/extending-eclipse-che-build-custom-cloud-ides&quot;&gt;Extending Eclipse Che to Build Custom Cloud IDEs&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.eclipsecon.org/france2016/session/code-cloud-eclipse-che-and-docker&quot;&gt;Code in the Cloud with Eclipse Che and Docker&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.eclipsecon.org/france2016/session/xtext%E2%80%99s-new-adventures-che&quot;&gt;Xtext’s New Adventures with Che&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Lunchtime Demo: Pair Programming in the Cloud with Eclipse Che&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the workshop, attendees learned how to create a custom developer environment for the Go language using Docker and add menu actions in the Cloud IDE.&lt;/p&gt;

&lt;p&gt;During the “Introduction to Eclipse Che” talk, Stevan and Florent demonstrated Che Java IDE’s capabilities, from basic code completion to remote debugging. They discussed the concept of universal workspaces and introduced the Github contribution factory link, developed by the Serli team, which enables quick project cloning in a preconfigured Che workspace.&lt;/p&gt;

&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/ekTT36vwHJI?list=PLy7t4z5SYNaRJff0KBMbubOaj8gevvML4&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;

&lt;p&gt;I also did a live demo of my pair programming plugin for Che, showcasing the first step towards a Google Docs-like experience in coding.&lt;/p&gt;

&lt;h3 id=&quot;commitstrip&quot;&gt;CommitStrip&lt;/h3&gt;

&lt;p&gt;For those who haven’t heard of Commit Strip, check out their comics at &lt;a href=&quot;http://commitstrip.com&quot;&gt;Commit Strip&lt;/a&gt;. Thomas and Etienne gave a great keynote at EclipseCon France, sharing their experiences as coders through humor and comics in the session &lt;a href=&quot;https://www.eclipsecon.org/france2016/session/explaining-code-my-mom-cassiop%C3%A9e&quot;&gt;Explaining Code to My Mom&lt;/a&gt;. My favorite strip is &lt;a href=&quot;http://www.commitstrip.com/fr/2015/10/21/why-marty-and-the-doc-might-not-arrive-after-all/&quot;&gt;Why Marty and the Doc Might Not Arrive After All&lt;/a&gt;.&lt;/p&gt;

&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/x2EQJpYBdc0?list=PLy7t4z5SYNaRJff0KBMbubOaj8gevvML4&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;

&lt;h3 id=&quot;other-notable-sessions&quot;&gt;Other Notable Sessions&lt;/h3&gt;

&lt;p&gt;Here are some other sessions I attended and enjoyed:&lt;/p&gt;

&lt;h4 id=&quot;what-every-java-developer-should-know-about-angularjs&quot;&gt;&lt;a href=&quot;https://www.eclipsecon.org/france2016/session/what-every-java-developer-should-know-about-angularjs&quot;&gt;What Every Java Developer Should Know About AngularJS&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;By Maximilian Koegel and Edgar Mueller [EclipseSource]&lt;/p&gt;

&lt;p&gt;This was a comprehensive guide for Java developers wanting to start with JavaScript and AngularJS.&lt;/p&gt;

&lt;h4 id=&quot;whats-new-in-eclipse-ide-and-the-ecosystem-around-it&quot;&gt;&lt;a href=&quot;https://www.eclipsecon.org/france2016/session/whats-new-eclipse-ide-and-ecosystem-around-it&quot;&gt;What’s New in Eclipse IDE and the Ecosystem Around It&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;By Sopot Cela and Mickael Istria [Red Hat]&lt;/p&gt;

&lt;p&gt;This talk covered upcoming features in the Neon release, including theme enhancements, text editor zoom, substring completion in JDT, smart project import, auto-save, and auto-suggest editors in the marketplace.&lt;/p&gt;

&lt;h4 id=&quot;the-state-of-docker-and-vagrant-tooling-in-eclipse&quot;&gt;&lt;a href=&quot;https://www.eclipsecon.org/france2016/session/state-docker-and-vagrant-tooling-eclipse&quot;&gt;The State of Docker and Vagrant Tooling in Eclipse&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;By Roland Grunberg [Red Hat]&lt;/p&gt;

&lt;p&gt;Roland presented the current status and future plans for Docker and Vagrant tools in Eclipse.&lt;/p&gt;

&lt;h4 id=&quot;java-9-support-in-eclipse&quot;&gt;&lt;a href=&quot;https://www.eclipsecon.org/france2016/session/java-9-support-eclipse&quot;&gt;Java 9 Support in Eclipse&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;By Sasikanth Bharadwaj [IBM]&lt;/p&gt;

&lt;p&gt;This session provided an overview of Jigsaw support in Eclipse and how to create and configure Jigsaw modules.&lt;/p&gt;

&lt;h4 id=&quot;jsdt-20&quot;&gt;&lt;a href=&quot;https://www.eclipsecon.org/france2016/session/jsdt-20&quot;&gt;JSDT 2.0&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;By Ilya Buziuk [Red Hat]&lt;/p&gt;

&lt;p&gt;JSDT is being renewed with features like running/debugging Node.js code, a JSON editor, and Grunt/Gulp support.&lt;/p&gt;

&lt;h4 id=&quot;typescript-feedback-from-a-real-life-project-within-typescript-and-the-future-of-javascript&quot;&gt;&lt;a href=&quot;https://www.eclipsecon.org/france2016/session/typescript-feedback-real-life-project-within-typescript-and-future-javascript-sponsored&quot;&gt;TypeScript: Feedback from a Real-Life Project within TypeScript and the Future of JavaScript&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;By Sebastien Pertus [Microsoft]&lt;/p&gt;

&lt;p&gt;This talk included live demos of various TypeScript features using Eclipse tools.&lt;/p&gt;

&lt;h4 id=&quot;fast-unit-tests-for-eclipse-plugins---possible-architectures-and-available-tooling&quot;&gt;&lt;a href=&quot;https://www.eclipsecon.org/france2016/session/fast-unit-tests-eclipse-plugins-possible-architectures-and-available-tooling&quot;&gt;Fast Unit Tests for Eclipse Plugins - Possible Architectures and Available Tooling&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;By Aurelien Pupier [Red Hat]&lt;/p&gt;

&lt;p&gt;Aurelien shared his experience with unit testing in Eclipse plugin development, discussing different setup options and productivity tools.&lt;/p&gt;

&lt;h4 id=&quot;a-generic-rest-api-on-top-of-eclipse-cdo-for-web-based-modelling&quot;&gt;&lt;a href=&quot;https://www.eclipsecon.org/france2016/session/generic-rest-api-top-eclipse-cdo-web-based-modelling&quot;&gt;A Generic REST API on Top of Eclipse CDO for Web-Based Modelling&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;By Christophe Ponsard&lt;/p&gt;

&lt;p&gt;This session demonstrated a modeling application running EMF behind the scenes with a web UI.&lt;/p&gt;

&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/C-kWMlz5yEY?list=PLy7t4z5SYNaRJff0KBMbubOaj8gevvML4&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;

&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;That’s all for now! Apologies for not covering other topics like IoT, Science, and Modeling. I will update this blog with links to recorded talks as they become available.&lt;/p&gt;

&lt;p&gt;Thank you to the EclipseCon organizers for a great event!&lt;/p&gt;

&lt;p&gt;PS: Special thanks to David Gosling, Stevan Le Meur, Florent Benoît, and Aurélien Pupier for the review.&lt;/p&gt;
</description>
        <pubDate>Fri, 24 Jun 2016 00:00:00 +0000</pubDate>
        <link>https://sunix.github.io/articles/2016/06/24/EclipseConFrance.html</link>
        <guid isPermaLink="true">https://sunix.github.io/articles/2016/06/24/EclipseConFrance.html</guid>
        
        <category>eclipseche</category>
        
        <category>typescript</category>
        
        <category>vscode</category>
        
        <category>eclipsecon</category>
        
        <category>commitstrip</category>
        
        <category>languageserverprotocol</category>
        
        
        <category>articles</category>
        
      </item>
    
      <item>
        <title>A Universal Eclipse IDE</title>
        <description>&lt;p&gt;This year, I am participating in Google Summer of Code as a mentor for the Eclipse umbrella organization. I’ve submitted a few ideas about Eclipse Che and Eclipse Flux, and some of them have been selected. I am mentoring the project “Pair Programming with Eclipse Che,” which involves improving an existing prototype I demonstrated at various developer conferences. You can check out the &lt;a href=&quot;https://github.com/sunix/che-plugin-flux-live-edit&quot;&gt;GitHub pair programming Che extension&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A few days ago, my padawan Randika encountered issues setting up his Eclipse IDE on the latest Ubuntu. He faced problems with GTK3 and experienced strange performance issues. I suggested he run the Eclipse IDE inside a Docker container, which worked fine. However, since we are not in the same location, it was difficult to assist him with advanced IDE configurations like GWT super dev mode.&lt;/p&gt;

&lt;p&gt;I posted in our Gitter chat room, “Let’s try something fun,” and we decided to launch Eclipse IDE inside an Eclipse Che Docker workspace hosted by Codenvy beta. When I posted a screenshot of this a few hours later, I received a lot of interactions on Twitter from the community: “Say whaaat?”, “WTF? :)”, “Got some more info? :)“, and “Worth writing a blog post on how to set this up?”&lt;/p&gt;

&lt;!-- more --&gt;

&lt;h2 id=&quot;eclipse-mars-running-inside-eclipse-che&quot;&gt;Eclipse Mars Running Inside Eclipse Che&lt;/h2&gt;

&lt;p&gt;Randika ended up writing a blog post explaining how we did this: &lt;a href=&quot;http://www.rnavagamuwa.com/open-source/run-eclipse-mars-ide-inside-eclipse-che/&quot;&gt;Run Eclipse Mars IDE inside Che&lt;/a&gt;. This trick helped me assist Randika in setting up his GWT super dev mode in Eclipse Mars, though it wasn’t anything revolutionary like Che.&lt;/p&gt;

&lt;h2 id=&quot;universal-eclipse-ide&quot;&gt;Universal Eclipse IDE&lt;/h2&gt;

&lt;p&gt;So, what’s next? You might have seen Tyler’s keynote at EclipseCon 2016 about “Universal Workspaces” &lt;a href=&quot;http://www.infoq.com/presentations/eclipse-che-eclipsecon-2016&quot;&gt;EclipseCon keynote&lt;/a&gt;. Here are my thoughts on building a Universal Eclipse IDE.&lt;/p&gt;

&lt;p&gt;In Randika’s demo, although “ssh -X” worked fine on our local computer, I experienced some latency when it ran in the Cloud. On the other hand, Che lacks many features and can’t yet fill the gap compared to the classic Eclipse Desktop IDE. Additionally, when you install an Eclipse IDE plugin, it prompts you to restart. But why? Isn’t it running on OSGi, one of its key features? I’ve heard someone say the problem lies with SWT and that it should be replaced with JavaFX. I believe we should use web technologies because they are the present and the future.&lt;/p&gt;

&lt;p&gt;So, I have a dream: that one day, every single Eclipse plugin will have its services exposed in REST and/or WebSocket.&lt;/p&gt;

&lt;p&gt;I have a dream that Eclipse developers can write plugins that work for both Che and the classic Eclipse IDE.&lt;/p&gt;

&lt;p&gt;I have a dream that Che developers won’t reinvent the wheel but will reuse Eclipse IDE core OSGi bundles.&lt;/p&gt;

&lt;p&gt;I have a dream that we won’t have to restart our IDE after installing a plugin.&lt;/p&gt;

&lt;p&gt;I have a dream that one day we will all use a Universal Eclipse IDE.&lt;/p&gt;

&lt;h2 id=&quot;yes-we-can&quot;&gt;Yes, We Can!&lt;/h2&gt;

&lt;p&gt;In my opinion, this isn’t that hard to achieve:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The Eclipse core bundle could expose a REST API or WebSocket. We would need an additional “org.eclipse.bundle.web” alongside the “org.eclipse.bundle.ui,” both using the “org.eclipse.bundle.core” bundle. Eclipse would run with a Jetty HTTP server bundle.&lt;/li&gt;
  &lt;li&gt;We would run a headless Eclipse IDE inside a Che Docker-based workspace with X forwarding.&lt;/li&gt;
  &lt;li&gt;Eclipse Che cloud IDE client extension and Orion could connect to these Eclipse web services.&lt;/li&gt;
  &lt;li&gt;Alternatively, we could improve Eclipse Flux, which started something similar.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Everyone would benefit from this:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Che could reuse existing bundles of the Eclipse IDE.&lt;/li&gt;
  &lt;li&gt;Che could access plugins from the existing Eclipse Marketplace.&lt;/li&gt;
  &lt;li&gt;For the Eclipse Desktop IDE, it would be time to rethink the design and decouple the UI from core services.&lt;/li&gt;
  &lt;li&gt;JavaScript works everywhere, eliminating the need to maintain SWT graphical libraries for each target architecture.&lt;/li&gt;
  &lt;li&gt;We could use any UI library and even mix them: SWT for navigation, GWT for view content, pure Orion JavaScript for the editor, and AngularJS for the marketplace.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;recap&quot;&gt;Recap&lt;/h2&gt;

&lt;p&gt;To me, the Eclipse Universal IDE would be:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Eclipse Che with a Docker-based workspace&lt;/li&gt;
  &lt;li&gt;Eclipse IDE running in the container&lt;/li&gt;
  &lt;li&gt;Eclipse IDE exposing web services&lt;/li&gt;
  &lt;li&gt;Eclipse Che Cloud IDE (the client side running in the browser) consuming services exposed by the Eclipse IDE and core services exposed by the Che server&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Eclipse Flux could be an option for the communication layer.&lt;/p&gt;
</description>
        <pubDate>Mon, 16 May 2016 00:00:00 +0000</pubDate>
        <link>https://sunix.github.io/articles/howto/2016/05/16/Universal-IDE.html</link>
        <guid isPermaLink="true">https://sunix.github.io/articles/howto/2016/05/16/Universal-IDE.html</guid>
        
        <category>che</category>
        
        <category>eclipse</category>
        
        <category>docker</category>
        
        <category>ide</category>
        
        
        <category>articles</category>
        
        <category>Howto</category>
        
      </item>
    
      <item>
        <title>VGA External Projector Not Detected with Ubuntu on Dell XPS 13</title>
        <description>&lt;p&gt;Just got back from an amazing &lt;a href=&quot;http://www.jugsummercamp.org/edition/6&quot;&gt;Jug Summercamp&lt;/a&gt; at La Rochelle. I was ready for the presentation of the &lt;a href=&quot;http://www.jugsummercamp.org/edition/6/presentation/1121&quot;&gt;Live Pair Programming with Eclipse Cloud Development&lt;/a&gt; and … AGAIN! I faced display issues with the external VGA projector not being detected on my computer, the same issue I encountered a few months ago at Eclipse Con France. Here’s how I managed to resolve it.&lt;/p&gt;

&lt;!-- more --&gt;

&lt;h3 id=&quot;problem-description&quot;&gt;Problem Description&lt;/h3&gt;
&lt;p&gt;When I plugged the VGA cable into my display port, the projector displayed “SEARCHING …”. No screen was detected on my laptop’s configuration screen. Interestingly, the setup worked fine in another room, which made me suspect an issue with the extension of the VGA cable.&lt;/p&gt;

&lt;h3 id=&quot;laptop-specifications&quot;&gt;Laptop Specifications&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Operating System:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Linux Ubuntu Trusty&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Laptop:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Dell System XPS L322X&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Display Device:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;00:02.0 VGA compatible controller: Intel Corporation 3rd Gen Core processor Graphics Controller (rev 09)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The laptop is connected to the external screen projector using a VGA cable and a mini-display-port to VGA adaptor.&lt;/p&gt;

&lt;h3 id=&quot;fix&quot;&gt;Fix&lt;/h3&gt;
&lt;p&gt;The following steps outline the fix. Note that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eDP1&lt;/code&gt; refers to the main laptop screen and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DP1&lt;/code&gt; refers to the external screen. Use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;xrandr&lt;/code&gt; command to get the status of your display:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Screen 0: minimum 320 x 200, current 1920 x 1080, maximum 32767 x 32767
eDP1 connected primary 1920x1080+0+0 &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;normal left inverted right x axis y axis&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; 294mm x 165mm
   1920x1080      60.0&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;+   59.9     40.0  
   1680x1050      60.0     59.9  
   1600x1024      60.2  
   1400x1050      60.0  
   1280x1024      60.0  
   1440x900       59.9  
   1280x960       60.0  
   1360x768       59.8     60.0  
   1152x864       60.0  
   1024x768       60.0  
   800x600        60.3     56.2  
   640x480        59.9  
VGA1 disconnected &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;normal left inverted right x axis y axis&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
HDMI1 disconnected &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;normal left inverted right x axis y axis&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
DP1 disconnected &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;normal left inverted right x axis y axis&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
VIRTUAL1 disconnected &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;normal left inverted right x axis y axis&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Choose a resolution that works with the external monitor and ensure your VGA cable is plugged in before running these commands:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Set the main display to the desired resolution&lt;/span&gt;
xrandr &lt;span class=&quot;nt&quot;&gt;--output&lt;/span&gt; eDP1 &lt;span class=&quot;nt&quot;&gt;--mode&lt;/span&gt; 1280x1024

&lt;span class=&quot;c&quot;&gt;# Add the mode resolution to the external projector&lt;/span&gt;
xrandr &lt;span class=&quot;nt&quot;&gt;--addmode&lt;/span&gt; DP1 1280x1024

&lt;span class=&quot;c&quot;&gt;# Activate the output for the external projector using a clone of the main display&lt;/span&gt;
xrandr &lt;span class=&quot;nt&quot;&gt;--output&lt;/span&gt; DP1 &lt;span class=&quot;nt&quot;&gt;--mode&lt;/span&gt; 1280x1024 &lt;span class=&quot;nt&quot;&gt;--same-as&lt;/span&gt; eDP1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Wait for 5 seconds and it should work!&lt;/p&gt;

&lt;h3 id=&quot;using-arandr&quot;&gt;Using Arandr&lt;/h3&gt;
&lt;p&gt;(Edit 21/01/2015)&lt;/p&gt;

&lt;p&gt;You can also use the GUI tool Arandr to generate xrandr commands.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://sunix.github.io/images/arandr.png&quot; alt=&quot;arandr&quot; /&gt;&lt;/p&gt;

&lt;p&gt;It generates scripts like this:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cat&lt;/span&gt; ~/.screenlayout/clone.sh 
&lt;span class=&quot;c&quot;&gt;#!/bin/sh&lt;/span&gt;
xrandr &lt;span class=&quot;nt&quot;&gt;--output&lt;/span&gt; HDMI1 &lt;span class=&quot;nt&quot;&gt;--off&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--output&lt;/span&gt; VIRTUAL1 &lt;span class=&quot;nt&quot;&gt;--off&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--output&lt;/span&gt; DP1 &lt;span class=&quot;nt&quot;&gt;--mode&lt;/span&gt; 1920x1080 &lt;span class=&quot;nt&quot;&gt;--pos&lt;/span&gt; 0x0 &lt;span class=&quot;nt&quot;&gt;--rotate&lt;/span&gt; normal &lt;span class=&quot;nt&quot;&gt;--output&lt;/span&gt; eDP1 &lt;span class=&quot;nt&quot;&gt;--mode&lt;/span&gt; 1920x1080 &lt;span class=&quot;nt&quot;&gt;--pos&lt;/span&gt; 0x0 &lt;span class=&quot;nt&quot;&gt;--rotate&lt;/span&gt; normal &lt;span class=&quot;nt&quot;&gt;--output&lt;/span&gt; VGA1 &lt;span class=&quot;nt&quot;&gt;--off&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;So, each time I need to clone my screen, I can just execute the script … et voilà!&lt;/p&gt;
</description>
        <pubDate>Sun, 20 Sep 2015 00:00:00 +0000</pubDate>
        <link>https://sunix.github.io/articles/howto/2015/09/20/Fix-xps-display-vga-screen.html</link>
        <guid isPermaLink="true">https://sunix.github.io/articles/howto/2015/09/20/Fix-xps-display-vga-screen.html</guid>
        
        <category>linux</category>
        
        <category>display</category>
        
        <category>xrandr</category>
        
        <category>mini display port</category>
        
        <category>ubuntu</category>
        
        
        <category>articles</category>
        
        <category>Howto</category>
        
      </item>
    
  </channel>
</rss>
