<?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>weijie ou&#039;s scratch pad</title>
	<atom:link href="/feed/" rel="self" type="application/rss+xml" />
	<link>/</link>
	<description>writing and tech sharing from a backend engineer</description>
	<lastBuildDate>Fri, 21 Jan 2022 05:21:28 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.8.1</generator>

<image>
	<url>/wp-content/uploads/2022/01/cropped-Photo_2021-12-22_082907_Cropped-32x32.jpg</url>
	<title>weijie ou&#039;s scratch pad</title>
	<link>/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Debugging &#8220;403 Forbidden&#8221; Error Accessing Files on Apache 2</title>
		<link>/2022/01/20/debugging-403-forbidden-error-accessing-files-on-apache-2/</link>
		
		<dc:creator><![CDATA[weijie ou]]></dc:creator>
		<pubDate>Fri, 21 Jan 2022 05:19:06 +0000</pubDate>
				<category><![CDATA[Tech]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[devops]]></category>
		<category><![CDATA[hosting]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[web]]></category>
		<guid isPermaLink="false">/?p=137</guid>

					<description><![CDATA[<p>Recently I was trying to play around with some WordPress plugins, that brought my attention to the console and discovered there have been JavaScript errors [...]</p>
<p>The post <a href="/2022/01/20/debugging-403-forbidden-error-accessing-files-on-apache-2/">Debugging &#8220;403 Forbidden&#8221; Error Accessing Files on Apache 2</a> appeared first on <a href="/">weijie ou&#039;s scratch pad</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Recently I was trying to play around with some WordPress plugins, that brought my attention to the console and discovered there have been JavaScript errors for my site:</p>



<pre class="wp-block-preformatted">GET /wp-includes/js/dist/vendor/lodash.min.js?ver=4.17.19 net::ERR_ABORTED 403 (Forbidden)</pre>



<p>Looking at the site errors logged by Apache, it shows:</p>



<pre class="wp-block-preformatted">[Thu Jan 13 01:50:48.844763 2022] [access_compat:error] [pid 18887] [client 50.47.132.16:60932] <strong>AH01797: client denied by server configuration:</strong> /var/www/html/aresou.net/public_html/wp-includes/js/dist/vendor/lodash.min.js, referer: /wp-admin/index.php</pre>



<p>Weird enough, this error only happens on admin pages, not on the front pages or posts. The first thing I did is to check the folder and file permissions within the WordPress installation. Apache might be unable to serve the static file because <code>www-data</code> account cannot read that file or folder.</p>



<p>Nothing suspicious after checking that. I even set folders to 755 and files to 644 with <code>chmod</code>. Seems like the problem isn&#8217;t in the file system. Having done a bit more research, I realized that the next possible cause is the Apache site configurations.</p>



<p>I have three sites on my host, serving two blogs (one of them is aresou.net, aka this site you&#8217;re reading) and one personal wiki. The wiki shares the same root domain with this blog. First I reviewed the <code>&lt;Directory></code> sections of the configs for the two sites with their own domains. Everything looks good, there was no permission restricted from either root or sub folders. Apache should not be blocking access to these folders.</p>



<p>As the wiki site is sharing the same root domain with this blog, I did not think of checking the config. Well, this is the worst assumption I had in the debugging. With more research, I found a line somewhere saying &#8220;Apache will combine directives from all enabled site configurations when loading&#8221;. To be precise, let me quote from Apache official documentation:</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>Directives in the configuration files may apply to the entire server, or they may be restricted to apply only to particular directories, files, hosts, or URLs. This document describes how to use configuration section containers or <code>.htaccess</code> files to change the scope of other configuration directives.</p><cite><a href="https://httpd.apache.org/docs/2.4/sections.html">https://httpd.apache.org/docs/2.4/sections.html</a></cite></blockquote>



<p>Which means, any directives from any site config file will be applied to the whole server, if it is not restricted to a particular scope. I immediately went back and checked the config for my wiki site. There were a few lines blocking access for some folders, but not everywhere:</p>



<pre class="wp-block-preformatted">...
Require all denied
...
Order allow,deny
Deny from all
Satisfy All</pre>



<p>They are for protecting data folders in DokuWiki, specifically for Apache older than version 2.4. The config is copied directly from <a href="https://www.dokuwiki.org/security#deny_directory_access_in_apache">their official documentation</a>. Then I noticed another few lines:</p>



<pre class="wp-block-preformatted">&lt;LocationMatch "(data|conf|bin|inc|<strong>vendor</strong>)/">
    Order allow,deny
    Deny from all
    Satisfy All
&lt;/LocationMatch></pre>



<p>The &#8220;vendor&#8221; regex keyword immediately caught my eyes. Recall that the forbidden JavaScript file is placed under somewhat &#8220;/vendor/&#8221; folder. Also, this <code>&lt;LocationMatch></code> section lays at the top level without scope restriction, meaning it will be applied by Apache to the whole server, even though it is only configured within one site.</p>



<p>It&#8217;s easy to fix the problem if knowing the root cause. By adding a prefix in the match regex, the forbidden error in WordPress went away and the admin page is again working like a charm.</p>



<pre class="wp-block-preformatted">&lt;LocationMatch "<strong>/wiki/</strong>(data|conf|bin|inc|vendor)/">
    Order allow,deny
    Deny from all
    Satisfy All
&lt;/LocationMatch></pre>



<p>It is also possible to fix this by adding new directives introduced from Apache 2.4, without using <code>&lt;LocationMatch></code>:</p>



<pre class="wp-block-preformatted">&lt;Directory /usr/share/dokuwiki/data>
        Require all denied
        ## FOR VER APACHE2.4
        ## Add other directories one by one
&lt;/Directory></pre>



<p>Hope this article can save someone a bit of time. It took me almost 2 hours to figure out what was going on. Have a good day!</p>
<p>The post <a href="/2022/01/20/debugging-403-forbidden-error-accessing-files-on-apache-2/">Debugging &#8220;403 Forbidden&#8221; Error Accessing Files on Apache 2</a> appeared first on <a href="/">weijie ou&#039;s scratch pad</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>First 3 months at Discord as a Software Engineer</title>
		<link>/2022/01/11/first-3-months-at-discord-as-a-software-engineer/</link>
		
		<dc:creator><![CDATA[weijie ou]]></dc:creator>
		<pubDate>Wed, 12 Jan 2022 00:49:08 +0000</pubDate>
				<category><![CDATA[Life]]></category>
		<category><![CDATA[career]]></category>
		<category><![CDATA[discord]]></category>
		<category><![CDATA[software engineering]]></category>
		<guid isPermaLink="false">/?p=111</guid>

					<description><![CDATA[<p>Intro Last year (2021), I decided to move on from Microsoft, where I worked in the past 4 years. Microsoft is absolutely one of the [...]</p>
<p>The post <a href="/2022/01/11/first-3-months-at-discord-as-a-software-engineer/">First 3 months at Discord as a Software Engineer</a> appeared first on <a href="/">weijie ou&#039;s scratch pad</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<div class="wp-block-image is-style-default"><figure class="aligncenter size-full is-resized"><img decoding="async" src="/wp-content/uploads/2022/01/Discord-LogoWordmark-Color.png" alt="" class="wp-image-116" width="285" height="78" srcset="/wp-content/uploads/2022/01/Discord-LogoWordmark-Color.png 876w, /wp-content/uploads/2022/01/Discord-LogoWordmark-Color-300x82.png 300w, /wp-content/uploads/2022/01/Discord-LogoWordmark-Color-768x210.png 768w" sizes="(max-width: 285px) 100vw, 285px" /></figure></div>



<p class="has-medium-font-size">Intro</p>



<p class="has-drop-cap">Last year (2021), I decided to move on from Microsoft, where I worked in the past 4 years. Microsoft is absolutely one of the best workplaces for Software Engineers. Azure is even better. At Service Bus team, I learnt a ton on how to build and maintain a stable cloud service which serves millions of customers including large enterprises.</p>



<p>Interviewing sessions took about 3 months, and Discord is the last company I interviewed with. At the time Yen, our Director of Data Platform, reached out to me directly on LinkedIn, I was almost going to accept the offer from Square. Luckily, I still finished the process with Discord and found it most attractive.</p>



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



<p>To be honest though, I was not a regular Discord user before I joined. However, it was a significant factor for my decision that the app is well-designed, super snap and super user-friendly. The UI/UX and feeling was impressive the first time I dived into the app. Not to say the voice and video streaming quality is the best among all the online meeting/chatting app that I have used for prolong period. Teams (yes as a ex-Microsoft-er I do think Teams is doing great but can be much better) and Zoom can really learn from Discord, in my own opinion.</p>



<p class="has-medium-font-size">As an Engineer</p>



<p>So far I have no issue or complaints about the engineering system at Discord. Like most start-ups, the engineering process is flexible and fast-pace here. Unlike most start-ups, the system and toolset are also mature enough for engineers to not worry too much about anything outside the product they build, for example the infrastructure, CI, and deployment.</p>



<p>The development setup is straightforward, effortless and compatible. I easily initiated local dev environment on all my machines in both MacOS and Windows (via WLS2 Ubuntu).  My favorite editor Visual Studio Code is by default supported with basic workspace and settings files integrated in the repository. Spinning up the local environment and get read for coding is as simple as typing one command.</p>



<p>Managers are supportive, engineers have great control on the design and code. Passionate people are contributing (a lot) to the repo everyday, progressing the app and service. Everything is moving fast, but right things are being done. Check-ins following good engineering principles and reviews are neat.</p>



<p>Stale components are also retired properly by removing relevant code and references. Engineers are encouraged to spend time on housekeeping works which I think is fantastic to keep the code base always in high quality and clean state.</p>



<p class="has-medium-font-size">Collaboration</p>



<p>This section is observing not only form an engineer&#8217;s perspective. Internally we heavily use Discord as the communication tool (for sure!), which is a new experience to me. We all know that collaboration nicely happen when people are actively communicating. Discord is doing a great job to replace even emails, with good ability of searching chat history.</p>



<p>Real-time DM tool like Discord has an advantage that you usually don&#8217;t have to wait long before people reply. For emails, there could be days of waiting time and &#8220;buried in piles of email&#8221; is a common reason that you don&#8217;t get prompt response.</p>



<p>It is also a breeze to start voice conversations with whoever you want to talk to, and stream your screen with almost no glitches. Of course, you are very welcomed to subscribe to Nitro for high resolution streaming that greatly improves the experience of your audiences.</p>



<p>From the experience of leading my first ground zero project at Experimentation Team at Discord, I like how my colleagues are friendly, participating and contributing to my own project. I received tons of useful feedbacks on scoping, design and coding from engineers, data scientists and PMs. They are proactive and read through the documents carefully, giving considerate comments that you can really apply to improve the overall quality of your project.</p>



<p>Meetings are effective, too. While I don&#8217;t currently have too many meetings on my calendar, every session I attended or led, is super fruitful. We tend to get prepared for the meetings, even with pre-read minutes so that everyone will be on the same page. Attendees share their opinions and concerns out of thoughtful observations. You can certainly get valuable feedbacks rather than wasting 30-60 minutes just walking through PPTs.</p>



<p>I feel that everyone is doing the best to share his/her knowledge and perspective to make others more productive. So that the project can further progress and as a result, Discord products are becoming better and better. I really do love this kind of collaboration.</p>



<p class="has-medium-font-size">Culture</p>



<p>I love the culture at Discord, it is inclusive, active and belonging. It might be still early and I have more to experience. Many employees are gamers, which I knew from the beginning since I was so surprise to find one interviewer know the title <em>&#8220;428: Shibuya Scramble&#8221;</em>, a game that not even known by many AVG players. People are talking like friends, discussing and collaborating like comrades.</p>



<p>Discord has a shallow top-bottom structure in regards of leveling. My most impressive new-hire experience is that Jason Citron, our CEO, will hold an hour-long meeting with all the new employees in that week to share the history and outlook of the company. He also welcome any question and be very careful, concrete and specific on the answers. I appreciate Jason for doing a bit research before he coming back to my question via direct message, I felt respected as a member of the Discordians.</p>



<p>These all make up to what Discord advocates to the world: build belongings. While Discord is striving to make here the best place for any group or community, we as the builders feel strong belonging to the company as well. I truly believe that we have the right direction and strategy as a company, and the future has more to come. Discord is playing a very important role to accommodate more and more people to provide open, smooth and reliable experience for all sorts of communication. In the past two years, pandemic brings increasing demand for the community to find a belonging place in the virtual world, and Discord is the first and best for that, ever.</p>
<p>The post <a href="/2022/01/11/first-3-months-at-discord-as-a-software-engineer/">First 3 months at Discord as a Software Engineer</a> appeared first on <a href="/">weijie ou&#039;s scratch pad</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Reflection for My Last Semester at OMSCS</title>
		<link>/2021/05/21/reflection-for-my-last-semester-at-omscs/</link>
					<comments>/2021/05/21/reflection-for-my-last-semester-at-omscs/#comments</comments>
		
		<dc:creator><![CDATA[weijie ou]]></dc:creator>
		<pubDate>Fri, 21 May 2021 19:12:22 +0000</pubDate>
				<category><![CDATA[Thoughts]]></category>
		<category><![CDATA[computer science]]></category>
		<category><![CDATA[georgia tech]]></category>
		<category><![CDATA[master degree]]></category>
		<category><![CDATA[omscs]]></category>
		<guid isPermaLink="false">/?p=48</guid>

					<description><![CDATA[<p>Introduction Spring 2021 was my last semester in the master program at Georgia Tech. I chose to push my limit and elected two courses: 6515 [...]</p>
<p>The post <a href="/2021/05/21/reflection-for-my-last-semester-at-omscs/">Reflection for My Last Semester at OMSCS</a> appeared first on <a href="/">weijie ou&#039;s scratch pad</a>.</p>
]]></description>
										<content:encoded><![CDATA[<h1>Introduction</h1>
<p>Spring 2021 was my last semester in the master program at Georgia Tech. I chose to push my limit and elected two courses:</p>
<ul>
<li>6515 Graduate Introduction to Algorithms</li>
<li>7210 Distributed Computing</li>
</ul>
<p>The second course is new on OMSCS. Nobody has elected this one before, we are literally the first batch of students to test the course.</p>
<p>It turns out the course is excellent and my passion on distributed systems aligns with the contents very well.</p>
<h1>Course Contents</h1>
<p>Let&#8217;s first see what are included in syllabus:</p>
<ul>
<li>Introduction to Distributed Systems</li>
<li>Primer of RPC</li>
<li>Time in Distributed Systems</li>
<li>State in Distributed Systems</li>
<li>Consensus</li>
<li>PAXOS and Friends</li>
<li>Replication</li>
<li>Fault-tolerance</li>
<li>Distributed Transactions</li>
<li>Consistency and Geo-Distributed Data Stores</li>
<li>Peer-to-peer, Mobility</li>
<li>Distributed Data Analytics</li>
<li>Distributed Machine Learning</li>
<li>Support for Datacenter-based Distributed Computing</li>
<li>Byzantine Fault Tolerance, Blockchain</li>
<li>Edge Computing, IoT</li>
</ul>
<p>The course covers a large range of theory and real-life practices in distributed systems. While it starts from fundamentals, it also goes up to the latest edge development of the industry, including graduate level topics like consensus, replication and fault-tolerance etc.</p>
<p>For the suggested readings, you can find classical articles and industry showcases from the companies running the largest distributed (and geo-distributed) systems in the world. Some examples:</p>
<ul>
<li>Raynal and M. Singhal. Logical Time: A Way to Capture Causality in Distributed Systems (Links to an external site.). IRISA Technical Report. (up to Section 7)</li>
<li>Lamport, Time, Clocks and The Ordering of Events in Distributed Systems</li>
<li>Spanner: Google’s Globally-Distributed Database</li>
<li>Scaling Memcache at Facebook</li>
<li>Gaia: Geo-Distributed Machine Learning Approaching LAN Speeds</li>
</ul>
<p>One of the hottest topics &#8211; machine learning &#8211; is also adapted in this course in a DS fashion. You will learn in a geo-distributed scenario, what are the advanced ways to make sure the learning system is working at most efficiency, utilizing compute power globally.</p>
<h1>Projects</h1>
<p>Well, I would say this course has the most hardcore projects among all the ones I studied in the program. It is even much harder than those in 8803 Compiler. You will be asked to implement a bunch of things which are critical components/concepts of a distributed system:</p>
<ul>
<li>Key-value stores</li>
<li>PAXOS consensus</li>
<li>View server</li>
<li>State transition and consistency in distributed system</li>
<li>Two-phase commit</li>
<li>Distributed transaction</li>
<li>Async message delivery in distributed system</li>
</ul>
<p>Projects are kind of related as one would be the base of another, especially for project 4 and 5.</p>
<p>The only complaint I have is the instructions, which can be improved to state the project intent and requirements much better. Most time I struggle understanding what should be done and what is the expected way to do it.</p>
<p>There are a bunch of tests running on GradeScope to evaluate your implementation. Two types of tests to expect: The RUN tests and SEARCH tests. Search test is a relatively new concept to me. The test code is not checking if the input/output are valid, but walking through the STATEs that your program can reach and see if any invariant violation. The concept reminds me something learnt in CS6340 Software Analysis and Test, which tests for invariants of code block, loops and branches.</p>
<p>The search test can be very difficult to pass reliably if the logic of the implementation is not or near to perfect. Any edge case, including super trivial ones, will be caught when the test walks into a state that is violating any assumption. Compare to run tests, search tests is very efficient in finding missed edge cases, along with the DSLab framework, to wrap everything in-memory (including I/O operations).</p>
<p>Difficulty of projects increases tremendously after Project 3 (as of Spring 2021). The first two are quite straightforward and simple, if you have some exposure to software engineering. You implement a basic key-value store, extending the provided interface and base <code>Application</code> class. After that, PAXOS comes into play and you are going to scratch (to the ground) your head for over 50 hours to implement the famous consensus protocol from Lamport&#8217;s thesis <a href="https://lamport.azurewebsites.net/pubs/paxos-simple.pdf"><em>Paxos Made Simple</em></a>. Well it feels like the &#8220;How to draw an owl meme&#8221;:</p>
<p><img fetchpriority="high" decoding="async" class="alignnone wp-image-50 size-full" src="/wp-content/uploads/2021/05/how-to-draw-an-owl.jpg" alt="" width="500" height="407" srcset="/wp-content/uploads/2021/05/how-to-draw-an-owl.jpg 500w, /wp-content/uploads/2021/05/how-to-draw-an-owl-300x244.jpg 300w" sizes="(max-width: 500px) 100vw, 500px" /></p>
<p>For sure, you will learn A LOT at the end, when you finish all five projects. It&#8217;s okay if you cannot get full score in all of them, I did not in the last one. Still, learn by coding is a good approach for studying distributed system, and computer science.</p>
<h1>Conclusion</h1>
<p>By striving through the course, I firmly believe that my passion is with Distributed Systems and I want to continue this journey. Go deep and go wide, that&#8217;s what I will be trying to do.</p>
<p>I strongly recommend anyone who is interested in the topics to take this class, it is well-organized, content rich, with good support from the professor and TAs. The topics are not stale, you could even leverage most of things you learnt in your job, if you work in the cloud industry.</p>
<p>Also applied to be an TA in this course, see you in Fall 2021.</p>
<p>The post <a href="/2021/05/21/reflection-for-my-last-semester-at-omscs/">Reflection for My Last Semester at OMSCS</a> appeared first on <a href="/">weijie ou&#039;s scratch pad</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>/2021/05/21/reflection-for-my-last-semester-at-omscs/feed/</wfw:commentRss>
			<slash:comments>4</slash:comments>
		
		
			</item>
		<item>
		<title>Summary and thinking on Bulb Switcher problem</title>
		<link>/2019/10/25/summary-and-thinking-on-bulb-switcher-problem/</link>
		
		<dc:creator><![CDATA[weijie ou]]></dc:creator>
		<pubDate>Fri, 25 Oct 2019 09:30:00 +0000</pubDate>
				<category><![CDATA[Tech]]></category>
		<category><![CDATA[algorithm]]></category>
		<category><![CDATA[leetcode]]></category>
		<guid isPermaLink="false">/?p=9</guid>

					<description><![CDATA[<p>Bulb Switcher Problem: There are n bulbs that are initially off. You first turn on all the bulbs. Then, you turn off every second bulb. [...]</p>
<p>The post <a href="/2019/10/25/summary-and-thinking-on-bulb-switcher-problem/">Summary and thinking on Bulb Switcher problem</a> appeared first on <a href="/">weijie ou&#039;s scratch pad</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<h4 class="wp-block-heading">Bulb Switcher</h4>


<p>Problem:</p>


<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>There are n bulbs that are initially off. You first turn on all the bulbs. Then, you turn off every second bulb. On the third round, you toggle every third bulb (turning on if it’s off or turning off if it’s on). For the ith round, you toggle every i bulb. For the nth round, you only toggle the last bulb. Find how many bulbs are on after n rounds.</p></blockquote>


<p>You can find the problem at <a href="https://leetcode.com/problems/bulb-switcher/">https://leetcode.com/problems/bulb-switcher/</a>.</p>


<p>I’m not going to talk about how to actually code the problem here, just want to share how I thought and finally got to the best solution.</p>


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


<p>The very naive way would be, create an array of length <code>n</code>, then loop through the array <code>n</code> times to switch the bulbs. This will work, but obviously comes with a O(n^2) time complexity. For that, Leetcode will not pass your solution, and we don’t like an algorithm at O(n^2). OK, then there must be something nicer and quicker to do the job. Let’s think about it.</p>


<p>Assume <code>n</code> is big enough, at the first round, we switch all bulbs:</p>


<p>[On, On, On, … , On]</p>


<p>At the second round ,we switch every two bulbs:</p>


<p>[On, Off, On, Off, … , On] (if <code>n</code> is an odd number) [On, Off, On, Off, … , Off] (if <code>n</code> is an even number)</p>


<p>At the third round, we switch every three bulbs:</p>


<p>[On, Off, Off, Off, On, On, On, … , Off] (if n is an odd number and it could be divided by 3) [On, Off, Off, Off, On, On, On, … , On] (if n is an odd number and it could not be divided by 3) [On, Off, Off, Off, On, On, On, … , On] (if n is an even number and it could be divided by 3) [On, Off, Off, Off, On, On, On, … , Off] (if n is an even number and it could not be divided by 3)</p>


<p>Hmmm, cannot get any pattern till now. But we can see, as the count of round goes up, the former part of array will not be touched anymore. Let’s give a position number to all the bulbs, starting from <code>1</code> to <code>n</code>.</p>


<p>[1, 2, 3, …, n]</p>


<p>And switch the words <code>one</code>, <code>two</code>, <code>three</code> to number <code>1</code>, <code>2</code>, <code>3</code> … <code>n</code>. OK, so before the round reaches a particular number (bulb), it could be switched one or more times. After that, it will remain the same status. How can we know how many times will a bulb be switched? A straight idea is to find its divisors.</p>


<p>It is easy to understand that, in this situation, a number (bulb) will only be reached when the count of round is a divisor of it. You could also call it prime factors. For example:</p>


<ul class="wp-block-list"><li>Bulb at position 6 will be switched at 1st, 2nd, 3rd and 6th round.</li><li>Bulb at position 69 will be switched at 1st, 3rd 23th and 69th round.</li></ul>


<p>And so on! Then we know how to calculate the times of a given number is reached. Suppose we have a good algorithm to get all divisors of a number, we can get the solution to the number much more quicker. From this chart, it seems like a number k will have much less number of divisors: <a href="https://www.math.upenn.edu/~deturck/m170/wk2/divisors.html.">https://www.math.upenn.edu/~deturck/m170/wk2/divisors.html.</a> Maybe the average time complexity will decrease to less than O(n/2)? You loop through all numbers and see if the bulb at this position will be on at last. The code looks like:</p>


<p>However, this solution didn’t pass because it is using too much time. So I had to re-think about the algorithm I applied. I thought it about an hour (yes, very long time) and suddenly noticed that the divisors are all in pairs! This is really an a-ha moment for me when solving this problem. Let’s see:</p>


<ul class="wp-block-list"><li>Position 6: divisors are [1, 6], [2, 3]</li><li>Position 69: divisors are [1, 69], [3, 23]</li></ul>


<p>Did you think of anything? When a bulb is toggled twice, it will be off. So the bulb at #6 and #69 will be off at last. They will not be counted into the number of bulbs are on. But there must be some bulbs remain on when the loop is ended. Which numbers? From the above examples, we can see at least position #1 is on. But why it is one? Because it only have one divisor “1”. Just think a little bit deeper, or you have listed enough examples to observe the divisor pairs, you will find out:</p>


<ul class="wp-block-list"><li>Position 9: divisors are [1, 9], [3, 3]</li><li>Position 16: divisors are [1, 16], [2, 8], [4, 4]</li></ul>


<p>A-ha! A bulb at position with a number which is perfect square will survive! That’s the critical point. If you still not getting, let me explain it.</p>


<p>We are looping all the bulbs, skipping one more bulb after every round; Consider every position has its number, it will only be reached when the round number is a divisor of its position number; Divisor appears in pairs, unless the divisor is a square root of the position number; A square root will only be reached once, bulb will be toggled only once at [square root]th round. At all the other rounds, the bulb will be toggled on-then-off.</p>


<p>The conclusion is, only the bulbs at a position which order number is a perfect square, will the bulb be on at last. We just need to find out how many perfect squares are there in range <code>[1, n]</code> (inclusive). The code will look like:</p>


<p><code>def bulbSwitch(self, n): """ :type n: int :rtype: int """ count = 0 i = 1 while i &lt; n + 1: if i ** 2</code></p>


<p>Why stop when <code>i ** 2</code> greater than <code>n</code>? Because you have already found the square roots of all the perfect squares within the range, no need to loop further. So someone even gave better solution: just <code>return int(math.sqrt(n))</code> and this will be the answer.</p>


<p>That’s it. Please leave any comment if you think I’m wrong or you have suggestions for my expressions (as I’m not a native English speaker, just want to make myself more clear on explaining an algorithm problem).</p>
<p>The post <a href="/2019/10/25/summary-and-thinking-on-bulb-switcher-problem/">Summary and thinking on Bulb Switcher problem</a> appeared first on <a href="/">weijie ou&#039;s scratch pad</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>JavaScript (jQuery AngularJS) Notes</title>
		<link>/2019/10/25/javascript-jquery-angularjs-notes/</link>
		
		<dc:creator><![CDATA[weijie ou]]></dc:creator>
		<pubDate>Fri, 25 Oct 2019 05:54:00 +0000</pubDate>
				<category><![CDATA[Tech]]></category>
		<category><![CDATA[javascript]]></category>
		<guid isPermaLink="false">/?p=11</guid>

					<description><![CDATA[<p>Better way to compare two floats When you compare two floats, you’d better not directly compare them. Because in the calculation handled by computer, some [...]</p>
<p>The post <a href="/2019/10/25/javascript-jquery-angularjs-notes/">JavaScript (jQuery AngularJS) Notes</a> appeared first on <a href="/">weijie ou&#039;s scratch pad</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<h4 class="wp-block-heading">Better way to compare two floats</h4>


<p>When you compare two floats, you’d better not directly compare them. Because in the calculation handled by computer, some minor difference will be introduced into infinities. Try to compare floats if they are equal using:</p>


<pre class="wp-block-code"><code>Math.abs(1 / 3 - (1 - 2 / 3)) &lt; 0.0000001; // true</code></pre>


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


<h4 class="wp-block-heading">Convert data to a particular format</h4>


<p><code>toLocaleString()</code> is good for converting a number to formatted string. You do not need to implement any extra methods yourself, JavaScript has done this for you. For example, you have some price to show in a table, you want to display it in USD currency format, just one line:</p>


<pre class="wp-block-code"><code>// Displays "128,000,000" if in U.S. English locale
var price = 128000000; console.log(price.toLocaleString());</code></pre>


<h4 class="wp-block-heading">Comparing with <code>==</code> and <code>===</code></h4>


<p>Try to compare with <code>===</code> but not <code>==</code>. <code>==</code> will convert the variable for comparison, <code>===</code> will only compare when the two comparators are the same type. Using <code>===</code> can avoid some unexpected behavior.</p>


<p>However, there is one exception. <code>NaN === NaN</code> will always return <code>False</code>. The only way to judge if a variable is to use <code>isNaN()</code></p>


<h4 class="wp-block-heading">Dynamic Binding</h4>


<p>The event handlers can only bind to static elements if you use <code>$(selector).eventHandler(...)</code>.</p>


<p>Try to use <code>$(document).on('eventName', handler(){...}?</code> to bind elements that are dynamically generated.</p>


<h4 class="wp-block-heading">.next(selector)</h4>


<p>Will only give you the next sibling, but not finding the next available element for you.</p>


<p>That is, if the next element is not matching selector, it will return empty. Without a selector, it will just give you the next element in DOM tree.</p>


<p>If you want to find anything in all the siblings, use <code>.nextAll(selector)</code> instead.</p>
<p>The post <a href="/2019/10/25/javascript-jquery-angularjs-notes/">JavaScript (jQuery AngularJS) Notes</a> appeared first on <a href="/">weijie ou&#039;s scratch pad</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Compile &#038; install 32 bit Python 2.7 on 64 bit CentOS 6.5</title>
		<link>/2019/10/24/compile-install-32-bit-python-2-7-on-64-bit-centos-6-5/</link>
		
		<dc:creator><![CDATA[weijie ou]]></dc:creator>
		<pubDate>Fri, 25 Oct 2019 06:00:00 +0000</pubDate>
				<category><![CDATA[Tech]]></category>
		<category><![CDATA[centos]]></category>
		<category><![CDATA[devops]]></category>
		<category><![CDATA[python]]></category>
		<guid isPermaLink="false">/?p=10</guid>

					<description><![CDATA[<p>You might want to compile a version of Python other than shipped one on your CentOS system. For example, running a Python script using a [...]</p>
<p>The post <a href="/2019/10/24/compile-install-32-bit-python-2-7-on-64-bit-centos-6-5/">Compile &amp; install 32 bit Python 2.7 on 64 bit CentOS 6.5</a> appeared first on <a href="/">weijie ou&#039;s scratch pad</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>You might want to compile a version of Python other than shipped one on your CentOS system. For example, running a Python script using a library that only has a 32bit build. Here are the steps on how to compile &amp; install Python 2.7.12 from source code on CentOS 6.5. All operations tested on a clean CentOS 6.5 (AWS AMI: <em>CentOS 6.5 x86_64(HVM) — 20141008–0 — minimal install with cloud helpers plus Intel SRIOV (ami-4dc28f7d)</em>)</p>


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


<p>Firstly, prepare your system for development and compilation:</p>


<p><code>sudo yum groupinstall "Development tools"</code></p>


<p>Please note that you might receive “Group Development tools does not exist” warning if you don’t have proper repositories. Try to install EPEL, CentOS-base or other necessary repositories. Also remember to setup proxies on if your server is in an internal network, otherwise <code>yum</code> will not work to get external resources.</p>


<p>Then, install the libraries required for compiling Python. As we are compiling a 32bit application on a 64bit system, we need to grab 32bit version of all these libraries. On CentOS 6, append ‘.i686’ to the package name for 32bit versions.</p>


<p><code>sudo yum install glibc-devel.i686 glibc-devel zlib-devel.i686 bzip2-devel.i686 openssl-devel.i686 ncurses-devel.i686 sqlite-devel.i686 readline-devel.i686 tk-devel.i686 gdbm-devel.i686 db4-devel.i686 libX11-devel.i686</code></p>


<p>Note that <code>libX11</code> library will be installed by <code>tkinter</code> but not <code>libX11-devel</code>, so we have to install it separately. Now download satisfied version of Python from <a href="https://www.python.org/">python.org</a>. Let’s say put it in your home directory.</p>


<p><code>wget [https://www.python.org/ftp/python/2.7.12/Python-2.7.12.tar.xz](https://www.python.org/ftp/python/2.7.12/Python-2.7.12.tar.xz)</code></p>


<p>Unzip it:</p>


<p><code>unxz Python-2.7.12.tar.xz tar xf Python-2.7.12.tar</code></p>


<p>OK, we are set to start the compilation process. Change directory:</p>


<p><code>cd Python-2.7.12</code></p>


<p>Create a folder for your Python installation:</p>


<p><code>mkdir /opt/python-2.7.12.i686</code></p>


<p>Configure the compile:</p>


<p><code>BASECFLAGS=-m32 LDFLAGS=-m32 CFLAGS=-m32 ./configure --prefix=/opt/python-2.7.12.i686 --enable-shared</code></p>


<p>The <code>-prefix</code> option allows you to install Python in a custom location (instead of <code>/usr/local</code>); <code>--enable-shared</code> option tells <code>make</code> to build both static and dynamic Python libraries. The <code>-m32</code> flags tells the compiler to use 32bit libraries for building. By default, gcc will use 64bit libraries on a 64bit platform.</p>


<p>Make the Python source files:</p>


<p><code>make</code></p>


<p>Search any library if the <code>make</code> failed on some modules (though it should not happen). You can ignore <code>bsddb185</code> and <code>sunaudiodev</code> if you don’t need them. But other modules should be built for a complete functioning Python installation. From <a href="https://gist.github.com/reorx/4067217">https://gist.github.com/reorx/4067217</a> we know these libraries are undocumented or deprecated:</p>


<ul class="wp-block-list"><li><code>bsddb185</code>: Older version of Oracle Berkeley DB. Undocumented. Install version 4.8 instead.</li><li><code>dl</code>: For 32-bit machines. Deprecated. Use ctypes instead.</li><li><code>imageop</code>: For 32-bit machines. Deprecated. Use PIL instead.</li><li><code>sunaudiodev</code>: For Sun hardware. Deprecated.</li><li><code>_tkinter</code>: For tkinter graphy library, unnecessary if you don’t develop tkinter programs.</li></ul>


<p>Another consideraion is, there a bug in ffi.c in Python source code. When I was compiling, make returned an error message like this:</p>


<p><code>/opt/python-3.4.2/Python-3.4.2/Modules/_ctypes/libffi/src/x86/ffi.c:679: undefined reference to `ffi_closure_FASTCALL' /usr/bin/ld: build/temp.linux-x86_64-3.4/opt/python-3.4.2/Python-3.4.2/Modules/_ctypes/libffi/src/x86/ffi.o: relocation R_386_GOTOFF against undefined hidden symbol `ffi_closure_FASTCALL' can not be used when making a shared object</code></p>


<p>This will prevent you from successfully building <code>_ctypes</code> module. Through a little bit search, I found out this is caused by the mixed definition of calls for different platforms (x86 and x64). Some awesome guys provided a patch at <a href="https://bugs.python.org/issue23042">https://bugs.python.org/issue23042</a>. Read through the patch file (<a href="https://bugs.python.org/file39321/ffi.patch">https://bugs.python.org/file39321/ffi.patch</a>) and fix the logic in your <code>ffi.c</code>. In my case, I just need to move one line of <code>#ifdef X86_WIN32</code> upper, before the line <code>else if (cif-&gt;abi == FFI_FASTCALL)</code> near line 678.</p>


<p>After make is succeed, install Python binary into the folder we created before:</p>


<p><code>make install altinstall</code></p>


<p>The <code>altinstall</code> option make sure the new installation will not replace the current version shipped with your system. Now let’s head to the installation folder and run the new built Python:</p>


<p><code>cd /opt/python-2.7.12.i686/bin ./python</code></p>


<p>You might encounter this error message when starting up:</p>


<p><code>libpython2.7.so.1.0: cannot open shared object file: No such file or directory</code></p>


<p>Modify your <code>LD_LIBRARY_PATH</code>, add <code>/opt/python-2.7.12.i686/lib</code> to this environment variable:</p>


<p><code>export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/python-2.7.12.i686/lib</code></p>


<p>You will want to save this export statement into your own bash configure file (usually <code>~/.bashrc</code>) to make the change permanent. I also suggest to create a virtualenv for the new Python installation for further use.</p>


<h4 class="wp-block-heading">REFERENCES</h4>


<p><a href="https://www.iram.fr/IRAMFR/GILDAS/doc/html/gildas-python-html/node36.html">https://www.iram.fr/IRAMFR/GILDAS/doc/html/gildas-python-html/node36.html</a></p>


<p><a href="http://shouro.blogspot.com/2013/07/compile-python27-on-centos-6.html">http://shouro.blogspot.com/2013/07/compile-python27-on-centos-6.html</a></p>


<p><a href="https://bugs.python.org/issue23042">https://bugs.python.org/issue23042</a></p>
<p>The post <a href="/2019/10/24/compile-install-32-bit-python-2-7-on-64-bit-centos-6-5/">Compile &amp; install 32 bit Python 2.7 on 64 bit CentOS 6.5</a> appeared first on <a href="/">weijie ou&#039;s scratch pad</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>How to check Python version (both command-line and programmatically)</title>
		<link>/2016/10/25/how-to-check-python-version-both-command-line-and-programmatically/</link>
		
		<dc:creator><![CDATA[weijie ou]]></dc:creator>
		<pubDate>Tue, 25 Oct 2016 05:39:00 +0000</pubDate>
				<category><![CDATA[Tech]]></category>
		<category><![CDATA[python]]></category>
		<guid isPermaLink="false">/?p=12</guid>

					<description><![CDATA[<p>Sometimes you might want to confirm if your program will run / is running under Python 2.x or 3.x. We have a very simple way [...]</p>
<p>The post <a href="/2016/10/25/how-to-check-python-version-both-command-line-and-programmatically/">How to check Python version (both command-line and programmatically)</a> appeared first on <a href="/">weijie ou&#039;s scratch pad</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Sometimes you might want to confirm if your program will run / is running under Python 2.x or 3.x. We have a very simple way to do the stuff.</p>


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


<h4 class="wp-block-heading">Command Line Method</h4>


<p>It is really easy to confirm a Python version using the option &#8211;version of the interpreter.</p>


<pre class="wp-block-code"><code>ares$ python --version Python 2.7.10
ares$ python3 --version Python 3.5.1</code></pre>


<p>You can also start the interpreter, and see the version information in the welcome message.</p>


<pre class="wp-block-code"><code>ares$ python
Python 2.7.10 (default, Sep 23 2015, 04:34:21)
[GCC 4.2.1 Compatible Apple LLVM 7.0.0 (clang-700.0.72)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>></code></pre>


<h2 class="wp-block-heading">Programmatically Check</h2>


<p>You can also check the version on-the-fly when your program runs. Just a short piece of code:</p>


<pre class="wp-block-code"><code>import sys # if it is Python2.x is_py2=(sys.version_info[0] == 2) # if it is Python3.x is_py3=(sys.version_info[0] == 3)</code></pre>


<p>By integrating the two values, you can check the current running environment and implement compatibility stuffs, such as <code>__unicode__()</code> and <code>__str__()</code> for Python 2.</p>


<p>Let’s take a close look at what <code>sys.version_info</code> returns:</p>


<pre class="wp-block-code"><code>>>> import sys
>>> sys.version_info
sys.version_info(major=2, minor=7, micro=10, releaselevel='final', serial=0)
>>></code></pre>
<p>The post <a href="/2016/10/25/how-to-check-python-version-both-command-line-and-programmatically/">How to check Python version (both command-line and programmatically)</a> appeared first on <a href="/">weijie ou&#039;s scratch pad</a>.</p>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
