<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://pursuer.me/atom.xml" rel="self" type="application/atom+xml" /><link href="https://pursuer.me/" rel="alternate" type="text/html" /><updated>2026-01-07T23:45:28+00:00</updated><id>https://pursuer.me/atom.xml</id><title type="html">Pursuer</title><subtitle>For the good and beautiful. For meaning of life. For love and faith.</subtitle><entry><title type="html">Retiring EasyRSS</title><link href="https://pursuer.me/2024/01/14/retriring-easyrss/" rel="alternate" type="text/html" title="Retiring EasyRSS" /><published>2024-01-14T22:54:00+00:00</published><updated>2024-01-14T22:54:00+00:00</updated><id>https://pursuer.me/2024/01/14/Retriring%20EasyRSS</id><content type="html" xml:base="https://pursuer.me/2024/01/14/retriring-easyrss/"><![CDATA[<p>In 2013, as Google discontinued <a href="https://en.wikipedia.org/wiki/Google_Reader" target="_blank">Google Reader</a>, <a href="https://github.com/davidsun/EasyRSS" target="_blank">EasyRSS</a> stopped working. It was a rather unfortunate event. I was one of the users who heavily impacted by its discontinuation together with millions of users around the world. At the time I had the opportunity to switch EasyRSS to other RSS aggregators, such as <a href="https://feedly.com/" target="_blank">Feedly</a>, however, I didn’t get time to do it. Instead, I started using other news apps, such as <a href="https://about.flipboard.com/" target="_blank">Flipboard</a>.</p>

<p>I <a href="https://github.com/davidsun/EasyRSS" target="_blank">open-sourced EasyRSS on Github</a> in 2012, following my earlier promise. It was one of the most interesting college projects I worked on. I still remember I spent tens of hours optimizing the app’s performance to make it run smoothly on my old Android phone, a Sony Xperia running Android 2.3. There were some remarkable events, such as switching JSON parsing to use <a href="https://github.com/FasterXML/jackson" target="_blank">Jackson</a> instead of the system-provided JSON library, leading to a substantial speed up. HTML parsing <a href="https://github.com/davidsun/HtmlCleaner" target="_blank">was customized</a> as well to ensure the cleanness of the content. An early version of web page parser was built to extract the article from a web page, greatly shortening the content’s loading time. The app’s design got refreshed a few times. I was not a designer. However, after a few rounds of iterations, the app reached a point where the UI is quite mature, even in today’s eyes as I checked the <a href="https://github.com/davidsun/EasyRSS/tree/master/Screenshots" target="_blank">screenshots</a> just now. The app’s logo was created by myself, fitting into the app’s color scheme. I still like it very much.</p>

<p><img src="/assets/images/posts/2024-01-14-Retriring EasyRSS/logo.png" style="display: block; margin:0 auto; " /></p>

<p>Those are all fun activities, reminding me what the experience is to make an app single-handedly, and how limited the hardware is on older Android phones. Long gone the old days!</p>

<p>Though EasyRSS has stopped working for quite a while, I kept EasyRSS’s website alive, since it has been part of my personal website. It had been running quietly for more than 10 years. Days ago, as I decided to <a href="/2024/01/13/rebuilding-pursuer-me-using-jekyll/">rebuild my personal website</a>, EasyRSS’s website was finally shutdown. In the future, EasyRSS’s site traffic will be redirected to this post.</p>

<p>So, after so many interesting events, this marks the end of EasyRSS. What a fun journey!</p>]]></content><author><name></name></author><category term="技术" /><summary type="html"><![CDATA[In 2013, as Google discontinued Google Reader, EasyRSS stopped working. It was a rather unfortunate event. I was one of the users who heavily impacted by its discontinuation together with millions of users around the world. At the time I had the opportunity to switch EasyRSS to other RSS aggregators, such as Feedly, however, I didn’t get time to do it. Instead, I started using other news apps, such as Flipboard.]]></summary></entry><entry><title type="html">Rebuilding pursuer.me using Jekyll</title><link href="https://pursuer.me/2024/01/13/rebuilding-pursuer-me-using-jekyll/" rel="alternate" type="text/html" title="Rebuilding pursuer.me using Jekyll" /><published>2024-01-13T21:08:00+00:00</published><updated>2024-01-13T21:08:00+00:00</updated><id>https://pursuer.me/2024/01/13/Rebuilding%20pursuer.me%20using%20Jekyll</id><content type="html" xml:base="https://pursuer.me/2024/01/13/rebuilding-pursuer-me-using-jekyll/"><![CDATA[<p>My personal website, pursuer.me, was built using <a href="https://padrinorb.com/" target="_blank">Padrino</a> and hosted under <a href="https://www.linode.com/" target="_blank">Linode</a>. I had been thinking about rebuilding it for a while, as it was fairly aged in terms of its design and technology. I want to refresh it with a modern web framework and host it using more advanced technologies, preferably container + Kubernetes. Kubernetes might be an overkill for personal websites like this, but it’d be a great practice if I could try it out.</p>

<p>After much consideration, I decided to kick off the rebuild project last weekend. I picked a web framework called <a href="https://jekyllrb.com/" target="_blank">Jekyll</a>, which is being actively developed, offers lots of functionality and provides plenty of customization options.</p>

<p>For hosting, currently I’m using a temporary solution utilizing my home NAS. I’m not using Kubernetes yet, given the complexity to set it up. Docker is used. The Docker image contains the static pages generated by Jekyll and a simple web server, nginx. The Docker image runs on my home NAS. Another nginx instance for the entire NAS is used as the reverse proxy to redirect external traffic to the Docker image.</p>

<ul id="markdown-toc">
  <li><a href="#installing-ruby-and-jekyll" id="markdown-toc-installing-ruby-and-jekyll">Installing Ruby and Jekyll</a></li>
  <li><a href="#configuring" id="markdown-toc-configuring">Configuring</a>    <ul>
      <li><a href="#theming" id="markdown-toc-theming">Theming</a></li>
      <li><a href="#navigation" id="markdown-toc-navigation">Navigation</a></li>
      <li><a href="#page-titles-and-seo" id="markdown-toc-page-titles-and-seo">Page titles and SEO</a></li>
      <li><a href="#pagination" id="markdown-toc-pagination">Pagination</a></li>
      <li><a href="#google-analytics" id="markdown-toc-google-analytics">Google Analytics</a></li>
      <li><a href="#other-options" id="markdown-toc-other-options">Other options</a></li>
    </ul>
  </li>
  <li><a href="#migration" id="markdown-toc-migration">Migration</a></li>
  <li><a href="#deployment" id="markdown-toc-deployment">Deployment</a>    <ul>
      <li><a href="#automated-deployment" id="markdown-toc-automated-deployment">Automated deployment</a></li>
      <li><a href="#reverse-proxy-and-dns" id="markdown-toc-reverse-proxy-and-dns">Reverse proxy and DNS</a></li>
    </ul>
  </li>
  <li><a href="#whats-next" id="markdown-toc-whats-next">What’s next</a></li>
