<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>python Archives - ClickedyClick</title>
	<atom:link href="https://gergely.imreh.net/blog/tag/python/feed/" rel="self" type="application/rss+xml" />
	<link>https://gergely.imreh.net/blog/tag/python/</link>
	<description>Life in real, complex and digital.</description>
	<lastBuildDate>Thu, 30 Jan 2025 02:59:00 +0000</lastBuildDate>
	<language>en-GB</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	
	<item>
		<title>Adventures into Code Age with an LLM</title>
		<link>https://gergely.imreh.net/blog/2024/11/adventures-into-code-age-with-an-llm/</link>
					<comments>https://gergely.imreh.net/blog/2024/11/adventures-into-code-age-with-an-llm/#respond</comments>
		
		<dc:creator><![CDATA[Gergely Imreh]]></dc:creator>
		<pubDate>Sat, 09 Nov 2024 09:50:20 +0000</pubDate>
				<category><![CDATA[Computers]]></category>
		<category><![CDATA[Machine Learning]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Claude]]></category>
		<category><![CDATA[llm]]></category>
		<category><![CDATA[python]]></category>
		<guid isPermaLink="false">https://gergely.imreh.net/blog/?p=2910</guid>

					<description><![CDATA[<p>It&#8217;s a relaxed Saturday afternoon, and I just remembered some nerdy plots I&#8217;ve seen online for various projects, depicting &#8220;code age&#8221; over time: how does your repository change over the months and years, how much code still survives from the beginning till now, etc&#8230; Something like this made by the author of curl: It looks [&#8230;]</p>
<p>The post <a href="https://gergely.imreh.net/blog/2024/11/adventures-into-code-age-with-an-llm/">Adventures into Code Age with an LLM</a> appeared first on <a href="https://gergely.imreh.net/blog">ClickedyClick</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>It&#8217;s a relaxed Saturday afternoon, and I just remembered some nerdy plots I&#8217;ve seen online for various projects, depicting &#8220;code age&#8221; over time: how does your repository change over the months and years, how much code still survives from the beginning till now, etc&#8230; Something like <a href="https://daniel.haxx.se/blog/2024/10/31/curl-source-code-age/">this made by the author of curl</a>:</p>



<figure class="wp-block-image size-large is-style-default"><img fetchpriority="high" decoding="async" width="1024" height="644" src="https://gergely.imreh.net/blog/wp-content/uploads/2024/11/screenshot-2024-10-31-at-13-39-29-gnuplot-1024x644.png" alt="" class="wp-image-2914" srcset="https://gergely.imreh.net/blog/wp-content/uploads/2024/11/screenshot-2024-10-31-at-13-39-29-gnuplot-1024x644.png 1024w, https://gergely.imreh.net/blog/wp-content/uploads/2024/11/screenshot-2024-10-31-at-13-39-29-gnuplot-500x314.png 500w, https://gergely.imreh.net/blog/wp-content/uploads/2024/11/screenshot-2024-10-31-at-13-39-29-gnuplot-768x483.png 768w, https://gergely.imreh.net/blog/wp-content/uploads/2024/11/screenshot-2024-10-31-at-13-39-29-gnuplot-1536x966.png 1536w, https://gergely.imreh.net/blog/wp-content/uploads/2024/11/screenshot-2024-10-31-at-13-39-29-gnuplot-2048x1288.png 2048w, https://gergely.imreh.net/blog/wp-content/uploads/2024/11/screenshot-2024-10-31-at-13-39-29-gnuplot-1200x754.png 1200w, https://gergely.imreh.net/blog/wp-content/uploads/2024/11/screenshot-2024-10-31-at-13-39-29-gnuplot-1980x1245.png 1980w" sizes="(max-width: 1024px) 100vw, 1024px" /><figcaption class="wp-element-caption">Curl&#8217;s code age distribution</figcaption></figure>



<p>It looks interesting and informative. And even though I don&#8217;t have codebases that have been around this long, there are plenty of codebases around me that are fast moving, so something like a month (or in some cases week) level cohorts could be interesting.</p>



<p>One way to take this challenge on is to actually sit down and write the code. Another is to take a <a href="https://en.wikipedia.org/wiki/Large_language_model">Large Language Model</a>, say <a href="https://claude.ai/">Claude</a> and try to get that to make it. Of course the challenge is different in nature. For this case, let&#8217;s put myself in the shoes of someone who says</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>I am more interested in the results than the process, and want to get to the results quicker.</p>
</blockquote>



<p>See how far we can get with this attitude, and where does it break down (probably no spoiler: it breaks down very quickly.).</p>



<p>Note on the selection of the model: I&#8217;ve chosen Claude just because generally I have good experience with it these days, and it can share generated artefacts (like the relevant Python code) which is nice. And it&#8217;s a short afternoon. :) Otherwise anything else could work as well, though surely with varying results. </p>



<h3 class="wp-block-heading">Version 1</h3>



<p>Let&#8217;s kick it off with a quick prompt.</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p><strong>Prompt</strong>: How would you generate a chart from a git repository to show the age of the code? That is when the code was written and how much of it survives over time?</p>
</blockquote>



<p>Claude quickly picked it up and made me a Python script, which is nice (that being my day-to-day programming language). I guess that&#8217;s generally a good assumption these days if one does data analytics anyways (asking for another language is left for another experiment).</p>



<span id="more-2910"></span>



<p>The result is this <a href="https://claude.site/artifacts/d7c4b1f6-e6c4-4d74-82dd-97e0d40d0c5e">this code</a>. I&#8217;ve skimmed it that it doesn&#8217;t just delete all my repo or does something completely batshit, but otherwise saved in a repo that I have at hand. To make it easier on myself, added some <a href="https://packaging.python.org/en/latest/specifications/inline-script-metadata/#inline-script-metadata">inline metadata</a> with the dependencies:</p>



<pre class="wp-block-code"><code class=""># /// script
# dependencies = [
#   "pandas",
#   "matplotlib",
# ]
# ///</code></pre>



<p>and from there I can just run the script with <a href="https://docs.astral.sh/uv/">uv</a>.</p>



<p>First it checked too few files (my repository is a mixture of Python and SQL scripts managed by <a href="https://www.getdbt.com/">dbt</a>), so had to go in and change those filters, expanding them.</p>



<p>Then the thought struck me to remove the filter altogether (since it already checks only files that are checked in git, so it should be fine &#8211; but then it broke on a step where it reads a file as if it was text to find the line counts. I guess there could be a better way of filtering (say &#8220;do not read binary files&#8221;, if there&#8217;s a way to do that), but just went with catching the problems:</p>



<pre class="wp-block-code"><code class=""># ....
    for file_path in tracked_files:
        try:
            timestamps = get_file_blame_data(file_path)
            for timestamp in timestamps:
                blame_data[timestamp] += 1
                total_lines += 1
        except UnicodeDecodeError:
            print(f"Error reading file: {file_path}")
            continue
#....</code></pre>



<p>(hance I know that a favicon PNG was causting those <code>UnicodeDecodeError</code> hubbub in earlier runs. Now we are getting somewhere, and we have a graph like this:</p>



<figure class="wp-block-image size-large"><img decoding="async" width="1024" height="512" src="https://gergely.imreh.net/blog/wp-content/uploads/2024/11/code_age_distribution-1024x512.png" alt="" class="wp-image-2911" srcset="https://gergely.imreh.net/blog/wp-content/uploads/2024/11/code_age_distribution-1024x512.png 1024w, https://gergely.imreh.net/blog/wp-content/uploads/2024/11/code_age_distribution-500x250.png 500w, https://gergely.imreh.net/blog/wp-content/uploads/2024/11/code_age_distribution-768x384.png 768w, https://gergely.imreh.net/blog/wp-content/uploads/2024/11/code_age_distribution.png 1200w" sizes="(max-width: 1024px) 100vw, 1024px" /><figcaption class="wp-element-caption">Version 1</figcaption></figure>



<p>This is already quite fun to see. There are the sudden accelerations of development, there are the plateaus of me working on other projects, and generally feel like &#8220;wow, productive!&#8221; (with no facts backing that feeling <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f602.png" alt="😂" class="wp-smiley" style="height: 1em; max-height: 1em;" />). Also pretty good ROI on maybe 15 mins of effort.</p>



<p>Having said that, this is still fair from what I wanted.</p>



<h3 class="wp-block-heading">Version 2</h3>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p><strong>Promt:</strong> Could we change the code to have cohorts of time, that is configurable, say monthly, or yearly cohoorts, and colour the chart to see how long each cohort survives?</p>
</blockquote>



<p>This came back with another <a href="https://claude.site/artifacts/34b65023-9ba4-4abb-b214-1c10d82eacfd">set of code</a>. Adding the metadata, skimming it (it has the filter on the file extensions again, never mind), and running it once more to see the output, I get this:</p>



<figure class="wp-block-image size-large"><img decoding="async" width="1024" height="542" src="https://gergely.imreh.net/blog/wp-content/uploads/2024/11/code_survival_monthly-1024x542.png" alt="" class="wp-image-2912" srcset="https://gergely.imreh.net/blog/wp-content/uploads/2024/11/code_survival_monthly-1024x542.png 1024w, https://gergely.imreh.net/blog/wp-content/uploads/2024/11/code_survival_monthly-500x265.png 500w, https://gergely.imreh.net/blog/wp-content/uploads/2024/11/code_survival_monthly-768x406.png 768w, https://gergely.imreh.net/blog/wp-content/uploads/2024/11/code_survival_monthly-1536x813.png 1536w, https://gergely.imreh.net/blog/wp-content/uploads/2024/11/code_survival_monthly-2048x1083.png 2048w, https://gergely.imreh.net/blog/wp-content/uploads/2024/11/code_survival_monthly-1200x635.png 1200w, https://gergely.imreh.net/blog/wp-content/uploads/2024/11/code_survival_monthly-1980x1048.png 1980w" sizes="(max-width: 1024px) 100vw, 1024px" /><figcaption class="wp-element-caption">Version 2</figcaption></figure>



<p>Because of the file extension filter in place, the numbers are obviously not aligning with the above, but it does something. The something is a bit unclear, bit it <em>feels</em> like progress, so let&#8217;s give it a benefit of the doubt, and just change once more. </p>



<h3 class="wp-block-heading">Version 3</h3>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p><strong>Promt:</strong> Now change this into a cummulative graph, please.</p>
</blockquote>



<p>One more time Claude came back with <a href="https://claude.site/artifacts/a391c5dc-743c-439f-aa09-70ec9b86a19a">this code</a>. Adding the metadata again, same drill. Running this has failed with errors in <code>numpy</code>, though:</p>



<pre class="wp-block-code"><code class="">TypeError: ufunc 'isfinite' not supported for the input types, and the inputs could not be safely coerced to any supported types according to the casting rule ''safe''</code></pre>



<p>Now this needed some debugging. It turns out a column the code is trying to plot is actually numbers as strings rather than numbers as, you know, say floats&#8230;</p>



<pre class="wp-block-code"><code class=""># my "fix"
        df['cumulative_percentage'] = df['cumulative_percentage'].astype(float)
# end

        # Plot cumulative area
        plt.fill_between(df.index, df['cumulative_percentage'],
                        alpha=0.6, color='royalblue',
                        label='Cumulative Code')</code></pre>



<p>It didn&#8217;t take too many tries, but it was confusing at first &#8211; why shouldn&#8217;t be, if I didn&#8217;t actually <em>read</em> just skim the code&#8230;</p>



<p>The result is then like this:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="543" src="https://gergely.imreh.net/blog/wp-content/uploads/2024/11/code_growth_monthly-1024x543.png" alt="" class="wp-image-2913" srcset="https://gergely.imreh.net/blog/wp-content/uploads/2024/11/code_growth_monthly-1024x543.png 1024w, https://gergely.imreh.net/blog/wp-content/uploads/2024/11/code_growth_monthly-500x265.png 500w, https://gergely.imreh.net/blog/wp-content/uploads/2024/11/code_growth_monthly-768x407.png 768w, https://gergely.imreh.net/blog/wp-content/uploads/2024/11/code_growth_monthly-1536x814.png 1536w, https://gergely.imreh.net/blog/wp-content/uploads/2024/11/code_growth_monthly-2048x1085.png 2048w, https://gergely.imreh.net/blog/wp-content/uploads/2024/11/code_growth_monthly-1200x636.png 1200w, https://gergely.imreh.net/blog/wp-content/uploads/2024/11/code_growth_monthly-1980x1049.png 1980w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /><figcaption class="wp-element-caption">Version 3</figcaption></figure>



<p>Sort of <em>meh</em>, it feels like it&#8217;s not going to the right direction overall.</p>



<p>But while debugging the above issues, I first tried tried to ask Claude about the error (maybe it can fix it itself), but came back with &#8220;Your message exceeds the <a href="https://support.anthropic.com/en/articles/7996848-how-large-is-claude-s-context-window">length limit</a>. &#8230;&#8221; (for free users, that is). So I kinda stopped here for the time being.</p>



<h2 class="wp-block-heading">Lessons learned</h2>



<p>The first lesson is very much re-learned:</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>Garbage in, garbage out.</p>
</blockquote>



<p>If I cannot express what I really want, it&#8217;s very difficult to make it happen. And my prompts were by no means expressing my wishes correctly, no wonder Claude wasn&#8217;t really hitting the mark. Whether or not a human engineer would have faired better, I don&#8217;t know. I know however, that this kind of &#8220;tell me exceedingly clearly what&#8217;s your idea&#8221; is an everyday conversation for me as an engineer (and being on both end of the convo).</p>



<p>The code provided by the model wasn&#8217;t really far off for <em>some</em> solution, so that was fun! On the other hand, when it hit any issues, I really had to have domain and language knowledge to fix things. This seems like an interesting place to be:</p>



<ul class="wp-block-list">
<li>the results are quick and on the surface good-enough for a non/less technical person, probably</li>



<li>but they would also be the ones who couldn&#8217;t do anything if something goes wrong.</li>
</ul>



<p>Even myself I feel that it would be hard to support the code as a software engineer if it was just generated like this. But that&#8217;s also a strange thought: so many times I have to support (debug, extend, explain, refactor) code that I haven&#8217;t had anything to do with before.</p>



<p>It seems to me that now that since Claude comes across as an eager junior engineer, writing decent code that always needs some adjustments, the trade-off is really in the dimension of spending time to get better at prompting vs better at coding. </p>



<p>If there&#8217;s a person with some amount of programming skills, mostly interested in the results not the process, and doubling down on prompting: they likely could get loads further than I did here. Good quality prompts and small amount of code adjustments being the sweet spot for them.</p>



<p>For others who have more programming expertise, and maybe more interested in the process, spending time on getting better at programming rather than getting really better at prompting: keeping to smaller snippets might be the sweet spot, or learning new languages, &#8230; Something as a starting point for digging in, a seed, is what this process can help with.</p>



<h2 class="wp-block-heading">Future</h2>



<p>Given the above notes on how this generated code is like a new codebase that I suddenly neet to support, here&#8217;s a different, fun exercise <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" /> to actually improve engineering skills:</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>Take AI generated code that is &#8220;good enough&#8221; for a small problem and refactor, extent, productionise it.</p>
</blockquote>



<p>I&#8217;m not sure if this would work, or would get me into wrong habits, but if I wanted do have some quick ways of doing <a href="https://en.wikipedia.org/wiki/Peak:_Secrets_from_the_New_Science_of_Expertise">deliberate practice</a> &#8211; and not <a href="https://exercism.org/">Exercism</a>, <a href="https://gergely.imreh.net/blog/2023/08/doing-the-easy-problems-on-leetcode/">LeetCode</a>, or somilar, rather something that can be custom made, then this seems a way to get started.</p>



<p>Also, now that I&#8217;ve gotten even more interested in the problem, I&#8217;ll likely just dig into how to actually define that chart I was looking for and what kind of data I would need to get from <code>git</code> to make it happen. The example code made me pretty confident, that &#8220;all I need is Python&#8221; really, even though while prepping for this I found other useful tools like <a href="https://github.com/mergestat/mergestat-lite">one allowing you to write SQL queries for your repo</a>, that might be some further way to expand my understanding.</p>



<p>Either way, it&#8217;s just fun to mess with code on a lazy Saturday.</p>
<p>The post <a href="https://gergely.imreh.net/blog/2024/11/adventures-into-code-age-with-an-llm/">Adventures into Code Age with an LLM</a> appeared first on <a href="https://gergely.imreh.net/blog">ClickedyClick</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://gergely.imreh.net/blog/2024/11/adventures-into-code-age-with-an-llm/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Programming challenge: Protohackers 3</title>
		<link>https://gergely.imreh.net/blog/2022/09/programming-challenge-protohackers-3/</link>
					<comments>https://gergely.imreh.net/blog/2022/09/programming-challenge-protohackers-3/#respond</comments>
		
		<dc:creator><![CDATA[Gergely Imreh]]></dc:creator>
		<pubDate>Sat, 24 Sep 2022 09:33:28 +0000</pubDate>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[protohackers]]></category>
		<category><![CDATA[python]]></category>
		<guid isPermaLink="false">https://gergely.imreh.net/blog/?p=2720</guid>

					<description><![CDATA[<p>Incursion into server programming with Python and failing in a productive way.</p>
<p>The post <a href="https://gergely.imreh.net/blog/2022/09/programming-challenge-protohackers-3/">Programming challenge: Protohackers 3</a> appeared first on <a href="https://gergely.imreh.net/blog">ClickedyClick</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p><a href="https://protohackers.com/">Protohackers</a> is a server programming challenge, where various network protocols are set as a problem. It has started not so long ago, and <a href="https://protohackers.com/problem/3">the No 3. challenge</a> was just released yesterday, aiming at creating a simple (&#8220;Budget&#8221;) multi-user chat server. I thought I <s>sacrifice a decent part of my weekend</s> give it a honest try. This is the short story of trying, failing, then getting more knowledge out than I&#8217;ve expected.</p>



<p>Definitely wanted to tackle it using Python as that&#8217;s my current utility language that I want to know most about. Since the aim of Protohackers, I think, is to go from scratch, I set to use only the standard library. With some poking around documentation I ended up choosing <a href="https://docs.python.org/3/library/socketserver.html#module-socketserver">SocketServer</a> as the basis of the work. It seemed suitable, but there was a severe dearth of non-dummy code and deeper explanation. In a couple of hours I did make some progress, though, that already felt exciting:</p>



<ul class="wp-block-list"><li>Figured out (to some extent) the purpose of the server / handler parts in practice</li><li>Made things multi-user with data shared across connections</li><li>Grokked a bit the lifecycle of the requests, but definitely not fully, especially not how disconnections happen.</li></ul>



<p>Still it was working to some extent, I <em>could</em> make a server that functioned for a certain definition of &#8220;functioned&#8221;, as the logs attest:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="232" src="https://gergely.imreh.net/blog/wp-content/uploads/2022/09/budget-chat-server-logs-1024x232.png" alt="Console log of server messages while trying my Budget Chat Server implementation." class="wp-image-2724" srcset="https://gergely.imreh.net/blog/wp-content/uploads/2022/09/budget-chat-server-logs-1024x232.png 1024w, https://gergely.imreh.net/blog/wp-content/uploads/2022/09/budget-chat-server-logs-500x113.png 500w, https://gergely.imreh.net/blog/wp-content/uploads/2022/09/budget-chat-server-logs-768x174.png 768w, https://gergely.imreh.net/blog/wp-content/uploads/2022/09/budget-chat-server-logs-1200x272.png 1200w, https://gergely.imreh.net/blog/wp-content/uploads/2022/09/budget-chat-server-logs.png 1386w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /><figcaption>Server logs from trying my Budget Chat Server</figcaption></figure>



<span id="more-2720"></span>



<p>On the other hand, ended up in a relative dead-end, as some message ordering issues kicked in, and reliably failed the test here, not knowing much what to try next just yet:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="836" src="https://gergely.imreh.net/blog/wp-content/uploads/2022/09/protohackers-3-failure-1024x836.png" alt="" class="wp-image-2721" srcset="https://gergely.imreh.net/blog/wp-content/uploads/2022/09/protohackers-3-failure-1024x836.png 1024w, https://gergely.imreh.net/blog/wp-content/uploads/2022/09/protohackers-3-failure-500x408.png 500w, https://gergely.imreh.net/blog/wp-content/uploads/2022/09/protohackers-3-failure-768x627.png 768w, https://gergely.imreh.net/blog/wp-content/uploads/2022/09/protohackers-3-failure-1536x1254.png 1536w, https://gergely.imreh.net/blog/wp-content/uploads/2022/09/protohackers-3-failure-1200x980.png 1200w, https://gergely.imreh.net/blog/wp-content/uploads/2022/09/protohackers-3-failure.png 1568w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /><figcaption>Testing my in-progress solution, and failing.</figcaption></figure>



<p>Since it&#8217;s a learning exercise and definitely not a competition on my part, I started to procrastinate. Not long before I&#8217;ve looked at the status of the <a href="https://protohackers.com/leaderboard">leaderboard</a>. Funnily enough, looking at the top entries, they were linking to the repositories where their solutions were! <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>



<h2 class="wp-block-heading">Shoulders of Giants</h2>



<p>Here&#8217;s my surprise and delight started, though. Within the first 7 entries there were 3 with Python implementations that included code! Even better, they actually covered 3 completely different ways of solving the task. Jackpot, really!</p>



<ol class="wp-block-list"><li>The <a href="https://github.com/pyxyne/protohackers/blob/9c4b26ecf0b274755856d5e1e3104bfa774a12f9/p3_chat.py">first solution</a> used pure <a href="https://docs.python.org/3/library/socket.html">sockets</a>, which is quite versatile if I&#8217;d want to go all-in on low-level networking in the future. It had quite a lot of helper code, though which makes it look like a pretty decent effort to duplicate.</li><li>The <a href="https://github.com/simon816/Protohackers-solutions/blob/f10c0f606a3688e7486d70a4914cd22e4d781e07/3/server.py">second solution</a> went with <a href="https://docs.python.org/3/library/socketserver.html">SocketServer</a> just like I&#8217;ve tried, and that is nice to dig in a bit more, given how small the whole code is. The main thing here was that I should have understood from the problem description this being a <a href="https://docs.python.org/3/library/socketserver.html#socketserver.StreamRequestHandler">Streaming</a> TCP connection case. Looks like streaming is the part that takes care of a lot of details, including the connection/disconnection that plagued me. Bam!</li><li>The <a href="https://github.com/LiraNuna/protohackers/blob/566b90aa7e17929f7d87a4fa9468cdb332bdf4ce/3%20-%20budget-chat/budget-chat.py">third solution</a> then used <a href="https://docs.python.org/3/library/asyncio.html?highlight=asyncio">asyncio</a>, to take it in a different direction again. It&#8217;s amazing how simple it all is when the relevant components and abstractions are understood.</li></ol>



<p>Which one is the most tempting solution to follow (and/or learn from)? Pure sockets are likely just a fallback option when there&#8217;s nothing else. On the SocketServer vs asyncio front however there was some useful <a href="https://stackoverflow.com/a/40177631">StackOverflow</a> discussion, even if a bit dated, coming from 2016. It pointed at the different use of threading and event loops. I guess this would make this answer a bit unsatisfying, but quite realistic: <em>learn both and know when either is applicable for your use case</em>. </p>



<h2 class="wp-block-heading">What did we learn?</h2>



<p>In the end I haven&#8217;t finished my code yet. Reading the existing solutions influences me and just adapting what others did and submit would feel like cheating (to myself). The way to resolve this is setting your own goals on top of the original challenge. Here I picked the following, and achieving these would complete things for me:</p>



<ul class="wp-block-list"><li>Use proper project structure and try out <a href="https://pdm.fming.dev/latest/">PDM</a></li><li>Figure out how to set up the project &amp; code to be testable with <a href="https://docs.pytest.org/en/7.1.x/">pytest</a> (basically grok testing of programs that run servers)</li></ul>



<p>The combination of these focuses on something akin to &#8220;going to production&#8221;, besides obviously writing the actual code, which is very much relevant to my interests.</p>



<p>So far I haven&#8217;t seen many examples of testing SocketServer, though <a href="https://github.com/python/cpython/blob/c5b750dc0b4d4e58047c9d93c635fa26b06562f7/Lib/test/test_socketserver.py">there&#8217;s Python&#8217;s own test suit</a> that could be a starting place. It has a lot of super useful helper functions (such as finding an unused port to run the server on), but overall seems a lot of boilerplate too. For asyncio I haven&#8217;t looked around yet. It being &#8220;cooler&#8221; there might be more discussion around it, but it&#8217;s by no means a given. Would be interesting to combine this with a Basic Chat client as well.</p>



<p>Another impression from today&#8217;s effort is that Python modules are documented to very varying levels. Their complexity definitely jumps when I try to go from dummy stuff to anything useful. For example here understanding the proper role and interaction of the Server and Handler parts of this multi-user environment.</p>



<p>I&#8217;m also acutely aware that my networking knowledge is very patchy regardless of doing networking-adjacent stuff for decades. It&#8217;s a very useful frontier to tackle when I have a chance.</p>



<p>Finally, <a href="https://ngrok.com/">ngrok</a> is still very cool tool, nice to be able to sit in a cafe and safely exposing a server to the internet.</p>
<p>The post <a href="https://gergely.imreh.net/blog/2022/09/programming-challenge-protohackers-3/">Programming challenge: Protohackers 3</a> appeared first on <a href="https://gergely.imreh.net/blog">ClickedyClick</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://gergely.imreh.net/blog/2022/09/programming-challenge-protohackers-3/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Creating a Prometheus metrics exporter for a 4G router</title>
		<link>https://gergely.imreh.net/blog/2022/06/creating-a-prometheus-metrics-exporter-for-a-4g-router/</link>
					<comments>https://gergely.imreh.net/blog/2022/06/creating-a-prometheus-metrics-exporter-for-a-4g-router/#respond</comments>
		
		<dc:creator><![CDATA[Gergely Imreh]]></dc:creator>
		<pubDate>Tue, 14 Jun 2022 03:25:24 +0000</pubDate>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[grafana]]></category>
		<category><![CDATA[prometheus]]></category>
		<category><![CDATA[python]]></category>
		<guid isPermaLink="false">https://gergely.imreh.net/blog/?p=2628</guid>

					<description><![CDATA[<p>Debugging 4G router network connectivity issues by scraping its metrics and making some pretty graphs. Experimenting with loads of new tech that I didn't get to use in anger before.</p>
<p>The post <a href="https://gergely.imreh.net/blog/2022/06/creating-a-prometheus-metrics-exporter-for-a-4g-router/">Creating a Prometheus metrics exporter for a 4G router</a> appeared first on <a href="https://gergely.imreh.net/blog">ClickedyClick</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Recently I begun fully remote working from home, with the main network connectivity provided by a 4G mobile router. Very soon I experienced patchy connectivity, not the greatest thing when you are on video calls for half of each day. What does one do then (if not just straight replacing the whole setup with a wired ISP, if possible), other than monitor what&#8217;s going on and try to debug the issues?</p>



<p>The router I have is a less-common variety, an Alcatel Linkhub HH441 (can&#8217;t even properly link to on the manufacturer&#8217;s site, just on online retail stores). At least as it should, it does have a web front-end, that one can poke around in, and gather metrics from &#8211; of course in an automatic way.</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="800" height="553" src="https://gergely.imreh.net/blog/wp-content/uploads/2022/05/linkhub_product.jpg" alt="" class="wp-image-2629" srcset="https://gergely.imreh.net/blog/wp-content/uploads/2022/05/linkhub_product.jpg 800w, https://gergely.imreh.net/blog/wp-content/uploads/2022/05/linkhub_product-500x346.jpg 500w, https://gergely.imreh.net/blog/wp-content/uploads/2022/05/linkhub_product-768x531.jpg 768w" sizes="auto, (max-width: 800px) 100vw, 800px" /><figcaption>The Alcatel HH41 LinkHub router that I had at hand to use</figcaption></figure>



<p>Looking at the router&#8217;s web interface, and checking the network activity through the browsers&#8217; network monitor (<a href="https://firefox-source-docs.mozilla.org/devtools-user/index.html#network-monitor">Firefox</a>, <a href="https://developer.chrome.com/docs/devtools/network/">Chrome</a>), the frontend&#8217;s API calls showed up, so I could collect a few that requested different things like radio receiving metrics, bandwidth usage, uptime, and so on&#8230; From here we are off to the races setting up our monitoring infrastructure, along these pretty standard lines:</p>



<ul class="wp-block-list"><li>Set up a <a href="https://prometheus.io/docs/instrumenting/exporters/">Prometheus metrics exporter</a>, pulling data from the router&#8217;s internal API (the same way the web interface does it)</li><li>Spin up a <a href="https://prometheus.io/">Prometheus</a> + <a href="https://grafana.com/">Grafana</a> interface to actually monitor, alert on, and debug any metrics</li></ul>



<span id="more-2628"></span>



<h2 class="wp-block-heading">Metrics Exporter</h2>



<p>Given that I&#8217;m mostly working with Python, using the existing <a href="https://github.com/prometheus/client_python">Prometheus Python client</a> was an easy choice, in particular using their internal <a href="https://github.com/prometheus/client_python#http">HTTP exporter</a> to get started quickly. It was relatively straightforward to turn many of the metrics into various <a href="https://prometheus.io/docs/concepts/metric_types/#gauge">gauges</a> (radio reception metrics, bandwidth used, &amp;c.), though some were naturally <a href="https://github.com/prometheus/client_python#info">info fields</a>, such as mobile network name and cell ID. This latter would be very useful as my hunch was cell hopping by the router is what&#8217;s mainly affecting my network quality.</p>



<p>After some poking around I&#8217;ve also realised, that the API exposed is just <a href="https://www.jsonrpc.org/">JSON-RPC</a> (although the router&#8217;s backend doesn&#8217;t seem implement everything in there, e.g. there&#8217;s no <a href="https://www.jsonrpc.org/specification#batch">batch</a>), which made a lot of things clearer, and potentially easier to use.</p>



<p>In the end, I&#8217;ve ended up with one class to do all the metrics gathering from a couple of JSON-RPC methods, working relatively robustly. The authentication was simplified very much: most need an auth token that can be extracted by manually observing some requests (more on this later) and some need a <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referer">referrer header</a> for the request to pretend to be coming from the admin console.</p>



<p>The resulting code is on GitHub: <a href="https://github.com/imrehg/linkhub_prometheus_exporter">imrehg / linkhub_prometheus_exporter</a>, and should be a full-featured server with most (though probably not all) the metrics available in the admin console as well.</p>



<h2 class="wp-block-heading">Monitoring</h2>



<p>With the metrics exporter running, I used a <a href="https://docs.docker.com/compose/">Docker Compose</a>-based <a href="https://github.com/vegasbrianc/prometheus">Prometheus + Grafana stack</a> locally to have everything together, just adding an extra &#8220;linkhub&#8221; task in Prometheus to pull the data periodically, and a new dashboard in Grafana to have a quick overview.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="602" src="https://gergely.imreh.net/blog/wp-content/uploads/2022/05/grafana_screenshot1-1024x602.png" alt="Grafana view of some of the reception metrics" class="wp-image-2630" srcset="https://gergely.imreh.net/blog/wp-content/uploads/2022/05/grafana_screenshot1-1024x602.png 1024w, https://gergely.imreh.net/blog/wp-content/uploads/2022/05/grafana_screenshot1-500x294.png 500w, https://gergely.imreh.net/blog/wp-content/uploads/2022/05/grafana_screenshot1-768x451.png 768w, https://gergely.imreh.net/blog/wp-content/uploads/2022/05/grafana_screenshot1-1536x902.png 1536w, https://gergely.imreh.net/blog/wp-content/uploads/2022/05/grafana_screenshot1-2048x1203.png 2048w, https://gergely.imreh.net/blog/wp-content/uploads/2022/05/grafana_screenshot1-1200x705.png 1200w, https://gergely.imreh.net/blog/wp-content/uploads/2022/05/grafana_screenshot1-1980x1163.png 1980w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /><figcaption>Grafana view of some of the reception metrics</figcaption></figure>



<p>I also went a bit overboard and added some extra bits and pieces, like coloured regions for the signal metrics to show what&#8217;s bad / acceptable / good / excellent or so, based on <a href="https://www.digi.com/support/knowledge-base/understanding-lte-signal-strength-values">some scouting</a>, making it clearer when things are good or not good.</p>



<p>I also tried to use a bit more of Grafana&#8217;s tooling (not a lot, but a bit more), so added some different sections for signal quality and network metrics, as well as a running average on some of the noisy metrics. </p>



<h2 class="wp-block-heading">Lessons learned</h2>



<p>Learned a bunch of things as this was the first time I used, from scratch, many of the tools here. The very first one being: how to choose the right Prometheus metrics for various data streams? Now I see how does it look like in practice, planning for a metric that needs to be monitored from the very early stage. There are fewer varieties of metrics that I&#8217;ve expected, and while there&#8217;s a lot of derivative stuff to make it a lot more useful, it&#8217;s not that everything that one imagines can be made to work.</p>



<p>Used Poetry here  more than previously, and set up <a href="https://github.com/mtkennerly/poetry-dynamic-versioning">poetry-dynamic-versioning plugin</a> (as a candidate competitor to <a href="https://github.com/pypa/setuptools_scm">setuptools-scm</a>). That meant also using poetry plugins and a beta Poetry release at this stage. It’s not bad, but sooo many gotchas in the process, and still have to figure out what would be a good reusable template for projects using these. (including __version__ variables, etc).</p>



<p>Figured out how to do good CI Docker image builds with libraries that rely on git for versioning, fortunately <a href="https://github.com/pypa/setuptools_scm#usage-from-docker">setuptools_scm did the work for us</a>: bind mount of .git in the specific build step. I think in CI/CD all this reliance of repo data being available can still make things a bit trickier, but something&#8217;s gotta give, and it&#8217;s not much extra compared to the rest of the things.</p>



<p>Learned a bit about JSON-RPC (and how the router might or might not be fully compliant). Not sure if I&#8217;d go with that for any future project myself, but good to be aware of it, and potentially looking at its presence in other routers or interfaces&#8217; communications channels.</p>



<p>Chance to use some Python 3.10-based features (match) and hit/fix some of <a href="https://github.com/actions/setup-python/issues/160">GitHub actions related issues with 3.10</a>:way to go libraries that convert 3.10 to “3.1&#8243; because it’s a number so let’s round it, right? Or actually way to go libraries/YAML to allow both &#8216;x.y&#8217; and x.y forms (quoted and unquoted), and the former would have been the correct form all the time, but people generally go with the latter to save a few keypresses. It&#8217;s subtle, but experience is expecting the subtleties and the reasons for them arising.</p>



<p>Seen how <a href="http://mypy-lang.org/">mypy</a> can actually benefit the coda quality: while trying to fix all the reported issues actually found stuff that was clear benefit and it’s coming not from adding all the type hints (that’s good, but baseline), rather than being smart where it complains and think about what’s the underlying issue (e.g. patterns of getting values out of dicts where there might not be result, exhaustive matching of match and return values of functions, etc…)</p>



<p>The resulting Docker image is north of 1GB due to Python, and that&#8217;s not great considering that it doesn&#8217;t do <em>that much</em> work. Writing/rewriting this whole thing in Go could be interesting and would be useful learning experience (or another compiled language, I guess, but Prometheus itself is written in Go, so there&#8217;s a connection). One step at a time, projects written in Python are useful proof-of-concept to compare other stuff against later, so it was well.</p>



<p>Having said that, I&#8217;ve seen the best practices listed <a href="https://prometheus.io/docs/instrumenting/writing_exporters/">when writing Prometheus exporters</a>, and given the current environment, I couldn&#8217;t apply all the best practices. <a href="https://prometheus.io/docs/instrumenting/writing_exporters/#scheduling">For example</a>: &#8220;Metrics should only be pulled from the application when Prometheus scrapes them, exporters should not perform scrapes based on their own timers.&#8221; The official Prometheus Python Exporter on the other hand seems to need to use exactly that sort of &#8220;while True&#8221; loop to keep getting/storing metrics, instead if running on demand. There might be a more subtle pattern to do on-demand work (which I see to be more correct), but I need to find it.</p>



<p>So what have I learned about the actual network issues? Most of the instability seemed to be correlated with switching to specific cell towers (based on cell IDs). Certain cell towers would pretty stable, and on some of the days the router was switching between towers, and that&#8217;s when most of my online calls were pretty futile.</p>



<p>Finally, I did think a lot about the adage that &#8220;something that isn&#8217;t worth doing isn&#8217;t worth doing well.&#8221; On the other hand there&#8217;s no kill like overkill, so here we are&#8230;</p>



<h2 class="wp-block-heading">Future development</h2>



<p>Compared to other projects I&#8217;ve done, this might be lighter maintenance, given that it&#8217;s sorta done for the moment (except if others start to use it and need other metrics, for example). Otherwise the Docker-based deployment and poetry.lock&#8217;d dependencies make bit-rot a bit slower, hopefully. In the meantime, I&#8217;ve switched to a wired connection, so unlikely to need this project much, but it could be that much of this will be repurposed for other monitoring projects.</p>
<p>The post <a href="https://gergely.imreh.net/blog/2022/06/creating-a-prometheus-metrics-exporter-for-a-4g-router/">Creating a Prometheus metrics exporter for a 4G router</a> appeared first on <a href="https://gergely.imreh.net/blog">ClickedyClick</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://gergely.imreh.net/blog/2022/06/creating-a-prometheus-metrics-exporter-for-a-4g-router/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Taiwan WWII Map Overlays</title>
		<link>https://gergely.imreh.net/blog/2015/11/taiwan-wwii-map-overlays/</link>
					<comments>https://gergely.imreh.net/blog/2015/11/taiwan-wwii-map-overlays/#comments</comments>
		
		<dc:creator><![CDATA[Gergely Imreh]]></dc:creator>
		<pubDate>Mon, 02 Nov 2015 13:47:43 +0000</pubDate>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Taiwan]]></category>
		<category><![CDATA[Google Maps]]></category>
		<category><![CDATA[history]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[maps]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[WWII]]></category>
		<guid isPermaLink="false">https://gergely.imreh.net/blog/?p=2102</guid>

					<description><![CDATA[<p>A while ago I came across the Formosa (Taiwan) City Plans, U.S. Army Map Service, 1944-1945 collection, in the Perry-Castañeda Library Map Collection of the University of Texas in Austin. I&#8217;m a sucker for maps, enjoy learning about history a lot, and I have a lot of interest in my current home, Taiwan &#8211; so you can call this a [&#8230;]</p>
<p>The post <a href="https://gergely.imreh.net/blog/2015/11/taiwan-wwii-map-overlays/">Taiwan WWII Map Overlays</a> appeared first on <a href="https://gergely.imreh.net/blog">ClickedyClick</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>A while ago I came across the <a href="https://www.lib.utexas.edu/maps/ams/formosa_city_plans/">Formosa (Taiwan) City Plans, U.S. Army Map Service, 1944-1945 collection</a>, in the <a href="https://www.lib.utexas.edu/maps/">Perry-Castañeda Library Map Collection</a> of the University of Texas in Austin. I&#8217;m a sucker for maps, enjoy learning about history a lot, and I have a lot of interest in my current home, Taiwan &#8211; so you can call this a magic mix of cool stuff.</p>
<p>There are 26 maps in the collection, made by the US Army by flying over different parts of the island, and mostly I guess stitching together aerial photographs. The maps themselves were not that easy check in an image viewer, since there&#8217;s no context, zoom is clumsy, and have no idea where about half the places should be located. Instead, I thought it would be great to have them as an overlay on top of current maps and satellite imagery on Google Maps.</p>
<p>The result is <a href="https://imrehg.github.io/taiwanmap/">Taiwan City Maps overlays</a>, which does exactly that. <em>Feel free to click the link and explore right now!</em> In the rest of this post, I try to first show how that page was made, and also some history lessons I gained by making it.</p>
<p><span id="more-2102"></span></p>
<h2>How it was made</h2>
<p>The <a href="https://developers.google.com/maps/documentation/javascript/examples/groundoverlay-simple">Google Maps Ground Overlay API</a> does exactly what I needed, so can&#8217;t claim much (almost any) innovation in the page, though I stumbled on it after a few other &#8220;Overlays&#8221;, as Google Maps has a couple, all working slightly differently.</p>
<p>Ground Overlay basically takes the following parameters:</p>
<ul>
<li>the map&#8217;s center,</li>
<li>zoom level,</li>
<li>an image,</li>
<li>the image&#8217;s N/E/W/S bounds in geographical coordinates.</li>
<li>whether to show satellite or maps view underneath</li>
</ul>
<p>Even cooler, the opacity of the image can be adjusted, so the overlay and the base layer can be viewed together much easier!</p>
<p>In that list above, the trickiest part is of course figuring out the boundaries of the image &#8211; basically the way to overlay them &#8211; for multiple reasons. First, all the maps have borders with information, titles, legend, and so on. Here below is the Taipei city plan from 1944. I can&#8217;t really tell where the corner of the image should be geographically, if there&#8217;s nothing to compare to.</p>
<p><figure id="attachment_2109" aria-describedby="caption-attachment-2109" style="width: 600px" class="wp-caption aligncenter"><a href="https://imrehg.github.io/taiwanmap/maps/txu-oclc-6565483.jpg"><img loading="lazy" decoding="async" class="wp-image-2109 size-full" src="https://gergely.imreh.net/blog/wp-content/uploads/2015/11/Taipei_Small-min.jpg" alt="Taipei / Taihoku city plan" width="600" height="490" srcset="https://gergely.imreh.net/blog/wp-content/uploads/2015/11/Taipei_Small-min.jpg 600w, https://gergely.imreh.net/blog/wp-content/uploads/2015/11/Taipei_Small-min-500x408.jpg 500w" sizes="auto, (max-width: 600px) 100vw, 600px" /></a><figcaption id="caption-attachment-2109" class="wp-caption-text">Taipei / Taihoku city plan</figcaption></figure></p>
<p>Then there&#8217;s also the problem of things have changed in the last ~70 years, so a lot of things are different on the maps, if I want to match them up. Lastly, the maps are not perfectly accurate either, they are stitched from multiple photographs of unknown quality.</p>
<p>Been trying to match the maps by hand for a while, and codings some tools to make that process easier &#8211; but it didn&#8217;t really get easier. I needed to get to get around all these issues, and have a reasonable, objectively good fit. Objectivity is a key, and math helps with that. What I ended up with doing a linear fit of geographical and image coordinates.</p>
<ul>
<li>look for landmarks that are reasonably the same back then and now</li>
<li>note their geographical coordinates, and their pixel coordinates on the image</li>
<li>note the image size</li>
<li>finally: run a linear fit that gives back the geographical coordinates of the image edges that would best match the landmark data in both sources</li>
</ul>
<p>In really ugly Python it would be something like this:</p>
<pre class="lang:python">import numpy as np

# # For example the contents of "taoyuanfit.csv":
# # Landmark data: image vertical/horizontal (px), latitude/longitude
# 1677,2861,24.991962,121.322634
# 1597,524,24.992282,121.304856
# 2385,1348,24.986873,121.311122
# 764,1342,24.998116,121.311411
datafile = "taoyuanfit.csv"
points = np.loadtxt(datafile, delimiter=",", comments="#")
imgwidth, imgheight = 3975, 3209

# Points on the image, scaled to range 0 to 1
px, py = points[:, 1]/imgwidth, (imgheight-points[:, 0])/imgheight
# Points on the map
gx, gy = points[:, 3], points[:, 2]
# Do the fitting
lx, ly = np.polyfit(px, gx, 1), np.polyfit(py, gy, 1)

# Fitting parameters give map boundaries, results in this case
west = lx[1]          # 121.300983
east = lx[1] + lx[0]  # 121.331141
north = ly[1]+ly[0]   #  25.003429
south = ly[1]         #  24.981204
</pre>
<p>This is now pretty objective, and then quality of the overlay depends on the quality of the landmarks I find, and the maps that they are on.</p>
<p>The best landmarks I could turn up were notable roundabouts like below&#8230;</p>
<p><figure id="attachment_2103" aria-describedby="caption-attachment-2103" style="width: 600px" class="wp-caption aligncenter"><a href="https://imrehg.github.io/taiwanmap/taiwanmap.html?location=Tainan#lat=22.992571&amp;lng=120.205386&amp;z=17"><img loading="lazy" decoding="async" class="wp-image-2103 size-full" src="https://gergely.imreh.net/blog/wp-content/uploads/2015/11/map_roundabout.gif" alt="Matching roundabouts (Tainan)" width="600" height="400" /></a><figcaption id="caption-attachment-2103" class="wp-caption-text">Matching roundabouts (Tainan, click to go to this section on the map)</figcaption></figure></p>
<p>&#8230; and recognizable streets and intersections, like below&#8230;</p>
<p><figure id="attachment_2104" aria-describedby="caption-attachment-2104" style="width: 600px" class="wp-caption aligncenter"><a href="https://imrehg.github.io/taiwanmap/taiwanmap.html?location=Taichung#lat=24.140336&amp;lng=120.680156&amp;z=17"><img loading="lazy" decoding="async" class="wp-image-2104 size-full" src="https://gergely.imreh.net/blog/wp-content/uploads/2015/11/map_streets.gif" alt="Matching recognizable streets (Taichung)" width="600" height="400" /></a><figcaption id="caption-attachment-2104" class="wp-caption-text">Matching recognizable streets (Taichung, click to go to this section on the map)</figcaption></figure></p>
<p>&#8230; but not too small and not too large streets. Large streets have fewer recognizable locations (unless some notable mid-sized street is intersecting with it), and small streets are usually not placed too carefully on the map, so can&#8217;t really trust their positions.</p>
<p>What I couldn&#8217;t trust, though: rivers (they changed a lot), bridges (usually can&#8217;t tell if they are the same bridge in both era, or a new one built close to the no longer there old one, as it is a common practice), coastlines, lakes, large structures.</p>
<p>The minimal number of landmarks needed for a fit (ideally) is just two, and surprisingly, there were a couple maps where I could get along with about three. In most cases, though, I needed at least 4-6 landmarks, and there were some I needed to discard for overall better quality of fit. Some maps show pretty good accuracy, while others (such as e.g. <a href="https://imrehg.github.io/taiwanmap/taiwanmap.html?location=Kaohsiung">Kaohsiung</a>) are quite poor &#8211; compared to today&#8217;s satellite pictures, of course. It&#8217;s all enjoyable, though.</p>
<p>Then added a few more functions to the page, such as changing the opacity, being able to link to the exact location and zoom level I&#8217;m looking at, and some page-load animation (the maps are in the range of 4-10MB, not that quick to load).</p>
<p>The source code for the site is <a href="https://github.com/imrehg/taiwanmap">on Github</a>, and pull requests are accepted, naturally.</p>
<h2>History lessons learned</h2>
<p>I was very interested to note the things that have changed, and things that haven&#8217;t in the decades passed.</p>
<h3>Things that mostly stayed the same</h3>
<p><strong>Schools</strong> are usually at the same location, even stayed the same type (e.g. girls&#8217; high school staying that <a href="https://imrehg.github.io/taiwanmap/taiwanmap.html?location=Changhua#lat=24.081851&amp;lng=120.544232&amp;z=17">in Changhua</a>).</p>
<p><strong>Airports</strong> are usually at the same location (duh!), though usually greatly expanded, while the old runways can be matched to the new ones (<a href="http://localhost:8000/taiwanmap.html?location=Hsinchu#lat=24.819385&amp;lng=120.946305&amp;z=15">like in Hsinchu</a>).</p>
<p><strong>Train stations</strong>, of course, although tracks might change, or entire stations disappear (like <a href="https://imrehg.github.io/taiwanmap/taiwanmap.html?location=Beigang#lat=23.567516&amp;lng=120.296347&amp;z=17">in Beigang</a> or <a href="https://imrehg.github.io/taiwanmap/taiwanmap.html?location=Hualien#lat=23.973977&amp;lng=121.611590&amp;z=17">in Hualien</a>).</p>
<p><strong>Military installations</strong>, which surprised me, can stay the same, looks like the KMT troops just took over the Japanese posts and continued to use them. Some turned into schools, or could disappear too.</p>
<p>Many <strong>roundabouts</strong>, <strong>outlines of city blocks</strong> (like the <a href="https://imrehg.github.io/taiwanmap/taiwanmap.html?location=Taipei#lat=25.035710&amp;lng=121.520802&amp;z=16">CKS Memorial Hall now</a>, or <a href="https://imrehg.github.io/taiwanmap/taiwanmap.html?location=Yilan#lat=24.757393&amp;lng=121.753820&amp;z=16">Yilan&#8217;s city outline</a>), <strong>mountains</strong>, also stayed mostly the same.</p>
<h3>Things that changed a lot</h3>
<p><strong>City areas</strong> changed enormously (duh!), just look at the capital, <a href="https://imrehg.github.io/taiwanmap/taiwanmap.html?location=Taipei">Taipei</a>, the west side stayed mostly the same but built in about twice/three times as big area on the east. Most other cities grown just like that, as it&#8217;s very clear for example <a href="https://imrehg.github.io/taiwanmap/taiwanmap.html?location=Taitung">for Taitung</a>. It&#8217;s no wonder, 5.8 million people on the island in 1940, while above 23 million by now (<a href="https://en.wikipedia.org/wiki/Demographics_of_Taiwan#Population_census">according to Wikipedia</a>). This also brings the changes of a lot of <strong>streets and roads</strong>.</p>
<p>Water is definitely very changeable. <strong>Rivers</strong> got diverted a lot, most notably on the <a href="https://imrehg.github.io/taiwanmap/taiwanmap.html?location=Taipei#lat=25.071025&amp;lng=121.566421&amp;z=14">east side of Taipei </a>(near Neihu and Songshan districts) the Keelung river was straightened up, but the roads can still mirror the old path. Other rivers (or channels?) got covered up, and now only live on as roads &#8211; though I guess they might still flow under our feet (just like <a href="https://en.wikipedia.org/wiki/Fleet_Street">Fleet Street</a>)? Some more dramatic change is an entire <strong>missing island</strong> <a href="https://imrehg.github.io/taiwanmap/taiwanmap.html?location=Danshui#lat=25.165905&amp;lng=121.438357&amp;z=16">in Danshui</a>, I wonder what happened to it? <strong>Lakes</strong> change too, mostly I guess due to development around them (<a href="https://imrehg.github.io/taiwanmap/taiwanmap.html?location=Zuoying#lat=22.684229&amp;lng=120.296463&amp;z=15">like in Zuoying</a>). The <strong>sea shore</strong> is different for the many cities, as probably they were developed and also the shallows were naturally filled by the rivers (<a href="https://imrehg.github.io/taiwanmap/taiwanmap.html?location=Hsinchu#lat=24.816249&amp;lng=120.923389&amp;z=15">like in Hsinchu</a> and <a href="https://imrehg.github.io/taiwanmap/taiwanmap.html?location=Tainan#lat=22.998689&amp;lng=120.199147&amp;z=14">in Tainan</a>). Harbors don&#8217;t stay the same either (<a href="https://imrehg.github.io/taiwanmap/taiwanmap.html?location=Penghu">like in Penghu</a>).</p>
<p>Some landmarks such as <strong>shrines</strong> have changed too. The most notable I could find so far is in Taipei / Yuanshan, where the current <a href="https://en.wikipedia.org/wiki/Grand_Hotel_(Taipei)">Grand Hotel / 圓山大飯店</a> replaced a shrine in 1952 (yellow rooftop on the left below), while the <a href="https://en.wikipedia.org/wiki/National_Revolutionary_Martyrs%27_Shrine">Taipei Martyrs&#8217; Shrine</a> seems to be built on the site of another previous shrine in 1969 (yellow rooftop and cross-shaped grounds on the right below). On the map there&#8217;s another temple-complex looking structure in between them, that&#8217;s now the <a href="https://www.americanclub.org.tw/">Taipei American Club</a> and the <a href="https://en.wikipedia.org/wiki/International_Community_Radio_Taipei">International Community Radio Taipei (ICRT)</a>.</p>
<p><figure id="attachment_2140" aria-describedby="caption-attachment-2140" style="width: 600px" class="wp-caption aligncenter"><a href="http://imrehg.github.io/taiwanmap/taiwanmap.html?location=Taipei#lat=25.079136&amp;lng=121.528545&amp;z=17"><img loading="lazy" decoding="async" class="wp-image-2140 size-full" src="https://gergely.imreh.net/blog/wp-content/uploads/2015/11/map_shrine.gif" alt="Map Shrines" width="600" height="400" /></a><figcaption id="caption-attachment-2140" class="wp-caption-text">Grand Hotel replacing a shrine (yellow rooftop on the left), while shrine becomes a Taipei Martyrs&#8217; Shrine (yellow roof and cross-shaped ground on the right). In the centre, now the Taipei American Club and the ICRT radio station (click to go to this section on the map)</figcaption></figure></p>
<p><strong>Race courses</strong> disappeared too &#8211; together with the cavalry, I guess (like <a href="https://imrehg.github.io/taiwanmap/taiwanmap.html?location=Tainan#lat=22.992773&amp;lng=120.232814&amp;z=16">in Tainan</a>).</p>
<p>I&#8217;m sure there are a bunch of other things too, it will take some time to discover and understand things&#8230;</p>
<h3>Other notes</h3>
<p>The <strong>legends</strong> and information on the maps was pretty interesting. For example here&#8217;s the coverage map for Taipei / Taihoku, showing what aerial maps they stitched together, and when were the flights that took the photos:</p>
<p><figure id="attachment_2115" aria-describedby="caption-attachment-2115" style="width: 464px" class="wp-caption aligncenter"><a href="https://imrehg.github.io/taiwanmap/taiwanmap.html?location=Taipei#lat=25.018566&amp;lng=121.560241&amp;z=16"><img loading="lazy" decoding="async" class="wp-image-2115 size-full" src="https://gergely.imreh.net/blog/wp-content/uploads/2015/11/Taipei_Coverage_1944-min.jpg" alt="Taipei aerial photo coverage" width="464" height="469" /></a><figcaption id="caption-attachment-2115" class="wp-caption-text">Taipei aerial photo coverage</figcaption></figure></p>
<p>The Internet also taught me a few things, such as <a href="https://www.reddit.com/r/taiwan/comments/3o2vwh/taiwanese_city_maps_in_wwii_and_now/cvu2wml">this very insightful comment on Reddit</a> that traced back the Chinese / Japanese <strong>city names</strong> of these maps.</p>
<p>I was also amazed by how detailed information the Americans had about the <strong>functions of the buildings</strong> &#8211; down to the type of factories, the type schools the buildings were. I would not be surprised if the maps were supplemented by some real intelligence from the ground. Especially likely as the big cities had so much more such details than the smaller locations (where there might not be more than a few likely military installations noted). I wonder if there&#8217;s any good source to learn about this &#8211; about American intelligence behind enemy lines in the Pacific theatre of WWII.</p>
<h2>To the Future</h2>
<p>Now that everything kinda works, I think I&#8217;ll spend more time looking at the maps instead of working with them, try to learn more.</p>
<p>Hosting this project on Github is definitely pretty easy and convenient, though I start to see that their speed is not necessarily very good for big assets like the map images. Could add Cloudfront very easily to speed things up, just I don&#8217;t necessarily want to pay for that extra speed just yet. :P</p>
<p>To be able to show the loading animation I currently need to use jQuery to preload the image, then rely on the browser caching to <em>not</em> to download the image for the second time when the image is attached to the map object to create the overlay. It works pretty well&#8230; except in the Facebook Android app&#8217;s built in browser &#8211; that happily ignores caching and downloads the image twice (ouch). Would be awesome to figure out how can I get directly from the Google Map API when it finished downloading the image.</p>
<p>Might revisit a couple of the maps to see if I can improve the fit, though really just a couple of them, most are totally fine for their quality. Should also add the Japanese writing of the city names for more authenticity and discoverability.</p>
<p>And in the meantime, <a href="http://imrehg.github.io/taiwanmap/">keep checking the map</a>, and any comment or feedback is appreciated! A big thanks to the <a href="http://www.lib.utexas.edu/">University of Texas Libraries </a>and the <a href="http://www.lib.utexas.edu/maps/">Perry-Castañeda Library Map Collection</a> for the <a href="http://www.lib.utexas.edu/usage_statement.html">public domain maps</a>!</p>
<p>The post <a href="https://gergely.imreh.net/blog/2015/11/taiwan-wwii-map-overlays/">Taiwan WWII Map Overlays</a> appeared first on <a href="https://gergely.imreh.net/blog">ClickedyClick</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://gergely.imreh.net/blog/2015/11/taiwan-wwii-map-overlays/feed/</wfw:commentRss>
			<slash:comments>12</slash:comments>
		
		
			</item>
		<item>
		<title>Automating the hell out of it</title>
		<link>https://gergely.imreh.net/blog/2013/09/automating-the-hell-out-of-it/</link>
					<comments>https://gergely.imreh.net/blog/2013/09/automating-the-hell-out-of-it/#comments</comments>
		
		<dc:creator><![CDATA[Gergely Imreh]]></dc:creator>
		<pubDate>Mon, 16 Sep 2013 10:03:29 +0000</pubDate>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[automate]]></category>
		<category><![CDATA[bash]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[scripts]]></category>
		<guid isPermaLink="false">https://gergely.imreh.net/blog/?p=1610</guid>

					<description><![CDATA[<p>I set up a number of scripts to automate part of my life, from checking bank account balances to being notified when an ebook sells. These are the scripts.</p>
<p>The post <a href="https://gergely.imreh.net/blog/2013/09/automating-the-hell-out-of-it/">Automating the hell out of it</a> appeared first on <a href="https://gergely.imreh.net/blog">ClickedyClick</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Even before the <a title="4-Hour Work Week homepage" href="http://www.fourhourworkweek.com/">4-Hour Work Week</a> made me more serious about this, I really enjoyed automating tasks, that benefit from not needing to remember to do, or would be troublesome to do otherwise. This frees up a lot of time, keeps a bunch of problems away, and it is actually quite fun when the information comes to me instead me going to it.</p>
<p>Now I have automated checking my bank account and credit card balance, updating dynamic IP of server, ebook sales numbers, and network clock synchronizing. There are some general ideas that I summarize, then give an intro to all of those scripts.</p>
<p><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-1615" alt="Banking script" src="https://gergely.imreh.net/blog/wp-content/uploads/2013/09/banking.jpg" width="500" height="310" /></p>
<h2>Tools</h2>
<p><strong>Most of my scripts</strong> are written in <a title="Bash reference" href="http://www.gnu.org/software/bash/manual/bashref.html">bash</a>, because it&#8217;s relatively straightforward to hammer out simple stuff, and it is surprisingly simple to do a lot of things once I have thought enough about a problem. The <a title="Advanced Bash-Scripting Guide" href="http://www.tldp.org/LDP/abs/html/">Advanced Bash-Scripting Guide</a> is always on my reading list, but I usually get to check only the parts that are relevant to the given problem. You can get quite far with a few simple constructs.</p>
<p>The most common parts I seem to come across:</p>
<ul>
<li>if-then-else constructs: <em>if [ -f &#8216;directory &#8216;]; then echo &#8220;Found!&#8221;; fi</em></li>
<li>for loops: <em>for f in *.png; do optipng $f; done</em></li>
<li>loading the results of a command into a variable: <em>VAR=$(command)</em></li>
</ul>
<p>For most other problems with a little keyword-fu there&#8217;s always an answer on <a title="StackOverflow" href="http://stackoverflow.com">StackOverflow</a> or on the web.</p>
<p>Another group of scripts uses <strong>Python</strong>, when a bit more data-manipulation is needed, like web scraping or JSON parsing. Actually, all of the scripts could be rewritten in Python for consistency, and it would probably be be simpler too, which is something for the future.</p>
<p>As a general tip, most of these scripts need tweaking, and all of them are sort of alpha-beta quality code. To facilitate hacking and reduce heartache of mangled clever code, I keep everything in <a title="Git homepage" href="http://git-scm.com/">git</a> repos. I share those repos online, so have to make sure there are <strong>no secrets checked in</strong>, ever. It helps to strategically use .gitignore, separate files for the secrets, and having an example how that secrets file should look in the inside.</p>
<p>Most of these scripts are <strong>run periodically</strong> by <a title="15 Practical Cron Examples" href="http://www.thegeekstuff.com/2009/06/15-practical-crontab-examples/">cron</a>, so it is worth having some basic knowledge about how to schedule it.</p>
<p>Some scripts <strong>send me emails</strong> under specific circumstances (some after every run, some when new information appears), and for good delivery I have set up postfix to use <a title="Configure Postfix to Use Gmail SMTP on Ubuntu" href="http://rtcamp.com/wordpress-nginx/tutorials/linux/ubuntu-postfix-gmail-smtp/">Gmail as an SMTP relay</a>. This way I&#8217;m sure to receive the emails and receive them quickly.</p>
<h2>Scripts</h2>
<p>These are the scripts I use most often and the longest. Still, many of them are under development and adjust them whenever I learn how to do things better. I list the links to all their repos, where it can be improved.</p>
<h3>Banking account balances</h3>
<p>My two main bank accounts are queried once a day for available balance and I&#8217;m notified by email. Both accounts needed quite a bit of web scraping (and got them done at two different <a title="OpenHack Taipei" href="http://openhack.github.com/taipei/">OpenHack Taipei events</a>). The banks&#8217; websites are pretty awfully organized (iframes within iframes within iframes; not using CSS classes and id), though it doesn&#8217;t have to be good for me, it has to be good for the bank.</p>
<h4>Cathay United Bank</h4>
<p>The <a title="Cathaycheck repo" href="https://github.com/imrehg/cathaycheck">cathaycheck</a> (click for repo) script queries the available balance at <a title="Cathay United Bank home page" href="https://www.cathaybk.com.tw">Cathay United Bank</a> by logging in with curl, and parsing the final page with <a title="Beautiful Soup" href="http://www.crummy.com/software/BeautifulSoup/">Beautiful Soup</a>. The script can be a skeleton for any other website where on has to log in and then navigate over a series of pages to get the information. The required HTML variable names can be extracted with the help of the Inspect Element tools in Chrome.</p>
<p>At the moment the credentials is stored in the crontab command, which is not really ideal, should rewrite to use a secrets file, though given that it runs on a server where I&#8217;m the only user (and root), for me there&#8217;s no practical difference at the moment. I have set it up to receive an email at the end of the day with the current balance.</p>
<h4>ANZ Taiwan credit card</h4>
<p>The <a title="anzcheck repo" href="https://github.com/imrehg/anzcheck">anzcheck</a> (click for repo) script queries my spending with the <a title="ANZ Taiwan homepage" href="http://anz.tw/">ANZ Taiwan</a> credit card. Again bash for logging in and Beautiful Soup for parsing the final page. It needs a bit more logic extracting information from a table, because the websites developers added no classes or ids to the items to make it easier to understand &#8211; or for them to style, but that&#8217;s not my problem.</p>
<p>Just recently updated that it extracts the spending items added to my balance on a given day, so I can will never be caught by surprise again (hopefully). Since many of my charges go to companies that have Chinese names, I quickly run into the problem of having to tell my Heirloom Mailx (that I use to send emails on my <a title="ArchLinux homepage" href="http://www.archlinux.org">ArchLinux</a> box)  that the text I want to mail is plain text, not an attachment. With some hacking the solution was to add a few more commands to &#8220;mail&#8221; so it knows that the text is UTF-8. From &#8220;sendthatmail.sh&#8221; in the repo, the parameters needed are:</p>
<pre>-S sendcharsets=utf-8 -S ttycharset=utf-8 -S encoding=8bit</pre>
<p>I could still extract some more information from the bank&#8217;s website, though nothing really urgent.</p>
<h3>No-IP address updater</h3>
<p>At the <a title="Taipei Hackerspace mailing list" href="https://groups.google.com/forum/#!forum/taipeihackerspace">Taipei Hackerspace</a> we have a handful of servers running, but the residential internet connection is provided by <a title="Chunghwa Telecom homepage" href="http://www.cht.com.tw/en/">Chunghwa Telecom</a> only gives us a dynamic IP address. Applying for a static IP seems to be pretty troublesome, so in the meantime I&#8217;m using a script on one of the servers to update the IP address associated with our dynamic <a title="Taipei Hackerspace homepage" href="http://tpehack.no-ip.biz">tpehack.no-ip.biz</a> address.</p>
<p>The <a title="No-Ip.com Bash Updater repo" href="https://github.com/taipeihackerspace/no-ip.com-bash-updater">no-ip-bash-updater</a> (click for repo) script is forked originally from <a title="the original repo" href="https://github.com/AntonioCS/no-ip.com-bash-updater">elsewhere</a>, but I have rewritten it quite a bit so that it</p>
<ul>
<li>needs no extra file to store the current IP address, but compares external IP with a DNS query</li>
<li>stores no secrets in the file</li>
</ul>
<p>It uses a pretty straightforward API call with HTTP authentication, the only real logic in there is to check when that call actually needs to be made.</p>
<h3>E-book sales</h3>
<p>Recently I have <a title="First sale of an ebook I helped to publish" href="https://gergely.imreh.net/blog/2013/09/first-sale-of-an-ebook/">helped a friend to publish an ebook</a> version of <a title="How to Start a Business in Taiwan ebook page" href="https://leanpub.com/startabusinessintaiwan">How to Start a Business in Taiwan</a> on Leanpub, and of course I want to know when there are any sales are made (disclaimer: I don&#8217;t get a cut of the sales, all goes to the author). The <a title="Leanpubsales repo" href="https://github.com/imrehg/leanpubsales">leanpubsales</a> (click for repo) script is written in Python, because using JSON there is easier than it would be with bash. The call otherwise is quite simple, just keep an external file around to check if the sales number have increased or not, if yes then send an email. To send an email conditional on the output the the script the &#8220;ifne&#8221; command from <a title="Moreutils homepage" href="http://joeyh.name/code/moreutils/">moreutils</a> is very useful (meaning: &#8220;if input is not empty&#8221;).</p>
<p>The query is run periodically, and lovely to receive the results. I will surely set up a script when I get <a title="My user on Leanpub" href="https://leanpub.com/u/imrehg">my own book ideas</a> published on Leanpub.</p>
<h3>RTC correction</h3>
<p>As a physicist in atomic physics, which is the area of science very much concerned about keeping precise time, keep all my servers&#8217; times synchronized with network time protocol (NTP) using chrony. One difficulty is that the real-time clock (RTC) of those computers is pretty crappy and drifts away. Wouldn&#8217;t be a problem if I never restart them, but a pain if I do: after restart it can be tens of seconds away until the time is synchronized again.</p>
<p>Chrony can sync NTP and the RTC, but it doesn&#8217;t do that automatically, I have to trigger it manually. Instead I have written up an <a title="Server scripts" href="https://github.com/imrehg/serverscripts">rtccorrect</a> (click for repo) script that is run every 2 hours or so (could be done just once a day, actually), and eliminates the drift of the RTC.</p>
<h3>Server backup</h3>
<p>For backing up data between servers <a title="Rsync homepage" href="http://rsync.samba.org/">rsync</a> has proven invaluable. I have a couple of scripts that do just that, though those are among my oldest ones and at that time I haven&#8217;t separated out personal information (way too easy to inline every credential, email, login, and all that), so I need to sanitize that. A couple of  ideas about these backup scripts:</p>
<ul>
<li>sometimes higher transfer speed can be achieved by messing with the ssh algorithms, eg. passing &#8220;-e &#8216;ssh -c arcfour'&#8221; to rsync</li>
<li>more often there&#8217;s even better performance when there&#8217;s an rsync daemon running on the remote computer (though with Raspberry Pi, both cases are still frustratingly slow)</li>
<li>can exclude some files if no need to transfer them, eg: &#8220;&#8211;filter=&#8217;- *.part'&#8221;</li>
<li>using rsync not just to transfer but to mirror, the &#8220;&#8211;delete&#8221; (delete at target if doesn&#8217;t exist at origin) and &#8220;&#8211;archive&#8221; are pretty useful</li>
</ul>
<p>For these backups I also use the <a title="Dead Man's Snitch" href="https://deadmanssnitch.com/">Dead Man&#8217;s Snitch</a> to know when things didn&#8217;t work out, e.g having a similar command in the cron list, where backup.sh is my script&#8217;s name, xxxxxxxx is the snitch ID from my account:</p>
<pre>backup.sh &amp;&amp; curl -s https://nosnch.in/xxxxxxx &gt; /dev/null</pre>
<p>This way I got to know when my backup server was dying all the time because of bad heatsink, or my host server by flaky hosting company&#8230;.</p>
<h2>Afterword</h2>
<p>I guess there will be just more automation in the future, and maybe many of these scripts can be ported onto a common base so new ones are made much easier. What else do you guys automate?</p>
<p>The post <a href="https://gergely.imreh.net/blog/2013/09/automating-the-hell-out-of-it/">Automating the hell out of it</a> appeared first on <a href="https://gergely.imreh.net/blog">ClickedyClick</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://gergely.imreh.net/blog/2013/09/automating-the-hell-out-of-it/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
		<item>
		<title>Barometric recording of Typhoon Soulik</title>
		<link>https://gergely.imreh.net/blog/2013/07/typhoon-soulik/</link>
					<comments>https://gergely.imreh.net/blog/2013/07/typhoon-soulik/#comments</comments>
		
		<dc:creator><![CDATA[Gergely Imreh]]></dc:creator>
		<pubDate>Sun, 14 Jul 2013 01:47:44 +0000</pubDate>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Taiwan]]></category>
		<category><![CDATA[arduino]]></category>
		<category><![CDATA[environment]]></category>
		<category><![CDATA[hackerspace]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[taipei]]></category>
		<category><![CDATA[typhoon]]></category>
		<guid isPermaLink="false">https://gergely.imreh.net/blog/?p=1489</guid>

					<description><![CDATA[<p>I got a barometric pressure sensor just in time for Typhoon Soulik. Recorded it's passing and synced it up with satellite imagery for better understanding typhoons.</p>
<p>The post <a href="https://gergely.imreh.net/blog/2013/07/typhoon-soulik/">Barometric recording of Typhoon Soulik</a> appeared first on <a href="https://gergely.imreh.net/blog">ClickedyClick</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>It all started a few weeks ago with <a title="Sparkfun Electronics" href="https://www.sparkfun.com/">Sparkfun</a> having &#8220;20%-off&#8221; day, when I got myself (among other things) a <a title="Barometric Pressure Sensor - BMP085 Breakout" href="https://www.sparkfun.com/products/11282">BMP085 barometric pressure sensor</a>. When it arrived, I have soldered some pins on it, and set it up with an <a title="Arduino Nano homepage" href="http://arduino.cc/en/Main/ArduinoBoardNano">Arduino Nano</a>, to have the readings off it easily.</p>
<p><figure id="attachment_1490" aria-describedby="caption-attachment-1490" style="width: 500px" class="wp-caption aligncenter"><img loading="lazy" decoding="async" class="size-full wp-image-1490" alt="View of the circuit" src="https://gergely.imreh.net/blog/wp-content/uploads/2013/07/bmp085.jpg" width="500" height="394" /><figcaption id="caption-attachment-1490" class="wp-caption-text">BMP085 barometric pressure sensor breakout board from Sparkfun</figcaption></figure></p>
<p>Originally all I wanted is just some laid back pressure recording, so maybe I can use that to predict the weather a bit. &#8220;Pressure falls: bad weather comes, pressure rises: things will clear up&#8221;. I was recording for about a week, and nothing really noteworthy came out of that.</p>
<p>Then it was the news, that the year&#8217;s first typhoon is on the way to Taiwan, and it was supposed to be a big one. Obvious that I will try to record the barometric pressure pattern of its passing, but wanted to make it more interesting and informative. More visual than just the timeseries plot of pressures.</p>
<p>The J<a title="JMA Tropical Cyclone page " href="http://www.jma.go.jp/en/typh/">apanese Meteorological Agency</a> (JMA) is a good place to watch for information about typhoons. They list path prediction, typhoon properties like strength, wind speeds, and central pressure, have satellite imagery. Putting these together, two days before the typhoon arrived, I set up a script to download the satellite imagery as it became available.</p>
<p><figure id="attachment_1502" aria-describedby="caption-attachment-1502" style="width: 493px" class="wp-caption aligncenter"><img loading="lazy" decoding="async" class="size-full wp-image-1502" alt="Satellite picture of Typhoon Soulik and location of Taiwan on 2013-07-12 morning" src="https://gergely.imreh.net/blog/wp-content/uploads/2013/07/youarehere.jpg" width="493" height="500" /><figcaption id="caption-attachment-1502" class="wp-caption-text">The morning before the typhoon arrived</figcaption></figure></p>
<p>The JMA publishes usually 2 satellite images in an hour for our North Western Quadrant (at :00 and :30), one of them covers the whole area, the other covers just the top 80% or so, leaving a dark band on the bottom. Nevertheless, matching up the pressure reading with the satellite pictures would be a good little project for this time.</p>
<p>Friday came, the government gave the afternoon off, though it turned out no landfall happened till everyone supposed to be off anyways, just a bit of on-and-off rain. People stocked up on convenience store food (I now have a good supply of instant noodles:) and water, taped over their glass windows, take in their plants and BBQ equipment from outside &#8211; well, those who have planned.</p>
<p>Around 10pm the big rain has arrived, <a title="Typhoon rain by Soulik" href="http://youtu.be/eS0LjVJU11I">here&#8217;s a video of how it looked from my window</a>. Went to sleep later, and got woken up around 3:30am by the rain having changed into pretty darn big wind. Here&#8217;s <a title="The windy part of the Typhoon Soulik" href="http://youtu.be/fNr4np10R0k">another video of the violent part of the typhoon</a> that time in the morning, that doesn&#8217;t even really do it justice. The houses around here are pretty tall, and I wonder if they have protected from the wind, or been artificial canyons channeling it. Some things got broken, though not as much as I expected &#8211; which is a very good thing.</p>
<p>In the meantime by the power of the Internet I have checked out the pressure reading, how is it going a few miles away in the <a title="Taipei Hackerspace in Google Maps" href="https://plus.google.com/100224637045566967774/about?hl=en">Taipei Hackerspace</a>, where I have left the barometric pressure sensor (the geolocation is <a title="Recording location: Taipei Hackerspace" href="https://maps.google.com/maps?q=25.052993,121.516981">25.052993,121.516981</a>)</p>
<p>Here&#8217;s the entire recording of the approximately 2 days of typhoon. It was pretty okay weather in the start and end of the plot.</p>
<p><figure id="attachment_1492" aria-describedby="caption-attachment-1492" style="width: 500px" class="wp-caption aligncenter"><img loading="lazy" decoding="async" class="size-full wp-image-1492" alt="Plot of pressure readings" src="https://gergely.imreh.net/blog/wp-content/uploads/2013/07/barolog.png" width="500" height="385" /><figcaption id="caption-attachment-1492" class="wp-caption-text">Pressure reading during the passing of Typhoon Soulik, recorded at the Taipei Hackerspace</figcaption></figure></p>
<p>The readings have been corrected to sea level (from about 20m height, where the Taipei Hackerspace is), should be good within 1hPa or less.</p>
<p>The the pressure was indeed dropping like a rock, and the dip on the graph coincided with the most violent wind that woke me up. According the JMA, the central area of the typhoon had pressures down to 950hPa, which means that core must have passed pretty close to here, having readings below 958hPa, though probably not directly, as it didn&#8217;t stay down there for long.</p>
<p>I made a video syncing up the pressure reading and the satellite picture. The red dot on the video marks the recording location. (Watching it in full screen and HD makes it clearer.)</p>
<p><iframe loading="lazy" title="Typhoon Soulik" width="580" height="326" src="https://www.youtube.com/embed/cROepeX6NmY?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe></p>
<p>I would wonder what was the flat part in the readings while the typhoon was leaving. Maybe sign of changing direction, by the look of it.</p>
<p>Either way, this was fun to do, and I am glad that only a few people got hurt here, much fewer then even during the less powerful typhoons. Maybe getting people scared a little (like with this &#8220;super typhoon&#8221; stuff that went on) helps them keep safe? Just don&#8217;t use it too often.</p>
<h4>Extra material</h4>
<p>I put almost all <a title="Scripts and data in Gist" href="https://gist.github.com/imrehg/5992831">material used here into a gist</a>: the satellite imagery download script, the plotting, the movie frame generation, the movie generation script, and the complete barometric recording. Because this last part is pretty big (5Mb), Github truncated the rest of the scripts. I guess it&#8217;s okay to check check it out. Will add the Arduino sketch to read the sensor and the logging script later.</p>
<p>The satellite imagery weighs about 60Mb, so don&#8217;t put it online, but if anyone wants them, let me know.</p>
<p>Keep safe!</p>
<p>The post <a href="https://gergely.imreh.net/blog/2013/07/typhoon-soulik/">Barometric recording of Typhoon Soulik</a> appeared first on <a href="https://gergely.imreh.net/blog">ClickedyClick</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://gergely.imreh.net/blog/2013/07/typhoon-soulik/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>Laboratory 2.0 &#8211; a monitoring system</title>
		<link>https://gergely.imreh.net/blog/2012/10/laboratory-2-0-a-monitoring-system/</link>
					<comments>https://gergely.imreh.net/blog/2012/10/laboratory-2-0-a-monitoring-system/#comments</comments>
		
		<dc:creator><![CDATA[Gergely Imreh]]></dc:creator>
		<pubDate>Sun, 28 Oct 2012 14:03:15 +0000</pubDate>
				<category><![CDATA[Admin]]></category>
		<category><![CDATA[Lab]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[mongodb]]></category>
		<category><![CDATA[nodejs]]></category>
		<category><![CDATA[python]]></category>
		<guid isPermaLink="false">http://gergely.imreh.net/blog/?p=1150</guid>

					<description><![CDATA[<p>Being lazy physicist programmer, I grab on every opportunity to automate things in our lab. Recently I had my first large scale chance to try out the technologies I was playing with in my spare time, and amaze my coworkers. And of course create something useful.</p>
<p>The post <a href="https://gergely.imreh.net/blog/2012/10/laboratory-2-0-a-monitoring-system/">Laboratory 2.0 &#8211; a monitoring system</a> appeared first on <a href="https://gergely.imreh.net/blog">ClickedyClick</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Looks like that one of my specialty as a physicist, and contribution to the labs where I have worked so far, is bringing different kinds of programming techniques, and technologies to the table. I&#8217;m not saying I&#8217;m any better than many of the professors, post-docs, and students I&#8217;ve met so far (there are plenty of ingenious ones), it&#8217;s more like I experiment with different tools, have tried more of the cutting edge or recent technologies, did some web programming and could whip up something quick &#8211; that might not work very well at first, but does broaden the horizon for the rest of the people.</p>
<p>Also, I&#8217;m a lazy person, so want to automate as much as possible. That was on my mind recently when we have been preparing to do a vacuum-system <a title="Bake-out explanation on Wikipedia" href="http://en.wikipedia.org/wiki/Bake-out" target="_blank">bake-out</a>. It&#8217;s essentially a procedure to have a delicate experimental system, mostly made up of steel, glass, and stuff like that, closed up from the atmosphere, all the air pumped out, then heated up to high temperature (~150-300°C). One has to be careful, because things can break, there are temperature limitations for some materials, also on how quickly that temperature can change, requiring careful monitoring of the status of the system. And the whole thing takes something like two weeks or more. Perfect setting for automation.</p>
<h2>Set up the electronics</h2>
<p>The pressure measurements are done by some expensive other equipment so didn&#8217;t have to bother with that one yet, so set to work first on the temperature monitoring. Before it was a bunch of <a title="Thermocouple on Wikipedia" href="http://en.wikipedia.org/wiki/Thermocouple" target="_blank">thermocouples</a> and <a title="Multimeter on Wikipedia" href="http://en.wikipedia.org/wiki/Multimeter" target="_blank">multimeters</a>, requiring manual intervention and lots of labour. Instead, got some inspiration from <a title="Thermocouple Amplifier MAX31855 breakout board (MAX6675 upgrade) - v1.0" href="http://www.adafruit.com/products/269" target="_blank">Adafruit&#8217;s Thermocouple Breakout Board</a>, using the <a title="MAX31855 Cold-Junction Compensated Thermocouple-to-Digital Converter" href="http://www.maximintegrated.com/datasheet/index.mvp/id/7273" target="_blank">MAX31855</a> chip, and also from the <a title="Ocean Controls K Thermocouple Multiplexer Shield" href="http://www.oceancontrols.com.au/KTA-259.html" target="_blank">Thermocouple Multiplexer Shield</a>. It can handle only one channel, but can use some other chip together with it to switch between the different thermocouples, and so we can read it out one-by-one. The Adafruit board could only handle 1 channel, and the multiplexer shield was using an older chip for the measurement that I could not buy anymore. In the end, found a good analog multiplexer that one that is sold in the computer market here in Taipei, the <a title="CD4067B CMOS Single 16-Channel Analog Multiplexer/Demultiplexer" href="http://www.ti.com/product/cd4067b" target="_blank">CD4067B</a>, and it works pretty well.</p>
<p><figure id="attachment_1167" aria-describedby="caption-attachment-1167" style="width: 550px" class="wp-caption aligncenter"><a href="http://gergely.imreh.net/blog/wp-content/uploads/2012/10/temphack2.jpg"><img loading="lazy" decoding="async" class="size-large wp-image-1167" title="Breadboard setup for temperature monitoring" src="http://gergely.imreh.net/blog/wp-content/uploads/2012/10/temphack2-1024x768.jpg" alt="Breadboard setup for temperature monitoring Arduino" width="550" height="412" srcset="https://gergely.imreh.net/blog/wp-content/uploads/2012/10/temphack2-1024x768.jpg 1024w, https://gergely.imreh.net/blog/wp-content/uploads/2012/10/temphack2-500x375.jpg 500w, https://gergely.imreh.net/blog/wp-content/uploads/2012/10/temphack2-768x576.jpg 768w, https://gergely.imreh.net/blog/wp-content/uploads/2012/10/temphack2.jpg 2048w" sizes="auto, (max-width: 550px) 100vw, 550px" /></a><figcaption id="caption-attachment-1167" class="wp-caption-text">Breadboard setup for temperature monitoring with Arduino</figcaption></figure></p>
<p>Of course, setting it all up was quite a bit of fun times, as there were way too many gotchas along the way.</p>
<ul>
<li>MAX31855 is a <a title="Surface Mount Technology on Wikipedia" href="http://en.wikipedia.org/wiki/Surface-mount_technology" target="_blank">surface-mount</a> component, and haven&#8217;t worked with it before. Not too bad, and can be much neater, just takes some plactice</li>
<li>MAX31855 is a 3.3V circuit, so the CMOS voltage levels used by my <a title="Arduino Mega ADK on Arduino Wiki" href="http://www.arduino.cc/en/Main/ArduinoBoardADK" target="_blank">Arduino Mega ADK</a> had to be level shifted</li>
<li>Unlike the older chip, MAX31855 really needs differential input, and it&#8217;s much more sensitive to the environment. This required different kind of analog multiplexer than that board had</li>
<li>The Arduino Mega is a new model for me, and had some strange behaviour in terms of the serial communication</li>
<li>Surprisingly there are not too many options for 3.3V voltage regulators over here, just the LM1117, which is different from what others are using elsewhere</li>
<li>Lots of noise and stability issues until figured out what should be how. For example under no circumstance should touch the thermocouple to conducting surfaces, and avoid ground loops</li>
<li>While MAX31855 says it&#8217;s &#8220;cold-point compensated&#8221;, meaning that it accounts for the chip-s local temperature when measuring the thermocouple, it doesn&#8217;t appear completely compensated, meaning that we can have unexpected measurement change because the chip is heating up for example by being in a closed box.</li>
<li>Figuring out the right amount of time to wait between switching channels (375ms seems to be good enough, 500ms is totally fine)</li>
</ul>
<div>In the end, though, we did have a nice 16 channel thermocouple multiplexer, sending off the measurements onto an LCD screen and to the computer over an USB cable.</div>
<p><figure id="attachment_1166" aria-describedby="caption-attachment-1166" style="width: 550px" class="wp-caption aligncenter"><a href="http://gergely.imreh.net/blog/wp-content/uploads/2012/10/temphack.jpg"><img loading="lazy" decoding="async" class="size-large wp-image-1166" title="Temperature monitoring board" src="http://gergely.imreh.net/blog/wp-content/uploads/2012/10/temphack-1024x768.jpg" alt="Temperature monitoring board soldered" width="550" height="412" srcset="https://gergely.imreh.net/blog/wp-content/uploads/2012/10/temphack-1024x768.jpg 1024w, https://gergely.imreh.net/blog/wp-content/uploads/2012/10/temphack-500x375.jpg 500w, https://gergely.imreh.net/blog/wp-content/uploads/2012/10/temphack-768x576.jpg 768w, https://gergely.imreh.net/blog/wp-content/uploads/2012/10/temphack.jpg 2048w" sizes="auto, (max-width: 550px) 100vw, 550px" /></a><figcaption id="caption-attachment-1166" class="wp-caption-text">Temperature monitoring board in it&#8217;s lab setting with 16 thermocouple channels</figcaption></figure></p>
<p>This is then saved in a database, and can be accessed from elsewhere.</p>
<h2>Visualize!</h2>
<p>The thing that my co-workers were most amazed by wasn&#8217;t the electronics. Sure, they haven&#8217;t worked with Arduinos, but did do similar stuff. Instead they liked the monitoring interface much more, this is the one on the picture right here (can click to enlarge)</p>
<p><figure id="attachment_1151" aria-describedby="caption-attachment-1151" style="width: 550px" class="wp-caption aligncenter"><a href="http://gergely.imreh.net/blog/wp-content/uploads/2012/10/BOMon.png" target="_blank"><img loading="lazy" decoding="async" class="size-large wp-image-1151  " title="Bakeout Monitor" src="http://gergely.imreh.net/blog/wp-content/uploads/2012/10/BOMon-1024x586.png" alt="Bakeout Monitor  interface showing the vacuum system, temperatures, pressures and long term graphs" width="550" height="314" /></a><figcaption id="caption-attachment-1151" class="wp-caption-text">Bakeout Monitor interface (click image for full view)</figcaption></figure></p>
<p>It&#8217;s the schematic layout of our equipment, with the temperatures positioned where the actual sensors are. Also, the change of the measured values in time are also displayed with live scrolling.</p>
<p>I&#8217;m not saying it&#8217;s great. Thinking about it, the major insight that made it good for the rest of the people is that I realized how much more people understand visual data: the placement of the values to the corresponding locations on the schematics. That&#8217;s the only thing.</p>
<p>So inside it&#8217;s a <a title="MongoDB" href="http://www.mongodb.org/" target="_blank">MongoDB</a> database (learned from previous mistakes, using a replica-set at least), with <a title="Python homepage" href="http://www.python.org/" target="_blank">Python</a> scripts talking to the sensors and saving the data, <a title="NodeJS home page" href="http://nodejs.org/" target="_blank">NodeJS</a> /<a title="Smoothie Charts homepage" href="http://smoothiecharts.org/" target="_blank"> Smoothie Charts</a> for visualization (and plain old CSS positioning of <a title="&lt;input&gt; tag explanation" href="http://www.w3schools.com/tags/tag_input.asp">&lt;input&gt; tags</a> for the reading display), <a title="NGINX homepage" href="http://nginx.org/" target="_blank">nginx</a>&#8216;s upstream module for running two monitoring servers just in case. It&#8217;s mostly in the <a title="Bakeout code on Github" href="https://github.com/imrehg/bakeout" target="_blank">Github repo of the monitoring code</a>, as well as the <a title="Arduino temperature monitoring" href="https://github.com/imrehg/sketchbook/tree/master/Thermocouple5" target="_blank">Arduino sketch for talking to the electronics</a>.</p>
<p>It was actually quite fun to write it all, and the gradual improvements, trying the new tech, trying not to lose to much data, amazed how well it works. Especially had a good time learning about the database, scaling, fault tolerance, performance&#8230;</p>
<p>Of course there could be room for a lot more improvements.</p>
<ul>
<li>My failover-restart bash scripts are awful, though they do seem to work more or less and counteract the USB unreliablilities</li>
<li>There were some changes to Smoothie Charts that I could improve on: logarithmic plotting, some display enhancements, wonder if it can be more optimized for performance</li>
<li>More efficient data loading. 12h data is about 30Mb in JSON format, that I send compressed, apparently it gets down to ~5% in size, but it still takes quite a bit of time to process on the frontend</li>
<li>The layout now can be changed from config files if the sensors change, so co-workers can do that without programming knowledge. I wonder if that can be simplified even more</li>
</ul>
<p>Of course, I&#8217;m a person who generally overengineers stuff, so maybe it&#8217;s good to stop somewhere. And the somewhere might be when I got to the point to use my Kindle for monitoring (craps out on 1h data already, but some real time things are good enough).</p>
<p><figure id="attachment_1161" aria-describedby="caption-attachment-1161" style="width: 500px" class="wp-caption aligncenter"><a href="http://gergely.imreh.net/blog/wp-content/uploads/2012/10/bomon_kindle_opt1.jpg"><img loading="lazy" decoding="async" class="size-full wp-image-1161" title="Bakeout Monitor on Kindle" src="http://gergely.imreh.net/blog/wp-content/uploads/2012/10/bomon_kindle_opt1.jpg" alt="Bakeout Monitor interface running on Kindle" width="500" height="416" /></a><figcaption id="caption-attachment-1161" class="wp-caption-text">Bakeout Monitor on running on Kindle 3, not perfect but does work</figcaption></figure></p>
<h2>Get on with it</h2>
<p>I did learn a lot along the way, and I&#8217;m sure that with this experience I will be let to do a little bit more in the lab in terms of programming ideas. I don&#8217;t like that the rest of the system is currently forced to be LabView, but that&#8217;s for another post, and there are so many things that can be improved in general as well. Let&#8217;s just go and do that.</p>
<p>The post <a href="https://gergely.imreh.net/blog/2012/10/laboratory-2-0-a-monitoring-system/">Laboratory 2.0 &#8211; a monitoring system</a> appeared first on <a href="https://gergely.imreh.net/blog">ClickedyClick</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://gergely.imreh.net/blog/2012/10/laboratory-2-0-a-monitoring-system/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
	</channel>
</rss>

<!--
Performance optimized by W3 Total Cache. Learn more: https://www.boldgrid.com/w3-total-cache/?utm_source=w3tc&utm_medium=footer_comment&utm_campaign=free_plugin

Object Caching 9/56 objects using APC
Page Caching using Disk: Enhanced 
Lazy Loading (feed)

Served from: gergely.imreh.net @ 2026-06-10 23:43:48 by W3 Total Cache
-->