</ul>

<h1 id="installing-ruby-and-jekyll">Installing Ruby and Jekyll</h1>

<p>Jekyll is built using Ruby. I need to install a Ruby environment first. I used RVM:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>curl <span class="nt">-sSL</span> https://get.rvm.io | bash <span class="nt">-s</span> stable
<span class="c"># You can pick a different version</span>
<span class="nv">$ </span>rvm <span class="nb">install </span>3.3.0
</code></pre></div></div>

<p>and then install Jekyll:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>gem <span class="nb">install </span>jekyll bundler
<span class="c"># Create the web app</span>
<span class="nv">$ </span>jekyll new pursuer-me-v2
<span class="nv">$ </span><span class="nb">cd </span>pursuer-me-v2/
<span class="c"># Set up RVM for the app's folder</span>
<span class="nv">$ </span>rvm use <span class="nt">--create</span> 3.3.0@pursuer-me-v2
<span class="nv">$ </span>bundle <span class="nb">install</span>
<span class="c"># Try out the initial set up</span>
<span class="c"># The website should be available at http://127.0.0.1:4000/ if the following command succeeds</span>
<span class="nv">$ </span>bundle <span class="nb">exec </span>jekyll serve
</code></pre></div></div>

<h1 id="configuring">Configuring</h1>

<h2 id="theming">Theming</h2>

<p>Jekyll offers <a href="https://jekyllrb.com/resources/" target="_blank">plenty of themes</a>. For my personal website I picked <a href="https://github.com/mmistakes/so-simple-theme" target="_blank">So Simple</a>. Installing a new theme involves adding the theme gem to Gemfile and running <code class="language-plaintext highlighter-rouge">bundle install</code> afterwards:</p>

<div class="language-diff highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Remove the old theme and add the new
<span class="gd">- gem "minima", "~&gt; 2.5"
</span><span class="gi">+ gem "jekyll-theme-so-simple", "~&gt; 3.2.0"
</span></code></pre></div></div>

<p>The new theme needs to be registered in <code class="language-plaintext highlighter-rouge">_config.yml</code> by setting the <code class="language-plaintext highlighter-rouge">theme</code> option:</p>

<pre><code class="language-Ruby">theme: jekyll-theme-so-simple
</code></pre>

<h2 id="navigation">Navigation</h2>

<p>Navigation is configured based on the instructions under <a href="https://github.com/mmistakes/so-simple-theme?tab=readme-ov-file#navigation" target="_blank">So Simple theme’s README</a>.</p>

<h2 id="page-titles-and-seo">Page titles and SEO</h2>

<p>To generate the titles for each page, I found the plugin <code class="language-plaintext highlighter-rouge">jekyll-seo-tag</code> pretty handy. To install the plugin, add <code class="language-plaintext highlighter-rouge">gem "jekyll-seo-tag"</code> to <code class="language-plaintext highlighter-rouge">Gemfile</code> and add <code class="language-plaintext highlighter-rouge">jekyll-seo-tag</code> to the list of gems under <code class="language-plaintext highlighter-rouge">_config.yml</code> .</p>

<h2 id="pagination">Pagination</h2>

<p>To enable more pagination capabilities, I strongly recommend the plugin <code class="language-plaintext highlighter-rouge">jekyll-paginate-v2</code> instead of <code class="language-plaintext highlighter-rouge">jekyll-paginate</code> . Follow <a href="https://jekyllrb.com/docs/pagination/" target="_blank">the instructions under Jekyll site</a> for more detailed guidance.</p>

<p>The page navigation bar needs to be styled. Navigation bar styling is already provided by So Simple theme. To enable it, I added additional HTML to the home page, similar to <a href="https://github.com/mmistakes/so-simple-theme/blob/master/_includes/posts-paginated.html" target="_blank">how it is configured in So Simple theme</a>.</p>

<h2 id="google-analytics">Google Analytics</h2>

<p>Google is <a href="https://support.google.com/analytics/answer/10089681" target="_blank">retiring Universal Analytics in favor of Google Analytics 4</a>. With a theme that hasn’t updated for more than 3 years, I needed to customize the site’s footer to replace <a href="https://github.com/mmistakes/so-simple-theme/blob/master/_includes/scripts.html" target="_blank">the original <code class="language-plaintext highlighter-rouge">scripts</code> template provided by the theme</a>. The <code class="language-plaintext highlighter-rouge">scripts</code> template is referred to by <a href="https://github.com/mmistakes/so-simple-theme/blob/master/_layouts/default.html" target="_blank">the <code class="language-plaintext highlighter-rouge">default</code> page layout</a>, thus included in every page.</p>

<p>This is done by creating a new file: <code class="language-plaintext highlighter-rouge">_includes/scripts.html</code> and filling in the Javascript scripts following Google Analytics’s instructions:</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;script </span><span class="na">async</span> <span class="na">src=</span><span class="s">"https://www.googletagmanager.com/gtag/js?id={{ site.google_analytics }}"</span><span class="nt">&gt;&lt;/script&gt;</span>
<span class="nt">&lt;script&gt;</span>
    <span class="nb">window</span><span class="p">.</span><span class="nx">dataLayer</span> <span class="o">=</span> <span class="nb">window</span><span class="p">.</span><span class="nx">dataLayer</span> <span class="o">||</span> <span class="p">[];</span>

    <span class="kd">function</span> <span class="nf">gtag</span><span class="p">()</span> <span class="p">{</span>
        <span class="nx">dataLayer</span><span class="p">.</span><span class="nf">push</span><span class="p">(</span><span class="nx">arguments</span><span class="p">);</span>
    <span class="p">}</span>
    <span class="nf">gtag</span><span class="p">(</span><span class="dl">'</span><span class="s1">js</span><span class="dl">'</span><span class="p">,</span> <span class="k">new</span> <span class="nc">Date</span><span class="p">());</span>
    <span class="nf">gtag</span><span class="p">(</span><span class="dl">'</span><span class="s1">config</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">{{ site.google_analytics }}</span><span class="dl">'</span><span class="p">);</span>
<span class="nt">&lt;/script&gt;</span>
</code></pre></div></div>

<p>Creating a customized <code class="language-plaintext highlighter-rouge">scripts.html</code> provides other benefits too: I can upgrade javascript libraries’ versions to the latest instead of using the old version that was published &gt;3 years ago.</p>

<h2 id="other-options">Other options</h2>

<p>A few other options can be configured as well, such as <code class="language-plaintext highlighter-rouge">read_time</code> and <code class="language-plaintext highlighter-rouge">google_fonts</code> . See <a href="https://jekyllrb.com/docs/configuration/" target="_blank">the guide for Jekyll</a> and the theme’s <a href="https://github.com/mmistakes/so-simple-theme" target="_blank">Github page</a> for more options.</p>

<h1 id="migration">Migration</h1>

<p>My previous personal website categorizes the posts under a few labels, including “思行”, “往昔” and “技术”. The updated website follows the same structure. This is done by creating specific pages using the <code class="language-plaintext highlighter-rouge">category</code> layout (provided by So Simple theme, <a href="https://github.com/mmistakes/so-simple-theme/blob/master/_layouts/category.html" target="_blank">source code</a>), such as:</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">&lt;!-- experiencing.md --&gt;</span>
---
layout: category
permalink: /experiencing/
title: Experiencing - 往昔
taxonomy: 往昔
---
</code></pre></div></div>

<p>Posts are added to the <code class="language-plaintext highlighter-rouge">_posts</code> folder using <code class="language-plaintext highlighter-rouge">post</code> layout with <code class="language-plaintext highlighter-rouge">categories</code> attribute set to the desired labels. For example:</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">&lt;!-- _posts/2011-06-26-立志、努力、为公.md --&gt;</span>
---
layout: post
title: "立志、努力、为公"
date: 2011-06-26 01:00:00 UTC
categories: 思行
---
<span class="c">&lt;!-- Post content --&gt;</span>
</code></pre></div></div>

<h1 id="deployment">Deployment</h1>

<h2 id="automated-deployment">Automated deployment</h2>

<p>Automated deployment is set up for my new personal website. A typical deployment contains the following steps:</p>

<ol>
  <li>For any new development, a new git branch is created for any updates to the website. Commits are uploaded to a private repo (I used <a href="https://bitbucket.org/" target="_blank">Bitbucket</a>).</li>
  <li>Once the branch is ready to be published, create a pull request to merge the branch into <code class="language-plaintext highlighter-rouge">master</code> branch.</li>
  <li>Continuous integration (CI) is set up, such that whenever there is a new commit under the <code class="language-plaintext highlighter-rouge">master</code> branch, a Docker build is triggered. I used <a href="https://circleci.com/" target="_blank">CircleCI</a> for CI and <a href="https://hub.docker.com/" target="_blank">DockerHub</a> for Docker image hosting. CircleCI’s config file looks like the following:</li>
</ol>

<div class="language-yml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">version</span><span class="pi">:</span> <span class="m">2.1</span>
<span class="na">jobs</span><span class="pi">:</span>
  <span class="na">build-and-push</span><span class="pi">:</span>
    <span class="na">docker</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">image</span><span class="pi">:</span> <span class="s">cimg/base:2022.09</span>
        <span class="na">auth</span><span class="pi">:</span>
          <span class="na">username</span><span class="pi">:</span> <span class="s">$DOCKERHUB_USERNAME</span>
          <span class="na">password</span><span class="pi">:</span> <span class="s">$DOCKERHUB_PASSWORD</span>
    <span class="na">steps</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s">checkout</span>
      <span class="pi">-</span> <span class="s">setup_remote_docker</span>
      <span class="pi">-</span> <span class="na">restore_cache</span><span class="pi">:</span>
          <span class="na">keys</span><span class="pi">:</span>
            <span class="pi">-</span> <span class="s">v1-{{ .Branch }}</span>
          <span class="na">paths</span><span class="pi">:</span>
            <span class="pi">-</span> <span class="s">/caches/app.tar</span>
      <span class="pi">-</span> <span class="na">run</span><span class="pi">:</span>
          <span class="na">name</span><span class="pi">:</span> <span class="s">Load Docker image layer cache</span>
          <span class="na">command</span><span class="pi">:</span> <span class="pi">|</span>
            <span class="s">set +o pipefail</span>
            <span class="s">docker load -i /caches/app.tar | true</span>
      <span class="pi">-</span> <span class="na">run</span><span class="pi">:</span>
          <span class="na">name</span><span class="pi">:</span> <span class="s">Build and push application Docker image</span>
          <span class="na">command</span><span class="pi">:</span> <span class="pi">|</span>
            <span class="s">TAG=0.1.$CIRCLE_BUILD_NUM</span>
            <span class="s">docker build -t $DOCKERHUB_USERNAME/pursuer-me-v2-nginx:$TAG -t $DOCKERHUB_USERNAME/pursuer-me-v2-nginx:latest .</span>
            <span class="s">echo $DOCKERHUB_PASSWORD | docker login -u $DOCKERHUB_USERNAME --password-stdin</span>
            <span class="s">docker push --all-tags $DOCKERHUB_USERNAME/pursuer-me-v2-nginx</span>

<span class="na">workflows</span><span class="pi">:</span>
  <span class="na">deploy</span><span class="pi">:</span>
    <span class="na">jobs</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">build-and-push</span><span class="pi">:</span>
          <span class="na">filters</span><span class="pi">:</span>
            <span class="na">branches</span><span class="pi">:</span>
              <span class="na">only</span><span class="pi">:</span>
                <span class="pi">-</span> <span class="s">master</span>
</code></pre></div></div>

<p>and the Dockerfile looks like the following:</p>

<div class="language-Dockerfile highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Muitistage Dockerfile to first build the static site, then using nginx serve the static site</span>
<span class="k">FROM</span><span class="w"> </span><span class="s">ruby:latest</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="s">builder</span>
<span class="k">WORKDIR</span><span class="s"> /usr/src/app</span>
<span class="k">COPY</span><span class="s"> Gemfile ./</span>
<span class="k">RUN </span>bundle <span class="nb">install</span>
<span class="k">COPY</span><span class="s"> . .</span>
<span class="k">RUN </span><span class="nv">JEKYLL_ENV</span><span class="o">=</span>production bundle <span class="nb">exec </span>jekyll build

<span class="c"># Copy _sites from build to Nginx Container to serve site</span>
<span class="k">FROM</span><span class="s"> nginx:latest</span>
<span class="k">COPY</span><span class="s"> --from=builder /usr/src/app/_site /usr/share/nginx/html</span>
<span class="k">EXPOSE</span><span class="s"> 80</span>
<span class="k">CMD</span><span class="s"> ["nginx", "-g", "daemon off;"]</span>

</code></pre></div></div>

<p>On my home NAS, I use <a href="https://github.com/containrrr/watchtower" target="_blank">Docker watchtower</a> to monitor Docker image updates on <code class="language-plaintext highlighter-rouge">pursuer91/pursuer-me-v2-nginx:latest</code> and automatically restart the server when there is a new image. Here’s the config for Docker Compose:</p>

<div class="language-yml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">services</span><span class="pi">:</span>
  <span class="na">pursuer_me</span><span class="pi">:</span>
    <span class="na">container_name</span><span class="pi">:</span> <span class="s">pursuer_me-compose</span>
    <span class="na">image</span><span class="pi">:</span> <span class="s">pursuer91/pursuer-me-v2-nginx:latest</span>
    <span class="na">restart</span><span class="pi">:</span> <span class="s">unless-stopped</span>
    <span class="na">ports</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s2">"</span><span class="s">9023:80"</span>
  <span class="na">watchtower</span><span class="pi">:</span>
    <span class="na">container_name</span><span class="pi">:</span> <span class="s">watchtower-compose</span>
    <span class="na">image</span><span class="pi">:</span> <span class="s">containrrr/watchtower</span>
    <span class="na">restart</span><span class="pi">:</span> <span class="s">unless-stopped</span>
    <span class="na">volumes</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s">/var/run/docker.sock:/var/run/docker.sock</span>
    <span class="na">command</span><span class="pi">:</span> <span class="s">pursuer_me-compose --interval </span><span class="m">600</span>
</code></pre></div></div>

<p>During the deployment, the site will be down for a few seconds. Thanks to the page caching provided by <a href="https://www.cloudflare.com/" target="_blank">Cloudflare</a>, the actual downtime should be much less.</p>

<h2 id="reverse-proxy-and-dns">Reverse proxy and DNS</h2>

<p>Pursuer.me is hosted by <a href="https://www.cloudflare.com/" target="_blank">Cloudflare</a>. I use <a href="https://ddclient.net/" target="_blank">ddclient</a> to periodically update the DNS record under Cloudflare and <a href="https://letsencrypt.org/" target="_blank">Let’s Encrypt</a> for HTTPS.</p>

<p>Nginx is used as the reverse proxy so the public traffic on pursuer.me will be redirected to the Docker instance. The Nginx configuration looks like the following:</p>

<div class="language-nginx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">server</span> <span class="p">{</span>
    <span class="kn">server_name</span> <span class="s">pursuer.me</span><span class="p">;</span>
    <span class="kn">location</span> <span class="n">/</span> <span class="p">{</span>
            <span class="kn">proxy_pass</span> <span class="s">http://127.0.0.1:9023</span><span class="p">;</span>
            <span class="kn">proxy_set_header</span> <span class="s">Host</span> <span class="nv">$host</span><span class="p">;</span>
            <span class="kn">proxy_set_header</span> <span class="s">X-Forwarded-For</span> <span class="nv">$proxy_add_x_forwarded_for</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="kn">access_log</span> <span class="n">/var/log/nginx/localhost.access_log</span> <span class="s">main</span><span class="p">;</span>
    <span class="kn">error_log</span> <span class="n">/var/log/nginx/localhost.error_log</span> <span class="s">info</span><span class="p">;</span>

    <span class="kn">listen</span> <span class="mi">443</span> <span class="s">ssl</span><span class="p">;</span> <span class="c1"># managed by Certbot</span>
    <span class="kn">ssl_certificate</span> <span class="n">/etc/letsencrypt/live/pursuer.me/fullchain.pem</span><span class="p">;</span> <span class="c1"># managed by Certbot</span>
    <span class="kn">ssl_certificate_key</span> <span class="n">/etc/letsencrypt/live/pursuer.me/privkey.pem</span><span class="p">;</span> <span class="c1"># managed by Certbot</span>
    <span class="kn">include</span> <span class="n">/etc/letsencrypt/options-ssl-nginx.conf</span><span class="p">;</span> <span class="c1"># managed by Certbot</span>
    <span class="kn">ssl_dhparam</span> <span class="n">/etc/letsencrypt/ssl-dhparams.pem</span><span class="p">;</span> <span class="c1"># managed by Certbot</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Note that the line marked as <code class="language-plaintext highlighter-rouge"># managed by Certbot</code> are added by <a href="https://letsencrypt.org/" target="_blank">Let’s Encrypt</a> for HTTPS certification management.</p>

<h1 id="whats-next">What’s next</h1>

<p>The next step is to set up Kubernetes under my VPS to better automate the deployment process and avoid site downtime during the deployment.</p>]]></content><author><name></name></author><category term="技术" /><summary type="html"><![CDATA[My personal website, pursuer.me, was built using Padrino and hosted under Linode. I had been thinking about rebuilding it for a while, as it was fairly aged in terms of its design and technology. I want to refresh it with a modern web framework and host it using more advanced technologies, preferably container + Kubernetes. Kubernetes might be an overkill for personal websites like this, but it’d be a great practice if I could try it out.]]></summary></entry><entry><title type="html">Trip to Yosemite</title><link href="https://pursuer.me/2023/08/09/trip-to-yosemite/" rel="alternate" type="text/html" title="Trip to Yosemite" /><published>2023-08-09T03:37:00+00:00</published><updated>2023-08-09T03:37:00+00:00</updated><id>https://pursuer.me/2023/08/09/Trip%20to%20Yosemite</id><content type="html" xml:base="https://pursuer.me/2023/08/09/trip-to-yosemite/"><![CDATA[<p>My parents visited the US. We decided to go to Yosemite, the national park not far away from the bay area, which is famous for its waterfalls, meadows, cliffs and rock formations.</p>

<p>We departed on Friday morning, went to Mariposa, a small town on the route to Yosemite for lunch, and arrived at Yosemite Valley at about 4PM. The traffic got much worse when we were close the the park. I guessed it could be worse, as I read from the news that people ended up with spending 2-3 hours in the traffic and looking for parking a few weeks earlier, during the long holiday, while it only took us less than an hour. It was Yosemite’s busy season. Plenty of water in the waterfalls.</p>

<p>We took a short walk to Lower Yosemite Fall upon arrival. The trail took ~30 mins roundtrip, between the waterfall base and visitor center. Spectacular view of both lower and upper Yosemite Fall.</p>

<p><img src="/assets/images/posts/2023-08-08-Trip to Yosemite/904A5600.jpg" style="display: block; width:400px; margin:0 auto; " /></p>

<p>Later in the afternoon, we took on a guided tour around Yosemite on a tram. A park ranger sit in front of the tram, telling us everything about the park - the park’s history, the various mountain hiking events that turned impossible into possible, the famous climbers, the woods, the animals, the forest fire, and so on. What I memorized the most, was about the bears. I kept what the ranger said in mind throughout the trip: don’t feed the bears and don’t leave smelly food in the car. Bears have the best sense of smell. The smell of peanut butter can attract them from miles away. What’s more, once they’ve tasted it, they’ll get addicted to it just like we human beings getting addicted to drugs. I didn’t witness any bear during our trip though.</p>

<p>The tram stopped at a few places. One of them is Tunnel View, where we could see El Capitan, Half Dome and Bridalveil Fall from the vista.</p>

<p><img src="/assets/images/posts/2023-08-08-Trip to Yosemite/904A5638.jpg" alt="" /></p>

<p>We hiked at Yosemite Falls Trail on the second day. A bird view of the valley:</p>

<p><img src="/assets/images/posts/2023-08-08-Trip to Yosemite/IMG20230729123208.jpg" alt="" /></p>

<p>And after hiking long enough, we could see the upper Yosemite Fall. We’ve hiked halfway to the top. The fall looked different:</p>

<p><img src="/assets/images/posts/2023-08-08-Trip to Yosemite/IMG20230729125030.jpg" style="display: block; width:400px; margin:0 auto; " /></p>

<p>On the third day, we took the Valley Loop Trail, a beautiful, quiet and fairly level trail looping through the valley, as the name suggests. There is mountains all around.</p>

<p><img src="/assets/images/posts/2023-08-08-Trip to Yosemite/IMG20230730074648.jpg" alt="" /></p>

<p><img src="/assets/images/posts/2023-08-08-Trip to Yosemite/IMG20230730103208.jpg" alt="" /></p>

<p><img src="/assets/images/posts/2023-08-08-Trip to Yosemite/IMG20230730080436.jpg" alt="" /></p>

<p><img src="/assets/images/posts/2023-08-08-Trip to Yosemite/IMG20230730075905.jpg" alt="" /></p>

<p>We went to Mirror Lake on the last day. There was a small river on the way there:</p>

<p><img src="/assets/images/posts/2023-08-08-Trip to Yosemite/IMG20230731095528.jpg" alt="" /></p>

<p>Mirror Lake is a small lake surrounded by the tall mountains. To get back on a different route, we crossed the lake by tapping into the water. The water was cold, urging us to walk faster, however the rocks on the lake bed were sharp, slowing us down. What a dilemma.</p>

<p><img src="/assets/images/posts/2023-08-08-Trip to Yosemite/IMG20230731112908.jpg" alt="" /></p>

<p>We left for home after having lunch. Another 4 hour of driving.</p>

<p>Yosemite is such a beautiful place. The beauty and variety of natural attractions made it all worth it. Definitely want to visit again.</p>]]></content><author><name></name></author><category term="往昔" /><summary type="html"><![CDATA[My parents visited the US. We decided to go to Yosemite, the national park not far away from the bay area, which is famous for its waterfalls, meadows, cliffs and rock formations.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://pursuer.me/assets/images/posts/2023-08-08-Trip%20to%20Yosemite/IMG20230730075646-Full.jpg" /><media:content medium="image" url="https://pursuer.me/assets/images/posts/2023-08-08-Trip%20to%20Yosemite/IMG20230730075646-Full.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">那些变化的与不变的</title><link href="https://pursuer.me/2018/11/11/%E9%82%A3%E4%BA%9B%E5%8F%98%E5%8C%96%E7%9A%84%E4%B8%8E%E4%B8%8D%E5%8F%98%E7%9A%84/" rel="alternate" type="text/html" title="那些变化的与不变的" /><published>2018-11-11T19:37:00+00:00</published><updated>2018-11-11T19:37:00+00:00</updated><id>https://pursuer.me/2018/11/11/%E9%82%A3%E4%BA%9B%E5%8F%98%E5%8C%96%E7%9A%84%E4%B8%8E%E4%B8%8D%E5%8F%98%E7%9A%84</id><content type="html" xml:base="https://pursuer.me/2018/11/11/%E9%82%A3%E4%BA%9B%E5%8F%98%E5%8C%96%E7%9A%84%E4%B8%8E%E4%B8%8D%E5%8F%98%E7%9A%84/"><![CDATA[<p>前些时候和一个朋友聊天，聊到了生活的无力感：周围的朋友经历着不开心，可自己却无能为力。生活的残酷挤压着童年遗留下来的改变周遭环境的梦想，周围的世界便不再那么乐观。上周与另外一个同事聊起类似的事情——他在工作中遭遇了一些不公，无力改变，于是决定换一个环境重新开始。我半严肃半开玩笑地调侃说，可能我不会放弃吧，还是要努力一下——哪怕努力失败了，至少也不会后悔。我同事笑笑说，对啊。然后他还是放弃了。</p>

<p>周末得空，翻看了一下过去的文字。我发现了一个模式：这些文字总从描述生活磨难的开始，最后却得出生活依然美好并且要坚持努力的结论。想想这个模式挺可怕的：一个十几岁的少年的生活里哪有这么多的悲观，而一个人需要多大的勇气才能克服这些悲观并坚持努力呢。或许这些文字都是最不开心的时候写下来的吧，只有艰难和痛苦才是最刻骨铭心的。</p>

<p>好像我依然活在之前的模式中。近些年经历多了一些，对很多事情可能会释然一些：和朋友一样，我时常能够感受到无力感，久而久之我对这种无力感也习以为常了，把其视作生活的一部分。这多多少少消磨了我改变生活的勇气。可是动力并没有消失：早晨起来，想到那些不完美的的事情，总想再尝试一下。有点矛盾。</p>

<p>我大概对这些矛盾感到过忧虑吧，想象着自己能不能让那些不完美的事物过去。不过这些忧虑总是短暂的，到头来我还是会做类似的选择。很有意思。</p>

<p>今年早些时候朋友推荐我看了一部动漫：《钢之炼金术士》。对动漫从来都不感冒的我看了前几集后竟然不由自主地把整部动漫看完了。几个月前我看了第二遍，有了更深的体会。这部动漫让我思考了很多事情：一个剥离了七宗罪的人能成为一个完美的人吗？世界最终还是因果。那些存在于一个人身上的最本质的元素，比如对世界悲观而清晰的认识，抑或是积极地改变世界的态度，或许是无法改变的。于是追求的便不再是完美，而是清晰地认识了自己后对自己的认可和接受。每每这样一想，也就释然了：很多痛苦大概来源于不清晰的认知，或者对认知的不接受吧。</p>

<p>诶，这篇文字好像是脱离了过去的模式了。</p>]]></content><author><name></name></author><category term="思行" /><summary type="html"><![CDATA[前些时候和一个朋友聊天，聊到了生活的无力感：周围的朋友经历着不开心，可自己却无能为力。生活的残酷挤压着童年遗留下来的改变周遭环境的梦想，周围的世界便不再那么乐观。上周与另外一个同事聊起类似的事情——他在工作中遭遇了一些不公，无力改变，于是决定换一个环境重新开始。我半严肃半开玩笑地调侃说，可能我不会放弃吧，还是要努力一下——哪怕努力失败了，至少也不会后悔。我同事笑笑说，对啊。然后他还是放弃了。]]></summary></entry><entry><title type="html">感恩</title><link href="https://pursuer.me/2013/11/11/%E6%84%9F%E6%81%A9/" rel="alternate" type="text/html" title="感恩" /><published>2013-11-11T09:35:00+00:00</published><updated>2013-11-11T09:35:00+00:00</updated><id>https://pursuer.me/2013/11/11/%E6%84%9F%E6%81%A9</id><content type="html" xml:base="https://pursuer.me/2013/11/11/%E6%84%9F%E6%81%A9/"><![CDATA[<p>好久都没有写一篇博客了。这里仿佛被遗弃的花园，叶子落了一地，也不知自己是不是错过了成熟的果实。我一篇篇文章地读过，看着自己一次次走出荆棘，前路却依然茫茫。很奇怪，哪怕是快乐的记忆，也带有一丝的伤感。或许这花园就是这样一个地方，让思想沉淀，留出心灵的空间。</p>

<p>我看到了几条新的评论，甚是感动。我未曾想到这些文字除了自我陶醉外还有这样的作用。我很欣慰，看到自己在简单、真实的道路上多了一个伙伴。</p>

<p>今天是11.11，回想去年的今天我或许在网上疯狂购物，买齐那些在购物车中囤积了多时的书籍。今年却大不一样——在美国，再过些时日就是感恩节了。也的确需要感恩。谢谢了！</p>

<p>献给所有我爱的人和爱我的人。</p>]]></content><author><name></name></author><category term="往昔" /><summary type="html"><![CDATA[好久都没有写一篇博客了。这里仿佛被遗弃的花园，叶子落了一地，也不知自己是不是错过了成熟的果实。我一篇篇文章地读过，看着自己一次次走出荆棘，前路却依然茫茫。很奇怪，哪怕是快乐的记忆，也带有一丝的伤感。或许这花园就是这样一个地方，让思想沉淀，留出心灵的空间。]]></summary></entry><entry><title type="html">EasyRSS 开源了</title><link href="https://pursuer.me/2012/11/04/easyrss-%E5%BC%80%E6%BA%90%E4%BA%86/" rel="alternate" type="text/html" title="EasyRSS 开源了" /><published>2012-11-04T21:10:00+00:00</published><updated>2012-11-04T21:10:00+00:00</updated><id>https://pursuer.me/2012/11/04/EasyRSS%20%E5%BC%80%E6%BA%90%E4%BA%86</id><content type="html" xml:base="https://pursuer.me/2012/11/04/easyrss-%E5%BC%80%E6%BA%90%E4%BA%86/"><![CDATA[<p>一年多前开始开发 EasyRSS，从最初的对 Android 一窍不通到逐渐了解。一年以来，EasyRSS 积累了不少用户，这对我是极大的鼓励。</p>

<p>之前有过承诺，如果没有时间维护 EasyRSS，就将这个项目开源。现在，手头的事情越来越多，显然是没有更多时间来维持 EasyRSS 的开发了。因此，兑现承诺，将项目开源。项目的地址是：https://github.com/davidsun/EasyRSS。欢迎 Fork！</p>]]></content><author><name></name></author><category term="技术" /><summary type="html"><![CDATA[一年多前开始开发 EasyRSS，从最初的对 Android 一窍不通到逐渐了解。一年以来，EasyRSS 积累了不少用户，这对我是极大的鼓励。]]></summary></entry><entry><title type="html">近期体会 2012.10</title><link href="https://pursuer.me/2012/10/29/%E8%BF%91%E6%9C%9F%E4%BD%93%E4%BC%9A-2012-10/" rel="alternate" type="text/html" title="近期体会 2012.10" /><published>2012-10-29T22:49:00+00:00</published><updated>2012-10-29T22:49:00+00:00</updated><id>https://pursuer.me/2012/10/29/%E8%BF%91%E6%9C%9F%E4%BD%93%E4%BC%9A%202012.10</id><content type="html" xml:base="https://pursuer.me/2012/10/29/%E8%BF%91%E6%9C%9F%E4%BD%93%E4%BC%9A-2012-10/"><![CDATA[<p>近段时间偶尔回味一下过去写的文章，每一次看都会有些体会。距上一次写感受已经半年有余了，最近总是觉得要写点什么，然而静下心了却又觉得无事可写，仿佛工作繁忙了思考就少了。恍惚之间让细务占据了心灵，回头却只能感叹时光飞逝。</p>

<p>其实体会不应该少。前些时日看完了《大秦帝国》，后来又读了一些有关做事方式的书，感触颇深。</p>

<p>《大秦帝国》展示了秦国从建国到称霸直到灭亡的历史画卷。作者是个理想主义者，在书中有不少大是大非的描述。如此描述也未尝不可，只是世间的事务永远不会如此完美。纵然如此，当融入了情绪，依然会感动于朝代的伟大，亦为其灭亡而感到惋惜。反观自己，更加觉得自己需要处理好决策与执行的关系，同时也从历史人物的经历中学会了更平和的心态。</p>

<p>更多地是在实践中体会。很多事情在慢慢地发生变化，到头了却又未必说的出一个所以然来。涓涓细流汇成江河湖海，一直向前走，总会有很多收获。</p>]]></content><author><name></name></author><category term="思行" /><summary type="html"><![CDATA[近段时间偶尔回味一下过去写的文章，每一次看都会有些体会。距上一次写感受已经半年有余了，最近总是觉得要写点什么，然而静下心了却又觉得无事可写，仿佛工作繁忙了思考就少了。恍惚之间让细务占据了心灵，回头却只能感叹时光飞逝。]]></summary></entry><entry><title type="html">编译框架</title><link href="https://pursuer.me/2012/06/18/%E7%BC%96%E8%AF%91%E6%A1%86%E6%9E%B6/" rel="alternate" type="text/html" title="编译框架" /><published>2012-06-18T14:54:00+00:00</published><updated>2012-06-18T14:54:00+00:00</updated><id>https://pursuer.me/2012/06/18/%E7%BC%96%E8%AF%91%E6%A1%86%E6%9E%B6</id><content type="html" xml:base="https://pursuer.me/2012/06/18/%E7%BC%96%E8%AF%91%E6%A1%86%E6%9E%B6/"><![CDATA[<p>这学期有编译这门课。这门课甚是无聊，我大约翘了一半。课程包含一个Project，任务是分三次来完成一个编译器。和其他课程的Project一样，起初，我想随便灌灌水就过去。可是，一天早上起来，我突然想到了一个编译器的框架——在这个框架下，仅仅修改一部分配置文件就能实现一门语言的编译过程。于是，从上周六开始，我着手实现了编译框架的各个部分（包括词法分析、语法分析、中间代码生成与中间代码解析执行）。说实话，看着编译框架的一个个部分逐渐实现并正常运行，心里还是很激动的。我回想，这可能是大学时期自己做过的最有意思的课程Project了。</p>

<p>我最早的想法很简答——编程者都会在编写代码的过程中产生自己对于编程语言的看法。比如，在PASCAL中，函数的定义是这样的：</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>&lt;type&gt; &lt;function name&gt; ( &lt;variable 1&gt; : &lt;variable type 1&gt;, &lt;variable 2&gt;: &lt;variable type 2&gt;, ... )
</code></pre></div></div>

<p>在C语言中，函数的定义是这样的：</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>&lt;type&gt; &lt;function name&gt; ( &lt;variable type 1&gt; &lt;variable 1&gt;, &lt;variable type 2&gt; &lt;variable 2&gt;, ... )
</code></pre></div></div>

<p>当然，两种方法仅仅是语法上的差别，但是，不同的编程者可能会有偏好（我个人喜欢后一种）。</p>

<p>尽管编程语言在语法上会有差别，但只要是面向过程（或函数式）的语言（面向对象的语言模型就大大不同了），其语言的特性都是类似的，无非是以下几条：</p>

<ol>
  <li>顺序执行</li>
  <li>条件分支</li>
  <li>循环</li>
  <li>函数调用</li>
</ol>

<p>那么，对于这些语言，语法不那么重要——无论何种语言，都可以对应到一套预定义的中间代码上面去。对应的过程很简单——仅仅需要将代码的每一种规约方式（比如，if语句的某一种归约方式可以为“if (判断){执行}”）翻译到中间代码就可以了。依然以“if (判断){执行}”的语句为例，假设这句语句的形式是“W(X){P}”，其中，W代表if，X代表一判断语句，P代表一代码片段，那么，这句语句可以这样对应到中间代码：</p>

<ul>
  <li>STEP 1：生成X对应的代码</li>
  <li>STEP 2：根据STEP 1的结果，如果结果为1，跳转到STEP 4</li>
  <li>STEP 3：生成P对应的代码</li>
  <li>STEP 4：（空）</li>
</ul>

<p>实践证明，任何一个类似于上述if语句的归约方式，都可以翻译到一个仅仅包含了17个语句的中间代码中（这17个语句是我自己定义的，有可能还可以减少）。</p>

<p>那么，问题就变成了这样——只要一种语言的语法可以用LR Parser（<a href="http://en.wikipedia.org/wiki/LR_parser" target="_blank">http://en.wikipedia.org/wiki/LR_parser</a>）、LALR Parser（<a href="http://en.wikipedia.org/wiki/LALR_parser" target="_blank">http://en.wikipedia.org/wiki/LALR_parser</a>）等parse算法接受，并且，这种语言的上下文关联性不是很强，这门语言就可以被这个被编译框架接受。当然，如果语言的关联性很强，比如支持面向对象特性，中间代码的生成就可能需要分多次执行（像gcc的link过程一样），这类语言的翻译过程我还没有想得特别清楚。</p>

<p>下一步，对于只包含了17个语句的中间代码，解析执行就十分简单了。其中需要注意的几点是：</p>

<ol>
  <li>变量的重复声明，或者未声明使用，都是需要判断的</li>
  <li>每个变量都有自己的定义域，出了定义域，变量就失效了</li>
  <li>函数调用可以是递归的，需要一个函数调用的栈来处理</li>
</ol>

<p>当然，这几点实现起来都不是很难。至于变量的定义域，我特地在中间代码中加入了SCOPE和ENDSCOPE两个语句——这样，在解析执行时，什么时候要申请变量以及什么时候要销毁变量就变得简单、直接了。</p>

<p>以上是对这个编译框架的简单描述。有空我再说得具体一些。</p>

<p>项目的代码我已经上传到GitHub（<a href="https://github.com/davidsun/TinyCompiler" target="_blank">https://github.com/davidsun/TinyCompiler</a>），欢迎围观。</p>]]></content><author><name></name></author><category term="技术" /><summary type="html"><![CDATA[这学期有编译这门课。这门课甚是无聊，我大约翘了一半。课程包含一个Project，任务是分三次来完成一个编译器。和其他课程的Project一样，起初，我想随便灌灌水就过去。可是，一天早上起来，我突然想到了一个编译器的框架——在这个框架下，仅仅修改一部分配置文件就能实现一门语言的编译过程。于是，从上周六开始，我着手实现了编译框架的各个部分（包括词法分析、语法分析、中间代码生成与中间代码解析执行）。说实话，看着编译框架的一个个部分逐渐实现并正常运行，心里还是很激动的。我回想，这可能是大学时期自己做过的最有意思的课程Project了。]]></summary></entry><entry><title type="html">脆弱且渺小</title><link href="https://pursuer.me/2012/04/05/%E8%84%86%E5%BC%B1%E4%B8%94%E6%B8%BA%E5%B0%8F/" rel="alternate" type="text/html" title="脆弱且渺小" /><published>2012-04-05T22:21:00+00:00</published><updated>2012-04-05T22:21:00+00:00</updated><id>https://pursuer.me/2012/04/05/%E8%84%86%E5%BC%B1%E4%B8%94%E6%B8%BA%E5%B0%8F</id><content type="html" xml:base="https://pursuer.me/2012/04/05/%E8%84%86%E5%BC%B1%E4%B8%94%E6%B8%BA%E5%B0%8F/"><![CDATA[<p>我算是消息闭塞的人了，到了今天下午，才知道上海交大的几个学生在旅游时出了事情。年轻的生命便如此湮灭了。身边的朋友感叹生命的脆弱——那几位年轻小伙，从谈笑风生到匆匆离去，仅仅是几分钟的时间。世事难料，若知后果如此，他们必然不会去做这样的事情。当然，这都是后话，有些事情，当时的人又怎么会知道后果呢？</p>

<p>记得帕斯卡尔曾说：“人是一根会思想的苇草”。的确，将生命置于广袤的天地，确实是同苇草一般，在风中飘渺，不知哪日会拦腰折断。可正是这种脆弱与不确定性，才塑造了生命的伟大——近日读了一些历史，看着恢宏的场景在书卷中徐徐展开。历史上人才辈出，然则反观这些伟人的生命，却是如苇草般脆弱。他们必然是经历了九死一生，方才成就了伟大的功业。春去秋来，历史的车轮滚滚向前，他们的生命在天空中绽放出点点光芒。</p>

<p>今天晚上与一同学讨论了一些人生的事情。这类事情总是如此地沉重。青年人总会觉得世间有太多的不确定，固总会迷茫，不满于现实，担忧未来。佛教说，痛苦来源于无知，想必也有一些这个层面的含义。然则，正是因为这不确定的种种，让我们有走下去的勇气，探索未来，成就事业。</p>

<p>固不必如此担忧了，知道生命的脆弱与渺小，便知当下之宝贵，也就会珍惜现在的时光了。末了我也是那样与那位同学说的。渺小依然，而征途才刚刚开始。</p>]]></content><author><name></name></author><category term="思行" /><summary type="html"><![CDATA[我算是消息闭塞的人了，到了今天下午，才知道上海交大的几个学生在旅游时出了事情。年轻的生命便如此湮灭了。身边的朋友感叹生命的脆弱——那几位年轻小伙，从谈笑风生到匆匆离去，仅仅是几分钟的时间。世事难料，若知后果如此，他们必然不会去做这样的事情。当然，这都是后话，有些事情，当时的人又怎么会知道后果呢？]]></summary></entry><entry><title type="html">好事多磨</title><link href="https://pursuer.me/2012/03/29/%E5%A5%BD%E4%BA%8B%E5%A4%9A%E7%A3%A8/" rel="alternate" type="text/html" title="好事多磨" /><published>2012-03-29T12:39:00+00:00</published><updated>2012-03-29T12:39:00+00:00</updated><id>https://pursuer.me/2012/03/29/%E5%A5%BD%E4%BA%8B%E5%A4%9A%E7%A3%A8</id><content type="html" xml:base="https://pursuer.me/2012/03/29/%E5%A5%BD%E4%BA%8B%E5%A4%9A%E7%A3%A8/"><![CDATA[<p>近来事情颇多，各种事情弄得我焦头烂额。之前写了文章宣泄种种不满，表达自己深深的无奈。而反观自己，大多数事情的确是没有定型，未来充满了未知。未知对于我应该是好事，在一切尘埃落定时我往往会失去斗志，多年的经验反复应证着这一点。但未知也让我无从选择，在事情来临时无法防御，也就陷入了被动。这或许是那些不满的事情的起因吧。</p>

<p>不过，总是有一些好事的——一些之前做过的事情开始渐渐显现出它本身的逻辑。昨天睡觉前收到一条短信，是有关MCM的结果的。那是一个多月以前的比赛了，说实话，参加这个比赛我没有任何期望，参赛仅仅凭着自己对数学和计算机的喜爱。不过这个结果的确让我挺兴奋的——它或许说明不了什么，却是一种认可，况且这认可来自于一个更加公平、公正的团队。更多的是自信和成就感吧。</p>

<p>而一切才刚刚开始。各件事情齐头并进。昨天刚刚完成了EasyRSS的一个更新，近几天就会发布。我已经有近一个月没有碰这款应用了，用户的反馈已经积累到了我不得不对它做出调整的程度。应用新增了黑色的皮肤。之前对如何处理Android应用的皮肤不甚了解，这次积累了不少经验。</p>

<p>更多的精力将会花在点星上。多人协作做一件事，进度有快有慢，从想法到执行总有一定的落差。其间一些事情完成得很好，一些事情却让我感到深深的不满。但项目在向前推动。昨天上大有很多社团入驻了，我们又沿着自己的思路向前走了一步。虽不知在这个时间点做这件事是好是坏，不过我相信这会是下一件“好事”。让时间证明一切吧。</p>

<p>听着Westlife的歌《As love is my witness》，心中莫名地感动，也愈加觉得来路方长。好事多磨，事情会一件件地落地。未来应该留给未来。</p>]]></content><author><name></name></author><category term="思行" /><summary type="html"><![CDATA[近来事情颇多，各种事情弄得我焦头烂额。之前写了文章宣泄种种不满，表达自己深深的无奈。而反观自己，大多数事情的确是没有定型，未来充满了未知。未知对于我应该是好事，在一切尘埃落定时我往往会失去斗志，多年的经验反复应证着这一点。但未知也让我无从选择，在事情来临时无法防御，也就陷入了被动。这或许是那些不满的事情的起因吧。]]></summary></entry></feed>