Fresh Blurbs by Irakli Nadareishvili
2023-11-24T07:06:41-05:00
https://www.freshblurbs.com/
Irakli Nadareishvili
donotSpamWillNeverRespond@freshblurbs.com
Generative AI In Financial Services
2023-09-06T00:00:00-04:00
http://www.freshblurbs.com/blog/2023/09/06/generative-ai-finance.html
<p>Today I had a fortune to spend some time with Mike Meriton (Co-Founder, EDM Council), Jocelyn Byrne Houle (Sr. Director of Product Management, Securiti), and Christopher J. Napoli (Head of Wealth and Asset Management, Snowflake) to discuss:</p>
<ul>
<li>The challenges of Generative AI in financial services</li>
<li>Evaluating bias and accuracy of Generative AI models</li>
<li>How financial services organizations are benefiting from Generative AI</li>
<li>Building a common data framework to identify and protect sensitive data throughout a complex multi-cloud landscape</li>
<li>Safely sharing data with internal and external stakeholders, including masking and differential privacy</li>
<li>Embedding automated controls to enable your organization to address compliance and other data obligations</li>
</ul>
<p>It was a great discussion, and you can view the video recording below:</p>
<video controls="controls" style="width: 100%" poster="https://d1p9oyod3rb1sr.cloudfront.net/edm-webinar_poster.jpg">
<source src="https://d1p9oyod3rb1sr.cloudfront.net/EDMWebinar_Securiti_09+06+-+Recording.mp4" type="video/mp4" />
Your browser does not support the HTML5 Video element.
</video>
Building API Platforms With Scale
2023-08-25T00:00:00-04:00
http://www.freshblurbs.com/blog/2023/08/25/api-platforms-scale.html
<p>I’ve spent good part of last 15 years designing and building APIs for various large, complex, distributed systems. And I’ve even written couple books about it - <a href="https://www.oreilly.com/library/view/microservice-architecture/9781491956328/">Microservice Architecture</a> and <a href="https://www.oreilly.com/library/view/microservices-up-and/9781492075448/">Microservices Up and Running</a></p>
<p>Despite my many years in the API space and my clear commitment to it, the most significant lesson I’ve learned is this: APIs, in themselves, don’t matter. They are simply interfaces to platforms. What truly matters is our ability to build scalable platforms, as that’s where the real delivery of tangible business value resides. Allow me to explain.</p>
<p><img style="width: 100%" src="/img/content/api-platforms/apis-dont-matter.jpg" /></p>
<p>First, let’s clarify what we mean by “a platform” and “scale”. In the context of this discussion, APIs are individual actions such as making a comment, updating a customer record, or processing a payment. Platforms, on the other hand, should deliver holistic business value. They consist of a carefully curated list of affordances: APIs, events, and operating models. For instance, an accounting platform should provide a comprehensive solution for all the accounting needs of its customers. A customer platform should manage the entire lifecycle of customers, and a commenting platform should oversee all aspects of commenting, including moderation and fraud protection.</p>
<p>Similarly, the term “scale” is used in a very specific context in this post. Here, scalability doesn’t merely refer to handling high read traffic, large data volumes, or intense rate of transactions. While a robust platform should be equipped to manage these, by “scalability”, we primarily mean designing a platform in such a universally applicable manner that it painlessly evolves with time and its users discover various new ways to leverage it—ways that the platform’s creators might never have envisioned. In essence, we’re discussing the use-case scalability of platforms. If we were to liken a platform to a startup business, we’d be interested in understanding how we could scale up its reach beyond its original purpose.</p>
<h2 id="storytime">Storytime</h2>
<p>To illustrate my perspective on APIs and Platforms, I want to tell you a story. A story that starts in the heart of a large enterprise, and in the middle of it is an experienced, dedicated, and brilliant CIO. We will call her Michelle. Michelle is a highly motivated technology executive. She is driven by her passion for efficiency through technological innovation. And she has what she would describe as healthy amount of contempt for any kind of wasteful activities.</p>
<p>On the day in question, Michelle was reviewing organizational-level performance metrics with her leadership team, to identify any wasteful trends. Going through various numbers and dashboards, her heart was starting to sink. It became glaringly apparent that numerous teams within her organization were repeatedly reinventing the wheel. As a seasoned executive, Michelle wasn’t prone to impulsive reactions. However, the data was undeniable — it was a call to action. A renewed emphasis on reuse was imperative. With resolute promptness, she decreed that the central architecture team would henceforth review all major new API endeavors. Their mandate was to pinpoint redundant efforts and grant “permissions to build” only when absolutely warranted.</p>
<p>Typically, these permissions would favor platform projects that encompassed a comprehensive set of unique, cohesively interlinked APIs, providing overarching business value. For example, the accounting division would be responsible for singular API suite to cater to all accounting-related needs. In a similar vein, the Enterprise Customer Platform would serve as the central hub for all API interfaces handling customer data.</p>
<h3 id="total-cost-of-reuse-tcr">Total Cost of Reuse (TCR)</h3>
<p>As Michelle was explaining her new mandate and taking feedback on the implementation details from her team, she noticed that a key leader on her team was silent and had a concerned look on his face. John had been Michelle’s trusted lieutenant for years. He was usually outspoken, and the uncharacteristic silence was troubling. Michelle asked John what was on his mind.</p>
<p>– I am worried about “total cost of reuse in time”, responded John.</p>
<p>“Total Cost of Reuse in Time?”, nobody in the room had ever heard such concept so Michelle asked John to explain what he meant.</p>
<p>John pointed out that when focusing on reuse, there’s a common pitfall: failing to assess the long-term costs and benefits. All too often, we zero in on the immediate advantages of reuse at the point of decision, overlooking the long-term implications of both reuse and centralization. Imagine a scenario where multiple departments in a large company require a particular functionality. Let’s use an online retailer as an example. Suppose all the business units decide they want to launch loyalty and rewards programs. Recognizing this as a need across many divisions, one might conclude that it’s an ideal candidate for reuse. Consequently, a centralized implementation might seem like the best route. At first glance, a centralized approach does appear beneficial. Rather than creating reward functions for retail customers, then again for small business customers, and yet again for large commercial clients, a single, centralized solution seems efficient. It promises to save time and resources. Celebrations all around! Surely everyone’s in for a big holiday bonus, right?</p>
<p>However, let’s project ourselves 3 to 6 months into the future. Suppose the commercial business unit wishes to modify their rewards program or introduce new features because they have found a very financially lucrative opportunity that such modifications would enable. Since the rewards system is centrally managed and universally shared, the following steps become necessary:</p>
<ol>
<li>The commercial business unit cannot make the changes on their own. They need to align with the central Rewards organization’s product roadmap to schedule the desired changes.</li>
<li>If the proposed change isn’t backwards-compatible, the central Rewards organization must communicate with all other business units utilizing the Rewards system to coordinate the changes, ensuring no disruption.</li>
</ol>
<p>This mandatory coordination can considerably delay the commercial business unit’s desired changes. It might extend the waiting period from mere weeks, had they handled it independently, to potentially several months, as they must now sync with both the central Rewards team and numerous other departments.</p>
<p>Over time, as changes accumulate, the initial advantages of system reuse can wane. Each subsequent modification necessitates a coordination effort, causing delays and potentially increasing costs. With a high enough rate of change, the centralized Rewards system might shift from being perceived as a collective asset to a shared burden.</p>
<p>Assessing the benefits of reuse and centralization only at a project’s outset can be misleading. Everything might seem rosy initially, but over an extended timeframe, the complications of change coordination can considerably erode or even negate the initial advantages. This underscores the importance of evaluating the Total Cost of Reuse (TCR) over the long term, rather than merely at the beginning</p>
<p><img style="width: 100%; border: thick solid #e1e4e7;" src="/img/content/api-platforms/rate-of-change.jpg" /></p>
<p>Does acknowledging TCR mean that we should avoid shared services or the creation of central platforms entirely? Not at all. It simply suggests that we need to be keenly aware of the long-term costs of reuse and regularly evaluate a platform throughout its lifecycle. Grasping the implications of TCR helps in devising strategies to manage and mitigate its associated costs</p>
<h3 id="expected-frequency-of-change">Expected Frequency of Change</h3>
<p>In particular, the expected frequency of change stands out as a vital consideration. While TCR suggests that subsequent modifications can render centralization exorbitantly expensive, if we centralize a function that inherently changes infrequently, the later alteration costs might remain lower than the initial benefits of reuse. Hence, the entire initiative could still be worthwhile. This is why we insist that any functionality centralized in a shared platform shouldn’t be expected to undergo frequent changes. Capabilities that evolve slowly are suitable for centralization and reuse. Conversely, those that change often tend to be cost-prohibitive in the long run, even if they address shared needs across many stakeholders</p>
<p>One crucial aspect to consider is the <em>frequency of change</em>. TCR underscores that subsequent modifications can render centralization excessively costly. Thus, centralizing functions that are inherently stable and less subject to change can be advantageous. In these scenarios, the long-term costs of updates might be offset by the upfront benefits of reuse, justifying the effort. Consequently, any functionality integrated into a shared platform should ideally exhibit stability and predictability. Capabilities that evolve at a slower pace are the best fit for centralization and reuse. Conversely, frequently changing capabilities can become financially untenable over time, even if they address the shared concerns of multiple stakeholders</p>
<p>A prime example of focusing on evergreen capabilities is seen in Public Cloud platforms like AWS, Google Cloud, and Azure. They prioritize the development of features that are highly focused and are resistant to need for frequent change. Take AWS’s Simple Storage Service (S3) as a case in point. I’m continually amazed by S3’s journey. Launched approximately 15 years ago primarily for hosting static web resources like CSS files and images, its basic API interface is now employed to construct vast enterprise data lakes, fueling intensive machine-learning projects. Fifteen years ago, it was inconceivable that S3 would serve such advanced purposes—many of these modern applications for S3 simply didn’t exist back then. This epitomizes true platform scalability: developing a platform that users adapt for purposes vastly beyond the original vision of its creators. Designing platforms with such level of evolvability ensures their enduring relevance, and S3’s evolution offers invaluable lessons for other platforms.</p>
<h2 id="three-pillars-of-scalable-api-platforms">Three Pillars of Scalable API Platforms</h2>
<p>The principles of closely monitoring TCR and steering clear of frequently-changing capabilities have distilled into three specific guidelines that we’ve successfully integrated into our practices:</p>
<h5 id="1-platforms-shouldnt-act-as-regulators-of-common-standards-for-applications-built-upon-them">1. Platforms shouldn’t act as regulators of common standards for applications built upon them</h5>
<p>In many large corporations, when teams build platforms (formerly known as “shared enterprise systems”), there’s often an inclination to sidestep the diverse needs of consumers. This is done by directing the platform teams to establish rigid standards on elements like data models and process workflows. This approach rarely succeeds. Firstly, achieving consensus on standardization is such an arduous process that years can be spent refining the standard—a laborious and frequently thankless endeavor. Such delays hinder the timely release of functional, valuable products. Additionally, data model standards are notoriously fragile. Often, by the time a consensus on a standard is achieved, it’s already on the brink of obsolescence.</p>
<p>Contrast this with the S3 platform as a counterexample. S3 doesn’t prescribe a specific data model for file storage and refrains from setting rigid standards. The platform didn’t get bogged down in protracted standard negotiations among its vast user base. Furthermore, it certainly doesn’t dictate the methodology for storing files.</p>
<p>For those aspiring to develop a successful platform, acting as the custodian of data and standards is the last role one should assume. Instead, primary objective ought to be the introduction of universally appealing features. Look at S3’s approach: its creators didn’t convene every web developer to hammer out a standard. They simply rolled out an intuitive solution that resonated with most users. Such universally acceptable features are what platform builders should aim to incorporate. To cater to the unique requirements of platform users, it’s more effective to offer extensibility points within the platform rather than attempting to accommodate every conceivable feature in a “one-size-fits-all” manner.</p>
<h5 id="2-platforms-should-refrain-from-orchestrating-calls-to-other-platforms-on-behalf-of-consumers">2. Platforms should refrain from orchestrating calls to other platforms on behalf of consumers</h5>
<p>The inspiration for this principle can be traced back to the Unix Philosophy of modular software development. Here, the platform (Unix) offers basic utilities, allowing users to freely combine (pipe) them in endless ways. While the platform develops these tools, it makes minimal assumptions about their subsequent combinations. Instead, it focuses on providing standardized inputs and outputs for seamless orchestration. In the realm of platforms, this translates to supplying functionalities as a set of “primitive” (meaning basic and foundational, not unsophisticated) APIs that the consumer can organize, without the platform itself handling any orchestration.</p>
<p>It’s essential to sidestep orchestration, primarily because it implies a predetermined workflow. Workflows, by nature, are fragile and subject to constant changes. The TCR principle warns us to steer clear of elements prone to frequent change. Consider, for instance, an order fulfillment platform. It could either implement various steps of the fulfillment process as APIs, allowing you to construct a sequence that suits your needs, or it might fully implement an end-to-end fulfillment workflow. With the latter, any deviation or customization you require transforms into a coordinated change challenge. While the end-to-end approach might seem like a convenient, ready-made solution initially, it offers only short-lived advantages. In the long term, it becomes a significant contributor to change-associated costs.</p>
<h5 id="3-platforms-must-refrain-from-implementing-consumer-specific-logic">3. Platforms must refrain from implementing consumer-specific logic.</h5>
<p>Building platforms often comes with the allure of trying to be everything to everyone. It’s not uncommon to want to over-deliver, proving the platform’s worth and attempting to encompass more than its intended scope. However, it’s vital to establish a clear boundary between the platform’s core functionalities and the responsibilities of its users, who craft end-user products atop this foundation. Platforms must resist the ‘crowd-pleasing’ pitfall. While initially promising a fully ‘turnkey’ solution might garner interest, becoming an impediment to adaptability in the long run will only sour the experience for both the platform developers and their users.</p>
<p>Consider the difference between S3 and services like Dropbox or Google Drive. Each is successful within its domain, but platforms like Google Drive or Dropbox aren’t typically used for applications like data lakes or fueling machine learning models. Why? Because Dropbox and Google Drive are tailored for specific user experiences, rendering them less adaptable for diverse applications. Despite probably leveraging technology akin to S3’s, their consumer-specific logic limits scalability. In contrast, S3’s success stems from its minimalistic capabilities and its decision not to presuppose its utilization, allowing it unparalleled scalability across a plethora of use-cases.</p>
<h3 id="in-conclusion">In conclusion</h3>
<p>As we wrap up, I’d like to leave you with this one thought. The era of a wild forest of APIs within major corporations has come to an end. The future lies in purpose-built platforms that are self-service and delivered as APIs and Streams. The enduring success of these platforms hinges on their architects’ profound understanding of the Total Cost of Reuse In Time and their adeptness in selecting stable, focused, slow-evolving capabilities to represent strong identity that they define for their platforms.</p>
Advanced Jira Queries (JQL) For Software Delivery Mastery
2023-06-02T00:00:00-04:00
http://www.freshblurbs.com/blog/2023/06/02/useful-jira-queries.html
<p>Whether we like it or not, Atlassian Jira is often the tool of choice to run large software
projects. It may or may not be your kind of a “pie”, but if you have to use it, it’s at least
useful to understand some of the powerful capabilities it provides. Over years, I have come to
sincerely appreciate Jira’s support of flexible quering of its data and ability to create
powerful dashboards with the use of that data, using a proprietary query language - JQL.</p>
<p>Further in this post, we will list some of the advanced query expressions and JQL examples that
have been useful in our experience.</p>
<p>Please note that a lot of examples in this blog post require the presence of
<a href="https://docs.adaptavist.com/sr4js/latest/features/jql-functions">Adaptavist Scriptrunner</a>
functions, which can be easily installed in SaaS version of Jira, via “Applications” and is
a common plugin enabled in self-hosted server addition of Jira, as well.</p>
<h2 id="project-dependencies-stories-of-specific-kind-linked-to-epic-with-conditions">Project Dependencies: Stories of Specific Kind linked to Epic with Conditions</h2>
<p>Let’s say we are analyzing cross-dependencies across projects. More specifically, let’s say
we want to understand regulatory-requirements related dependencies that Shipping has on Billing.
So we want to find all stories with <code class="language-plaintext highlighter-rouge">component=Regulatory</code> in
billing project that are linked to an epic in the Shipping project:</p>
<pre><code class="language-SQL">project = BIL AND type = Story AND Component = Regulatory
AND issueFunction in issuesInEpics("project = SHIP")
</code></pre>
<p>We can also write this query in a more generic way, by reversing subquery
and using parentsOf() function:</p>
<pre><code class="language-SQL">type = Epic AND project = SHIP AND
issueFunction in parentsOf(
"project = BIL AND type = Story AND Component = Regulatory"
)
</code></pre>
<p>This allows to query for any parent/child relationships (e.g. Epic vs Initiative)
and not just Story/Epic one.</p>
<h2 id="bigger-picture-epics-of-stories-satisfying-specific-condition">Bigger Picture: Epics Of Stories Satisfying Specific Condition</h2>
<p>In the previous example, we saw two ways of finding stories for certain kind of epics. Let’s
say we need the opposite - finding epics of certain kind of stories.</p>
<p>An example of this is if we want to create a high-level view of a release. Let’s assume our
teams have a rule that stories must be sized so that they are aligned with release, but sprints
can span multiple releases. In such a scenario, it makes sense to assign release (typically: fixVersion
in Jira) to stories, but not necessarily to epics.</p>
<p>Question: what are topics addressed in a release? Which can be represented in: what are all the epics
that have a closed or in-progress story that has fixVersion of the current release?</p>
<p>Let’s say fixVersion of current release for Billing is BIL_20230605. Then the query we need
may look like the following:</p>
<pre><code class="language-SQL">project = BIL and type = epic issueFunction in linkedIssuesOf("
type in (Story) and fixVersion = 'BIL_20230605' ")
</code></pre>
<p>This JQL should give you all the epics that have at least one story in the specified release (fixVersion).
Such view can be very helpful if you want to get a high-level (epic-level) view of work that is in
the release, rather then getting bogged-down into the detailed view of stories.</p>
Switch Root Partition to SSD On Raspberry Pi
2022-10-03T00:00:00-04:00
http://www.freshblurbs.com/blog/2022/10/03/rpi-root-disk-switch-to-ssd.html
<p>Raspberry Pi (RPi) is a truly amazing and fascinating device, considering how much
power you can get from this tiny device and its amazing versatility. The default and
easiest way to set up an RPi is using an SD card, that you can provision using the official
<a href="https://www.raspberrypi.com/software/">Raspberry Pi Imager</a></p>
<p>Unfortunately, SD cards are fairly slow in both read and write speed, especially compared to
even inexpensive solid-state drives (SSDs). A typical SD card has the read/write spead of
abouy 30Mb/sec, whereas SSD drives can easily do over 300MB/sec. SD cards are also lessi
reliable than their SSD alternatives and generally not recommended for intensive write scenarios.</p>
<p>Raspberry Pi uses two main partitions: boot partition and root partition. As the names would
suggest the former is used to load the operating system, where most runtime data is under the
root partition. In this blog post we explain how to keep boot partition on the SD card, while
moving the root partition to an SSD. In our opinion it gives you the best of both worlds,
without any significant headache.</p>
<p>Please note that in such setup you only need a tiny SD Card of handful GBs in size, since
most work will be switched to SSD, soon after the setup. 32GB was the smallest quality
mini SD card we could find, and what we used, but if you have something even smaller, it
will work just fine. 32GB was the smallest quality
mini SD card we could find, and what we used, but if you have something even smaller, it
will work just fine.</p>
<p>I also like using Ubuntu Servers everywhere (just a personal preference), so that’s what
we use in all examples below. You may need to update some commands if you end-up using
another Linux distribution.</p>
<h2 id="tldr-synopsis">TL;DR Synopsis</h2>
<p>Basic idea is to install everything on SD card, then partition and format a blank SSD
disk with ext4 filesystem. After which we duplicate SD Card’s root partition to the SSD,
change the label of SSD’s disk to “usbssd” and tell RPi, in cmdline.txt config file,
to use the disk with “usbssd” as its root partition, instead of the default, which
is partition labeled “writable” on the SD card.</p>
<h2 id="detailed-instructions">Detailed instructions</h2>
<p>First, let’s make sure you know the device name for both your SD card and SSD drive.
To see all attached devices, run: <code class="language-plaintext highlighter-rouge">sudo lsblk -o UUID,NAME,FSTYPE,SIZE,MOUNTPOINT,LABEL,MODEL</code>
command in your terminal.</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">></span><span class="w"> </span><span class="nb">sudo </span>lsblk <span class="nt">-o</span> UUID,NAME,FSTYPE,SIZE,MOUNTPOINT,LABEL,MODEL
<span class="go">UUID NAME FSTYPE SIZE MOUNTPOINT LABEL MODEL
loop0 squashfs 59M /snap/core20/1627
loop1 squashfs 57.9M /snap/core20/1614
loop2 squashfs 40.6M /snap/snapd/16299
loop3 squashfs 61M /snap/lxd/22761
loop4 squashfs 41.5M /snap/snapd/17032
a7c221ca-e02d-4446-8229-6c6cbd888234 sda 232.9G
mmcblk0 119.1G
5D5B-8026 ├─mmcblk0p1 vfat 256M /boot/firmware system-boot
a7c221ca-e02d-4446-8229-6c6cbd888234 └─mmcblk0p2 ext4 118.8G writable
</span></code></pre></div></div>
<p>In my case, the SSD is named <code class="language-plaintext highlighter-rouge">sda</code> and the SD card is named <code class="language-plaintext highlighter-rouge">mmcblk0</code> with <code class="language-plaintext highlighter-rouge">mcblk0p1</code> being the
boot partition and <code class="language-plaintext highlighter-rouge">mmcblk0p2</code> the root partition, respectively.</p>
<p>Now let’s partition and format our blank disk.</p>
<h3 id="partitioning-and-formatting-the-disk">Partitioning And Formatting The Disk</h3>
<p>To partition the disk, which in my case was blank, we need to use the <code class="language-plaintext highlighter-rouge">fdisk</code> utility:</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">></span><span class="w"> </span><span class="nb">sudo </span>fdisk /dev/sda
</code></pre></div></div>
<p>Since mine was blank, I first created a new partition with the <code class="language-plaintext highlighter-rouge">n</code> command, then accepted all of the
default settings, and finally saved the partition from memory to disk with the <code class="language-plaintext highlighter-rouge">w</code> comamnd, after which
I exited fdisk with the <code class="language-plaintext highlighter-rouge">q</code> command:</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="go">Command (m for help): n
Partition type
p primary (0 primary, 0 extended, 4 free)
e extended (container for logical partitions)
Select (default p): p
Partition number (1-4, default 1): 1
First sector (2048-488397167, default 2048):
Last sector, +/-sectors or +/-size{K,M,G,T,P} (2048-488397167, default 488397167):
Created a new partition 1 of type 'Linux' and of size 232.9 GiB.
Command (m for help): w
The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.
</span></code></pre></div></div>
<p>In your case, your disk pay already have partitions, so make sure to adapt accordingly.</p>
<p>Once we have a single partition on the SSD, it’s time to format it:</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">></span><span class="w"> </span><span class="nb">sudo </span>mkfs.ext4 /dev/sda
<span class="go">mke2fs 1.45.5 (07-Jan-2020)
Found a dos partition table in /dev/sda
Proceed anyway? (y,N) y
Creating filesystem with 61049646 4k blocks and 15269888 inodes
Filesystem UUID: 73c7a0dd-91df-4397-8293-64b94f1f0ca0
Superblock backups stored on blocks:
32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208,
4096000, 7962624, 11239424, 20480000, 23887872
Allocating group tables: done
Writing inode tables: done
Creating journal (262144 blocks): done
Writing superblocks and filesystem accounting information: done
</span></code></pre></div></div>
<p>After the formatting successfuly completes, you may want to double-check the result with <code class="language-plaintext highlighter-rouge">lsblk</code> command:
<code class="language-plaintext highlighter-rouge">sudo lsblk -o UUID,NAME,FSTYPE,SIZE,MOUNTPOINT,LABEL,MODEL</code></p>
<h3 id="duplicating-sds-root-to-ssds">Duplicating SD’s Root to SSD’s</h3>
<p>Since Ubuntu was installed on the SD card, we need to copy all of the data on SD’s root partition, over to
the SSD, before we make a swap. You can do it with a command <code class="language-plaintext highlighter-rouge">dd</code> using a syntax similar to:</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">></span><span class="w"> </span><span class="nb">sudo dd </span><span class="k">if</span><span class="o">=</span>/dev/mmcblk0p2 <span class="nv">of</span><span class="o">=</span>/dev/sda <span class="nv">bs</span><span class="o">=</span>1M <span class="nv">status</span><span class="o">=</span>progress
<span class="go">420478976 bytes (420 MB, 401 MiB) copied, 9 s, 46.6 MB/s
</span></code></pre></div></div>
<p>Please note that we are indicating the root partition of the SD card, after the “if” parameter, as the source
and the single partition on the SSD as the destination.</p>
<p>This dd command will take a while, since it copies entire root partition of the SD card to SSD. This (in addition
to lower cost) is another reason why you shouln’t buy a larg mini SD card, smaller it is quickly this step will
complete.</p>
<p>Alternatively, you can use rsync for the same purpose, which under some conditions may be faster. RSync
way of achieving what you need, would look like the following:</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">></span><span class="w"> </span><span class="nb">sudo mkdir</span> /mnt/ssd
<span class="gp">></span><span class="w"> </span><span class="nb">sudo </span>mount /dev/sda /mnt/ssd
<span class="gp">></span><span class="w"> </span><span class="nb">export </span><span class="nv">src_dir</span><span class="o">=</span><span class="s2">"/"</span>
<span class="gp">></span><span class="w"> </span><span class="nb">export </span><span class="nv">dst_dir</span><span class="o">=</span><span class="s2">"/mnt/ssd"</span>
<span class="gp">></span><span class="w"> </span><span class="nb">sudo </span>rsync <span class="nt">--force</span> <span class="nt">-rltWDEHXAgoptx</span> <span class="nt">--delete</span> <span class="se">\</span>
<span class="go"> --exclude '.gvfs' \
--exclude '/dev/*' \
--exclude '/mnt/clone/*' \
--exclude '/proc/*' \
--exclude '/run/*' \
--exclude '/sys/*' \
--exclude '/tmp/*' \
--exclude 'lost\+found/*' \
</span><span class="gp">$</span>src_dir <span class="se">\</span>
<span class="gp">$</span>dst_dir
<span class="go">
</span></code></pre></div></div>
<p>Once <code class="language-plaintext highlighter-rouge">dd</code> or <code class="language-plaintext highlighter-rouge">rsync</code> is done, we need to fix the label of the partition on the SD drive, since the <code class="language-plaintext highlighter-rouge">dd</code> comand would have set
it to <code class="language-plaintext highlighter-rouge">writable</code> to mimic the SD car and rsync doesn’t set it at all. We do labeling with the following command:</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">></span><span class="w"> </span><span class="nb">sudo </span>e2label /dev/sda <span class="s2">"usbssd"</span>
</code></pre></div></div>
<h3 id="the-swap-of-partitions">The Swap Of partitions</h3>
<p>Last, but most importantly, we need to edit /boot/firmware/cmdline.txt configuration file and replace
<code class="language-plaintext highlighter-rouge">root=LABEL=writable</code> with <code class="language-plaintext highlighter-rouge">root=LABEL=usbssd</code>. Once it’s done, you need to restart your RPi, and after
a restart, everything should work with the root partition now being an SSD.</p>
Ubuntu Developer Setup With Bare Essentials
2022-08-21T00:00:00-04:00
http://www.freshblurbs.com/blog/2022/08/21/ubuntu-dev-environment-zsh-tmux-emacs.html
<p>Ubuntu Linux is a fanstastic operating system for writing wide variety of code, possibly anything
that is not MacOS or iOS code. While my desktop computer is usually a Mac, I always find myself
having a bunch of Ubuntu servers running for various types of coding. Whether it is a Raspberry Pi
(LOVE THEM!) with 8GB of RAM, or a small but super-fast (for what it is) HP EliteDesk 800 G5,
bought second-hand on eBay, with upgraded 64GBs of RAM, or a bunch of small servers on various
cloud providers - developer environments on Ubuntu are a constant presence. And that doesn’t
even include servers that actually run anything public-facing.</p>
<p>With these many Ubuntu servers, I find myself configuring some basics on them, all the time.
Following is a highly-opinionated walk-through of what and how I usually configure before
I even get to things like Docker and Kubernetes.</p>
<h2 id="1-mosh-instead-of-ssh">1. Mosh Instead of SSH</h2>
<p><a href="https://mosh.org/">Mobile Shell (Mosh)</a> is, arguably, an improved variant of SSH, in that it
is extremely resilient towards network interruptions. You can install it and configure firewall
to allow Mosh traffic on the server, with the following code:</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">></span><span class="w"> </span><span class="nb">sudo </span>apt-get <span class="nb">install </span>mosh
<span class="gp">></span><span class="w"> </span><span class="nb">sudo </span>ufw allow mosh
</code></pre></div></div>
<h2 id="2-zsh-instead-of-bash">2. Zsh Instead of Bash</h2>
<p>I spent decades using Bash and over the years developed a very elaborate configuration that met
my needs very closely, so I was super hesistant to switch to Zsh, even after MacOS made the latter
default. However, after finally spending enough time with Zsh and its extremely flexible, rich, and
configurable <a href="https://ohmyz.sh/">Oh My Zsh</a> extensions, it became clear that even two decades of one
person making shell comfortable for themselves cannot match with a vibrant community investing into
the same. I am a happy convert now, so the next thing I do is - install zsh and configure it to my
liking using enormous wealth of plugins provided by Oh My Zsh.</p>
<p>First, let’s make sure it is installed:</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">></span><span class="w"> </span><span class="nb">sudo </span>apt-get <span class="nb">install </span>zsh
<span class="gp">></span><span class="w"> </span>zsh <span class="nt">--version</span>
<span class="go">zsh 5.8
</span></code></pre></div></div>
<p>Make zsh the default shell (instead of bash):</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">></span><span class="w"> </span>chsh <span class="nt">-s</span> <span class="si">$(</span>which zsh<span class="si">)</span>
<span class="go">Password:
</span><span class="gp">></span><span class="w"> </span><span class="nb">exit</span>
</code></pre></div></div>
<p>Please make sure that “chsh” command is run as your non-privileged user and not with <code class="language-plaintext highlighter-rouge">sudo</code>, otherwise you
will make root’s shell zsh, and not yours.</p>
<p>Once you install and enable zsh, you need to exit and re-login to launch it for the first time. Zsh requires
certain amount of configuration when you first launch it:</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="go">This is the Z Shell configuration function for new users,
zsh-newuser-install.
You are seeing this message because you have no zsh startup files
(the files .zshenv, .zprofile, .zshrc, .zlogin in the directory
~). This function can help you with a few settings that should
make your use of the shell easier.
You can:
(q) Quit and do nothing. The function will be run again next time.
(0) Exit, creating the file ~/.zshrc containing just a comment.
That will prevent this function being run again.
(1) Continue to the main menu.
(2) Populate your ~/.zshrc with the configuration recommended
by the system administrator and exit (you will need to edit
the file by hand, if so desired).
--- Type one of the keys in parentheses ---
</span></code></pre></div></div>
<p>I usually hit <code class="language-plaintext highlighter-rouge">(2)</code> since the defaults are a good starting point, and any customizations I may want, I
would do after the installation, anyway. Yyou can choose <code class="language-plaintext highlighter-rouge">(1)</code> and configure things at this point, however,
if you really feel like it and know what you are doing.</p>
<p>Install oh-my-zsh:</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">sh -c "$</span><span class="o">(</span>curl <span class="nt">-fsSL</span> https://raw.github.com/ohmyzsh/ohmyzsh/master/tools/install.sh<span class="o">)</span><span class="s2">"
</span></code></pre></div></div>
<p>Once oh-my-zsh is installed, we need to configure it, which is done via <code class="language-plaintext highlighter-rouge">~/.zshrc</code> file.</p>
<p>The plugins I usually enable are:</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="go">plugins=(git python pip pyenv aws command-not-found docker-compose docker kubectl dirhistory)
</span></code></pre></div></div>
<p>You should also re-source .zshrc configuration with <code class="language-plaintext highlighter-rouge">source ~/.zshrc</code> once you make that change.</p>
<p>But equally importantly, to get everything looking and acting the way I like it, I also install
a very popular zsh theme called <a href="https://github.com/romkatv/powerlevel10k#oh-my-zsh">PowerLevel10K</a>
by running:</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">git clone --depth=1 https://github.com/romkatv/powerlevel10k.git $</span><span class="o">{</span>ZSH_CUSTOM:-<span class="nv">$HOME</span>/.oh-my-zsh/custom<span class="o">}</span>/themes/powerlevel10k
</code></pre></div></div>
<p>and change ZSH_THEME to <code class="language-plaintext highlighter-rouge">ZSH_THEME="powerlevel10k/powerlevel10k"</code> in <code class="language-plaintext highlighter-rouge">~/.zshrc</code> and re-source zsh by running
<code class="language-plaintext highlighter-rouge">source ~/.zshrc</code>. The PowerLevel10K theme is extremely configurable, and the first time you run it, configuration
wizard will run, which will allow you to fine-tune many aspects of the theme.</p>
<h2 id="3-tmux-for-the-win">3. Tmux For The Win</h2>
<p><a href="https://github.com/tmux/tmux/wiki/Getting-Started">Tmux</a> is a fantastic terminal multiplexer
that allows you to run things on the server in tmux session, detach
from the session, without interrupting those processes or a need to move them to background jobs. It also
has great support for creating and managing multiple screen panes, allowing you to be very productive. Getting
proficient in tmux takes a little bit of practice, but it is well worth it. I will share some configuration
and most convenient non-obvious commands I use.</p>
<p>To make most of tmux, I use tmux plugin manager (<a href="https://github.com/tmux-plugins/tpm">tpm</a>)
and install some super-convenient plugins. To install tpm:</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="go">git clone https://github.com/tmux-plugins/tpm ~/.tmux/plugins/tpm
</span></code></pre></div></div>
<p>And my overall <code class="language-plaintext highlighter-rouge">~/.tmux.conf</code> looks like the following:</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="go">unbind C-b
set -g prefix C-o
</span><span class="gp">#</span><span class="w"> </span><span class="nb">split </span>panes using h and v
<span class="go">bind h split-window -h
bind v split-window -v
unbind '"'
unbind %
unbind r
bind r source-file ~/.tmux.conf
set -g mouse on
set -g default-terminal screen-256color
unbind r
bind r source-file ~/.tmux.conf
set-environment -g PATH "/usr/local/bin:/bin:/usr/bin"
set -g @plugin 'tmux-plugins/tpm'
set -g @plugin 'tmux-plugins/tmux-sensible'
set -g @plugin 'dracula/tmux'
set -g @dracula-show-powerline true
set -g @dracula-plugins "network cpu-usage ram-usage"
run '~/.tmux/plugins/tpm/tpm'
</span></code></pre></div></div>
<p>Most Tmux keybaord commands start with a tmux “bind key”, by default Ctrl-B, then followed by other key combos.
My configuration, among other things, re-maps tmux command from <code class="language-plaintext highlighter-rouge">Ctrl-B</code> to a much more convenient (in my
opinion) <code class="language-plaintext highlighter-rouge">Ctrl-O</code>. In the rest of this post, I assume you have the same re-mapping. I also map creating
horizontally-split new pane to <code class="language-plaintext highlighter-rouge">C-b h</code> and vertically-split one to <code class="language-plaintext highlighter-rouge">C-b v</code>, which are way easier for me to remember
than the default combinations or other alternatives.</p>
<p>Toward the end of the config file, I enable “Dracula” theme for tmux, which I think is gorgeous, make
Dracula’s prompt display current network connection, CPU and memory utilizations, adding extra coolness
and utility to the whole thing.</p>
<p>You need to run <code class="language-plaintext highlighter-rouge">tmux source ~/.tmux.conf</code> from a tmux session, after you change tmux configuration</p>
<p>Finally, to have tmux run all necessary plugins, please issue commands <code class="language-plaintext highlighter-rouge">Ctrl-O Shift-i</code>. Again this assume
you also re-mapped tmux prefix to <code class="language-plaintext highlighter-rouge">Ctrl-O</code>, from the default <code class="language-plaintext highlighter-rouge">Ctrl-B</code>. In response, you should get
the output:</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="go">TMUX environment reloaded.
Done, press ESCAPE to continue.
</span></code></pre></div></div>
<h3 id="common-very-useful-key-shortcuts-for-tmux">Common, very useful key shortcuts for Tmux</h3>
<p>Since various people choose to use different “bind key” (default is <code class="language-plaintext highlighter-rouge">C-b</code><code class="language-plaintext highlighter-rouge">, but I like </code>C-o<code class="language-plaintext highlighter-rouge"> and some others like </code>C-a`),
in the following examples we will just refer to
the key combo as “bind-key”, but the default is Ctrl-b and in my config it is Ctrl-o. Also all of these
shortcuts assume my configuration, and not defaults:</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">tmux new -s sessionname</code> - create new session</li>
<li><code class="language-plaintext highlighter-rouge">bind-key d</code> - detach from tmux session. Do not use <code class="language-plaintext highlighter-rouge">exit</code> or the session will shut down!</li>
<li><code class="language-plaintext highlighter-rouge">tmux a</code> - attach to the latest tmux session</li>
<li><code class="language-plaintext highlighter-rouge">bind-key z</code> - toggle maximizing a pane and returning it to the original size</li>
<li><code class="language-plaintext highlighter-rouge">bind-key spacebar</code> - toggle between various useful preset pane layouts</li>
<li><code class="language-plaintext highlighter-rouge">bind-key o</code> - swap content in panes</li>
<li><code class="language-plaintext highlighter-rouge">bind-key arrowkeys</code> - switch focus between panes</li>
<li><code class="language-plaintext highlighter-rouge">bind-key q</code> - show pane numbers</li>
<li><code class="language-plaintext highlighter-rouge">bind-key q #</code> - switch to specific pane number where # stands for 0,1,2,3…</li>
<li><code class="language-plaintext highlighter-rouge">bind-key w</code> - preview session and window</li>
<li><code class="language-plaintext highlighter-rouge">bind-key x</code> - kill the active pane</li>
<li><code class="language-plaintext highlighter-rouge">bind-key ?</code> - see all shortcuts, if you forget any!</li>
</ul>
<h2 id="4-emacs-with-a-twist">4. Emacs, With a Twist.</h2>
<p>Installing emacs is fairly simple:</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">></span><span class="w"> </span><span class="nb">sudo </span>apt-get <span class="nb">install </span>emacs
<span class="gp">></span><span class="w"> </span>emacs <span class="nt">--version</span> │
<span class="go">GNU Emacs 27.1
</span></code></pre></div></div>
<p>Once emacs is installed, however, we want to run it in daemon mode (as a server) so that
each launch of an editor is just client connecting to the server. This will make emacs
launches significantly faster, and will also help with some aspects of retaining session
between edits.</p>
<p>Let’s create the emacs daemon configuration file at <code class="language-plaintext highlighter-rouge">.config/systemd/user/emacs.service</code>
with <code class="language-plaintext highlighter-rouge">> mkdir -p .config/systemd/user/</code> and <code class="language-plaintext highlighter-rouge">vi .config/systemd/user/emacs.service</code>,
that has following content:</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="go">[Unit]
Description=Emacs text editor
Documentation=info:emacs man:emacs(1) https://gnu.org/software/emacs/
[Service]
Type=forking
ExecStart=/usr/bin/emacs --daemon
ExecStop=/usr/bin/emacsclient --eval "(kill-emacs)"
Environment=SSH_AUTH_SOCK=%t/keyring/ssh
Restart=on-failure
[Install]
WantedBy=default.target
</span></code></pre></div></div>
<p>Try launching it with <code class="language-plaintext highlighter-rouge">systemctl start --user emacs</code> and stopping it with
<code class="language-plaintext highlighter-rouge">systemctl stop --user emacs</code></p>
<p>I usually also have an <code class="language-plaintext highlighter-rouge">emacs-reload</code> script on a path with the following content:</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">#</span><span class="o">!</span>/usr/bin/env sh
<span class="go">
systemctl stop --user emacs && systemctl start --user emacs
</span></code></pre></div></div>
<p>Once we have the daemon running, I usually create an alias for a client script and
put it in my ~/.zprofile, which is startup/login script for zsh:</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="go">export TERM="xterm-256color"
</span><span class="gp">export PATH="$</span>HOME/bin:<span class="nv">$PATH</span><span class="s2">"
</span><span class="gp">export PATH="$</span><span class="s2">HOME/.emacs.d/bin:</span><span class="nv">$PATH</span><span class="s2">"</span>
<span class="go">alias em="emacsclient -c"
</span></code></pre></div></div>
<p>To make emacs extra user-friendly for long-time vim users, like myself, make it minimalistically
good-looking by modern code editor standards, provide a wealth of extensions and to use sensible
defaults, I like to use <a href="https://github.com/doomemacs/doomemacs">Doom Emacs</a> configuration framework.</p>
<p>To install Doom Emacs, run:</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">></span><span class="w"> </span><span class="c"># prerequisites:</span>
<span class="gp">></span><span class="w"> </span><span class="nb">sudo </span>apt-get <span class="nb">install </span>ripgrep
<span class="gp">></span><span class="w"> </span><span class="nb">sudo </span>apt-get <span class="nb">install </span>fd-find
<span class="gp">></span><span class="w"> </span>git clone <span class="nt">--depth</span> 1 https://github.com/doomemacs/doomemacs ~/.emacs.d
<span class="gp">></span><span class="w"> </span>~/.emacs.d/bin/doom <span class="nb">install</span>
<span class="go">Installing Doom Emacs!
✓ Created ~/.doom.d/
- Creating ~/.doom.d/init.el
✓ Done!
- Creating ~/.doom.d/packages.el
✓ Done!
Generate an envvar file? (see `doom help env` for details) (y or n) y
</span><span class="gp">></span><span class="w"> </span>Generating envvars file
<span class="go"> ✓ Generated ~/.emacs.d/.local/env
... full printout skipped for brevity ...
✓ Finished! Doom is ready to go!
But before you doom yourself, here are some things you should know:
1. Don't forget to run 'doom sync', then restart Emacs, after modifying
~/.doom.d/init.el or ~/.doom.d/packages.el.
This command ensures needed packages are installed, orphaned packages are
removed, and your autoloads/cache files are up to date. When in doubt, run
'doom sync'!
2. If something goes wrong, run `doom doctor`. It diagnoses common issues with
your environment and setup, and may offer clues about what is wrong.
3. Use 'doom upgrade' to update Doom. Doing it any other way will require
additional steps. Run 'doom help upgrade' to understand those extra steps.
4. Access Doom's documentation from within Emacs via 'SPC h d h' or 'C-h d h'
(or 'M-x doom/help')
Have fun!
</span></code></pre></div></div>
<p>Once Doom Emacs is installed, spend some time with <code class="language-plaintext highlighter-rouge">~/.doom.d/init.el</code> and enable
the packages/extensions you like. One package I always enable is tree-sitter, which
is generic language parser/highlighter, and I put the following configuration
at the bottom of <code class="language-plaintext highlighter-rouge">~/.doom.d/packages.el</code></p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="go">(package! tree-sitter)
(package! tree-sitter-langs)
</span></code></pre></div></div>
<p>and the following at the end of <code class="language-plaintext highlighter-rouge">~/.doom.d/config.el</code>:</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="go">(use-package! tree-sitter
:config
(require 'tree-sitter-langs)
(global-tree-sitter-mode)
</span><span class="gp"> (add-hook 'tree-sitter-after-on-hook #</span><span class="s1">'tree-sitter-hl-mode))
</span></code></pre></div></div>
<p>When emacs is installed, you should sync doom with <code class="language-plaintext highlighter-rouge">doom sync</code> and restart emacs service,
otherwise the daemon/server won’t pick changes up. If you created the shell script above,
then you can do it simply by running <code class="language-plaintext highlighter-rouge">emacs-reload</code>.</p>
<p>Enjoy, and let me know in the comments if you have further tips and tricks for making
your Ubuntu environment minimalistically awesome.</p>
Tailscale With Mullvad VPN
2022-08-10T00:00:00-04:00
http://www.freshblurbs.com/blog/2022/08/10/tailscale-mullvad.html
<p><a href="https://tailscale.com/">Tailscale</a> is a wonderful, modern mesh VPN solution. Generally speaking, you don’t
need another VPN when using Tailscale. Even for tasks like bypassing geo-blocking, you can use their
<a href="https://tailscale.com/kb/1103/exit-nodes/">Exit Node</a> feature, as long as you have a node in the country
that you want to pretend to be in. But you may not always have that option. Which means for such use-cases,
you may need to use generic VPN service, but you probably still want to continue to use Tailscale, so you
will have to be able to combine them in a peaceful way. Since both are a VPN solution, it may not be a trivial
or possible task.</p>
<p>In this post, we explain how to make a popular VPN service Mullvad work with Tailscale.</p>
<p>Unfortunately, you actually cannot use native Mullvad client with Tailscale (confirmed by Mullvad support
as of August, 2022). Instead, you need to use <a href="https://mullvad.net/en/help/wireguard-macos-app/">Wireguard app</a>
and then disallow <code class="language-plaintext highlighter-rouge">100.0.0.0/8</code> and IPv6 from the Mullvad VPN. Since Wireguard app’s settings currently have
no support for a list of disallowed IPs and ranges, you need to retrofit it into allowed list setting, instead.
You can calculate allowed list, based on what you want to disallow, using something like
<a href="https://www.procustodibus.com/blog/2021/03/wireguard-allowedips-calculator/">Wireguard AllowedIPs calculator</a>
tool. If you disallow local IPs and `100.0.0.0/8’ you will end up with something like:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>AllowedIPs = 1.0.0.0/8, 2.0.0.0/8, 3.0.0.0/8, 4.0.0.0/6, 8.0.0.0/7, 11.0.0.0/8, 12.0.0.0/6, 16.0.0.0/4, 32.0.0.0/3, 64.0.0.0/3, 96.0.0.0/6, 101.0.0.0/8, 102.0.0.0/7, 104.0.0.0/5, 112.0.0.0/4, 128.0.0.0/3, 160.0.0.0/5, 168.0.0.0/6, 172.0.0.0/12, 172.32.0.0/11, 172.64.0.0/10, 172.128.0.0/9, 173.0.0.0/8, 174.0.0.0/7, 176.0.0.0/4, 192.0.0.0/9, 192.128.0.0/11, 192.160.0.0/13, 192.169.0.0/16, 192.170.0.0/15, 192.172.0.0/14, 192.176.0.0/12, 192.192.0.0/10, 193.0.0.0/8, 194.0.0.0/7, 196.0.0.0/6, 200.0.0.0/5, 208.0.0.0/4, ::/0
</code></pre></div></div>
<p><img src="/img/content/mullvad-tailscale.png" alt="Wireguard Configuration" /></p>
<p>P.S. Despite many years in Internet technologies, my brain still cannot deal with CIDR syntax, without
too much effort, so if I know a range and need CIDR,
I use: <a href="https://account.arin.net/public/cidrCalculator">ARIN’s awesome CIDR calculator</a>. In case you
were wondering, and would also like to use it…</p>
Fixing Missing Ethernet On Raspberry Pi With Ubuntu
2022-08-07T00:00:00-04:00
http://www.freshblurbs.com/blog/2022/08/07/fix-eth0-rpi-ubuntu.html
<p>Raspberry Pi is an amazing piece of hardware that is absolute joy for all kinds of tech projects, from
setting up IoT controllers, to building local Kubernetes cluster, to just using it as an affordable
Unix Desktop. However, there seems to be a problem with Ethernet (wired internet) connection, at least
with some configurations.</p>
<p>My setup is Raspberry Pi 4 Model B, with both WiFi and Ethernet (LAN) modules, running Ubuntu Server 22.04
LTS from Raspberry Pi Imager. When I set it up, only WiFi (WLan) was showing up in active/available
network connections:</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="go">❯ ifconfig
</span><span class="gp">lo: flags=73<UP,LOOPBACK,RUNNING></span><span class="w"> </span>mtu 65536
<span class="go"> inet 127.0.0.1 netmask 255.0.0.0
</span><span class="gp"> inet6 ::1 prefixlen 128 scopeid 0x10<host></span><span class="w">
</span><span class="go"> loop txqueuelen 1000 (Local Loopback)
RX packets 115 bytes 10120 (10.1 KB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 115 bytes 10120 (10.1 KB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
</span><span class="gp">wlan0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST></span><span class="w"> </span>mtu 1500
<span class="go"> inet 192.xxx.x.xxx netmask 255.255.255.0 broadcast 192.xxx.x.xxx
</span><span class="gp"> inet6 xxxx::xxxx:xxxx:xxxx:xxxx prefixlen 64 scopeid 0x20<link></span><span class="w">
</span><span class="go"> ether xx:xx:xx:xx:xx:xx txqueuelen 1000 (Ethernet)
RX packets 2086 bytes 420357 (420.3 KB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 538 bytes 126622 (126.6 KB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
</span></code></pre></div></div>
<p>Fortunately, there is an easy fix. Or at least there was, in my case, and hopefully something
that will help you, as well. The culprit, for me, was that there was no startup script authenticating
with DHCP server to enable LAN.</p>
<p>To test if the fix will work for you, please run the following command in shell (terminal)
of your RPi:</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="go">sudo dhclient -v
</span></code></pre></div></div>
<p>If everything goes well, you should see eth0 show up:</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="go">❯ ifconfig
</span><span class="gp">eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST></span><span class="w"> </span>mtu 1500
<span class="go"> inet 192.xxx.x.xxx netmask 255.255.255.0 broadcast 192.xxx.x.xxx
</span><span class="gp"> inet6 xxxx::xxxx:xxxx:xxxx:xxxx prefixlen 64 scopeid 0x20<link></span><span class="w">
</span><span class="go"> ether xx:xx:xx:xx:xx:xx txqueuelen 1000 (Ethernet)
RX packets 14549 bytes 2319637 (2.3 MB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 801 bytes 168254 (168.2 KB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
</span><span class="gp">lo: flags=73<UP,LOOPBACK,RUNNING></span><span class="w"> </span>mtu 65536
<span class="go"> inet 127.0.0.1 netmask 255.0.0.0
</span><span class="gp"> inet6 ::1 prefixlen 128 scopeid 0x10<host></span><span class="w">
</span><span class="go"> loop txqueuelen 1000 (Local Loopback)
RX packets 115 bytes 10120 (10.1 KB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 115 bytes 10120 (10.1 KB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
</span><span class="gp">wlan0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST></span><span class="w"> </span>mtu 1500
<span class="go"> inet 192.xxx.x.xxx netmask 255.255.255.0 broadcast 192.xxx.x.xxx
</span><span class="gp"> inet6 xxxx::xxxx:xxxx:xxxx:xxxx prefixlen 64 scopeid 0x20<link></span><span class="w">
</span><span class="go"> ether xx:xx:xx:xx:xx:xx txqueuelen 1000 (Ethernet)
RX packets 2086 bytes 420357 (420.3 KB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 538 bytes 126622 (126.6 KB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
</span></code></pre></div></div>
<p>That is great! Because, usually RPi’s LAN is much faster than the WiFi module.
However, just by running the above command, you cannot get a permanent solution.
Indeed, your network will still be gone, after a restart.</p>
<p>To make sure your network is always available, we need to run the command on
the machine boot. There are multiple ways to do this on Ubuntu, but I think
the most straightforward is to use Cron.</p>
<p>Run following command to edit root cron:</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="go">sudo crontab -e
</span></code></pre></div></div>
<p>and on a new line, at the end, add the following line:</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="go">@reboot dhclient -v
</span></code></pre></div></div>
<p>After you save the file, you should be all set! The network should last even after a restart.</p>
Testing In Prod vs. Unit Tests
2020-12-14T00:00:00-05:00
http://www.freshblurbs.com/blog/2020/12/14/test-coverage-system-resilience-autohealing.html
<p>A lot has been written about the merits of testing complex systems in production. My favorite is the now-famous presentation: <a href="https://www.infoq.com/presentations/testing-production-2018/">Yes, I Test in Production (And So Do You)</a> by <a href="https://www.infoq.com/presentations/testing-production-2018/">Charity Majors</a>. The main premise of which is that it’s impossible to recreate live (production)-system conditions in pre-production, so pre-production testing is always flawed and we end-up having to test quite a lot once system is already live. As Charity puts it: “They do test in prod, they just don’t admit it”, where by “they” she means everybody who thinks they can test systems before production enough that nothing would be left to post-going-live testing.</p>
<p>I have spent last several years being responsible for the development of core financial systems of one of the largest financial institutions in the United States. Arguably but very likely, financial industry is one of the most regulated industries with high emphasis on systems resiliency, so if anybody is not leaving anything for a chance - that would be us (maybe only second to aviation industry and NASA). So - do we test in production? Yes, we do. And we also do a lot of testing before going to production, but most importantly: what these two different kind of tests protect us from is the critical nuance that I would like to address in this short blog post.</p>
<p>Let’s get one fact out of the way: I don’t know any serious practitioner of system resiliency that believes it to be possible to catch all problems (bugs) before going live with a complex system. It’s noble to want to create 100% issue-free systems, but it is simply impossible. Being in denial doesn’t help either. Accepting reality and working with it, creating systems that can: quickly detect problems, limit the blast radius of the problems, and ideally can self-heal is the way here. Much of Charity’s talk addressed how to quickly detect and analyze problems through investing in observability.</p>
<p>When “testing in production” we also make sure the blast radius of problems is limited. Which is why every time we launch a systems we do it using <a href="https://martinfowler.com/bliki/CanaryRelease.html">canary releases</a>, <a href="https://martinfowler.com/bliki/BlueGreenDeployment.html">blue green deployments</a> and silent parallel runs. A Silent Parallel Run is when we run the old and the new systems in parallel for some reasonable time. Initially, only old system is serving customer traffic. We start sending the same traffic to the new system as well, but the reactions and responses from the new system are only used for validating the proper behavior of the new system (e.g. by comparing it to the output of the old system, when possible). Once we are confident in the correctness of the new system, it can gradually start accepting increasing amount of customer traffic. All of this happens in production, and can be quite a grueling process, but automation helps a ton and also–the safety of testing your systems with actual customer conditions is simply priceless. A lot goes into making sure financial systems are reliable. Many of those things, indeed, need to be performed in production.</p>
<p>Does this mean we can stop testing before going live? If we test so much in production, do we still need substantial number of unit-tests, integration tests and all the other forms of pre-production tests? Or are they just a waste of time and we would be better off getting our code to production, as soon as possible? You know - where we can actually test things?</p>
<p>Our answer to this questions is that, despite enormous emphasis we have on in-production testing, we still write a lot of automated tests before code ever reaches production space. As a matter of fact, code that our teams write have higher level of test coverage than any other code, anywhere else that I have worked at. We monitor test coverage levels and quality, and are pretty insistent on maintaining those tests. So, why do we do it?</p>
<p>To put it bluntly: for us, test-coverage means very little for production resilience. Production resilience is all about self-healing and testing in production (Canary, blue/green, parallel runs etc.). The reason we still insist on high levels of test coverage is that: it makes our systems evolvable in the future! Once we need to change system’s known functionality, automated tests help us detect if a change causes some hidden ripple effects, in the known functionality. Knowing if we violated any prior assumptions - that is what we write automated tests for!</p>
<p>As far as I am concerned, automated tests are for the ability of changing a system in the future. It has very little benefit for the present. And that really is the critical nuance we use in differentiating automated, pre-production tests from in-production testing. Hope other teams can find this perspective useful in their work, as well.</p>
Installing Docker Toolkit On Ubuntu
2020-08-14T00:00:00-04:00
http://www.freshblurbs.com/blog/2020/08/14/docker-via-snap-ubuntu-20.html
<p>Since Docker runs natively on Linux, it is usually much easier to install
than on Mac or Windows machines. There are, however some quirks and details
to be aware of. We cover couple of those in the following blog post.</p>
<h3 id="what-is-the-easiest-way-to-get-docker-on-ubuntu">What is the easiest way to get Docker on Ubuntu?</h3>
<p>Docker is available in apt repos, and is thus fairly easy to install
on Ubuntu. However, if you use apt for the installation, you won’t get
docker-compose. Now, docker-compose is very valuable, especially for local
development.</p>
<p>The quickest way to install a complete Docker tooolkit
on Ubuntu 18.x (Bionic Beaver) or Ubuntu 20.x (Focal Fossa) is
by using Snap:</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">></span><span class="w"> </span><span class="nb">sudo </span>snap <span class="nb">install </span>docker
<span class="gp">></span><span class="w"> </span><span class="nb">echo</span> <span class="s1">'export PATH="/snap/bin:$PATH"'</span> <span class="o">>></span> ~/.bashrc <span class="o">&&</span> <span class="nb">source</span> ~/.bashrc
</code></pre></div></div>
<p>There is, however, an additional highly-recommended step that you probably
want to perform. You see, by default Docker runs as root, and that is not
very secure. You can make docker run as unprivileged user (e.g. your ssh
user) by running following simple commands:</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">></span><span class="w"> </span><span class="nb">sudo </span>groupadd docker
<span class="gp">></span><span class="w"> </span><span class="nb">sudo </span>usermod <span class="nt">-aG</span> docker <span class="nv">$USER</span>
</code></pre></div></div>
<p>You do have to logout after running these commands, for them to take effect.
And by that, I don’t mean logging-out of just SSH connection, but actually
logging your user out. To be safe, it may be a good idea to restart the server,
if you can. Once you do that, you will be able to run all docker and docker-compose
commands using your unpriviledged user, not: root.</p>
<p>And that’s pretty much all it takes to get docker toolchain on Ubuntu.</p>
Gunicorn's Start/Stop Script
2020-05-15T00:00:00-04:00
http://www.freshblurbs.com/blog/2020/05/15/flask-gunicorn-start-stop-script.html
<p><a href="https://flask.palletsprojects.com/en/1.1.x/">Flask</a> is a very popular framework
that is widely used to create APIs in Python. <a href="https://gunicorn.org/">Gunicorn</a>
is a WSGI HTTP Server that many use to launch their Python/Flask programs
behind a web server. In production use, you are probably launching gunicorn in a
daemon-ized mode, with multiple worker threads. Unfortunately, gunicorn does not
have an easy way to stop those worker threads later.</p>
<p>Below is a start/stop script in a Makefile format that provides an elegant
solution to this challenge:</p>
<pre><code class="language-GNUmakefile">default: start
module:=helloservice
app:=api
.PHONY: start
start:
@ ./venv/bin/gunicorn -b "0.0.0.0:8123" \
-w 4 --daemon ${module}:${app}
.PHONY: show
show:
ps -ef | grep -i gunicorn
.PHONY: stop
stop:
@ for pid in \
$$(ps -eo pid,command | grep "gunicorn.*${module}:${app}" \
| grep -v grep | awk '{print $$1}'); do \
kill -9 $${pid}; \
done
</code></pre>
<p>In case you are wondering, this assumes that your code is in a file
called helloservice.py, and in its simplest form may look something
like the following:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">flask</span> <span class="kn">import</span> <span class="n">Flask</span>
<span class="n">api</span> <span class="o">=</span> <span class="n">Flask</span><span class="p">(</span><span class="n">__name__</span><span class="p">)</span>
<span class="o">@</span><span class="n">api</span><span class="p">.</span><span class="n">route</span><span class="p">(</span><span class="s">'/'</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">hello</span><span class="p">():</span>
<span class="k">return</span> <span class="s">"Hello World!"</span>
<span class="o">@</span><span class="n">api</span><span class="p">.</span><span class="n">route</span><span class="p">(</span><span class="s">'/<name>'</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">hello_name</span><span class="p">(</span><span class="n">name</span><span class="p">):</span>
<span class="k">return</span> <span class="s">"Hello {}!"</span><span class="p">.</span><span class="nb">format</span><span class="p">(</span><span class="n">name</span><span class="p">)</span>
<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">'__main__'</span><span class="p">:</span>
<span class="n">api</span><span class="p">.</span><span class="n">run</span><span class="p">()</span>
</code></pre></div></div>
<h2 id="bonus-pythons-virtual-environments-and-direnv">Bonus: Python’s Virtual Environments and Direnv</h2>
<p>If you have been writing in Python for a while you probably already know
that you want to write each application in its own virtual environment (or
a Docker container, but that’s a separate topic). Creating a virtual
environment, if you already have Python3 installed is very easy:</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="go">python3 -m venv venv
</span></code></pre></div></div>
<p>will create a folder “venv” in the current directory that allows you to
activate the virtual environment with an easy:</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="go">source venv/bin/activate
</span></code></pre></div></div>
<p>Once activated, “python” will point to the python3 version from the virtual
environment, so will “pip” and anything you install will be confined to that
virtual environment.</p>
<p>You can just as easily de-activate the virtual environment by writing</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="go">deactivate
</span></code></pre></div></div>
<p>while in the active environment.</p>
<p>Pretty sweet, but can we make it even better? What if the environment activated
itself when you entered the folder (in terminal) and de-activated when you
switch to some other folder? Not bad?</p>
<p>You can do all of that with the <a href="https://direnv.net/">direnv</a> utility. To make
it happen:</p>
<ol>
<li>Install “direnv” (e.g. <code class="language-plaintext highlighter-rouge">sudo apt-get install direnv</code>)</li>
<li>Hook <a href="https://direnv.net/docs/hook.html">direnv into your shell</a> with a
command appropriate for your shell. E.g. for Bash, put <code class="language-plaintext highlighter-rouge">eval "$(direnv hook bash)"</code>
in .bashrc</li>
<li>Restart your session so that your shell init script gets activated</li>
<li>Go to the folder where you want automatic environment. Let’s assume you
already have the “venv” folder there created (if not - follow the steps
earlier in this section i.e. <code class="language-plaintext highlighter-rouge">python3 -m venv venv</code>).</li>
<li>Put activation code into the .venvrc file in that folder:
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="go">. venv/bin/activate
unset PS1
</span></code></pre></div> </div>
</li>
<li>Save the file. You will get an error direnv warning about “.envrc is blocked”</li>
<li>Unblock direnv by running <code class="language-plaintext highlighter-rouge">direnv allow .</code></li>
<li>It should all work at this point. If you exit the folder from terminal,
and enter again - your virtual env will be enabled and it will be disabled
when you switch to somewhere else.</li>
</ol>
<p>Enjoy!</p>
Working in VS Code on iPad
2020-05-03T00:00:00-04:00
http://www.freshblurbs.com/blog/2020/05/03/vscode-ipad-development.html
<p>About a year ago I blogged about <a href="https://www.freshblurbs.com/blog/2019/05/27/iPad-Coding-Docker-Golang.html">how to turn iPad Pro into a capable coding
machine</a>
with the help of a remote linux server.</p>
<p>Since then several things have happened:</p>
<ol>
<li>New version of iPad Pros were released with the amazing Magic Keyboard that
is easier to type on, has trackpad and back-lighting, making iPads way nicer for
prolonged, serious work.</li>
<li>Apple has started limiting background applications to 15 minutes of activity.
This creates certain level of annoiance for any SSH client, including the ones
described in my blog post (Mosh is much less effected by it, however).</li>
</ol>
<p>Thankfully, there’s a new, very interesting way to code on iPads using an editor
that is a derivative of everybody’s favorite Visual Studio Code. The VS Code
itself, being a Javascript (well, TypeScript) program, obviously does not run
natively on iPad (and probably won’t any time soon), but there’s <a href="https://github.com/cdr/code-server">an open-source
project code-server</a> that allows you to
run, what basically is VS Code, as a server over HTTP(S) and to securely connect
to it in Safari browser.</p>
<p><strong>Note:</strong> since the server runs in foreground, you probably want to launch it
with tmux (e.g. <code class="language-plaintext highlighter-rouge">tmux new -s coder-server</code>) or screen, so it doesn’t hang
up once you disconnect, from your server.</p>
<p>But other than that - all it takes is to:</p>
<ol>
<li>Download the latest tar.gz file from the project releases page with: <code class="language-plaintext highlighter-rouge">wget https://github.com/cdr/code-server/releases/download/3.2.0/code-server-3.2.0-linux-x86_64.tar.gz</code></li>
<li>Extract it with <code class="language-plaintext highlighter-rouge">tar xzvf code-server-3.2.0-linux-x86_64.tar.gz</code></li>
<li>Choosing a custom port of your liking (unless you want to run on the default
8080, but I would not recommend it). Let’s say we like <code class="language-plaintext highlighter-rouge">9797</code></li>
<li>Opening that port up in the firewall with <code class="language-plaintext highlighter-rouge">sudo ufw allow 9797</code> (or: preferrably proxying using Caddy server to https)</li>
<li>Run it on any port of your choosing, say with <code class="language-plaintext highlighter-rouge">./code-server --bind-addr 0.0.0.0:9797</code></li>
<li>Opening the address like <code class="language-plaintext highlighter-rouge">http://165.22.2.89:9797/</code> where we assume that IP
is of your server.</li>
<li>Entering the password you have been given during the server startup
(for security), and enjoying your new awesome IDE.</li>
</ol>
<p>To make sure you don’t have to always start the app from Safari, on your iPad,
just click on “share” when you have it first opened in safari, and then scroll
down to “Add to Home Screen” to turn the website into an “app”.</p>
<p>Once all is done, you should have something like the setup on the
following screenshot:</p>
<p><img src="https://pbs.twimg.com/media/EXEFM-ZXQAEvZ6n?format=jpg&name=small" alt="" /></p>
<p>You may want to also configure HTTPS for your setup, once you know you like it
enough to actually use it regularly. Using Caddy Server’s automatic HTTPS via
Let’s Encrypt is easier for this, in my opinion, than dealing with certificates
yourself.</p>
<p>Thanks to Safari being first-class citizen on iPadOS, your app-ized “VS Code”
will be able to even use split-screen functionality! And obviously, VS Code
has built-in terminal app, so you don’t even have to set up a separate terminal
app or worry about it disconnecting.</p>
<p>Pretty sweet!</p>
<p>P.S. I wrote this blog using the setup described :)</p>
Docker and Kubernetes On Mac/Windows with Multipass
2020-04-19T00:00:00-04:00
http://www.freshblurbs.com/blog/2020/04/19/Multipass-Docker-Mac-Cassandra.html
<p>When <a href="https://docs.docker.com/docker-for-mac/">Docker4Mac</a> and
<a href="https://docs.docker.com/docker-for-windows/">Docker4Windows</a> came out they were
truly revolutionary: bringing the cutting-edge power of Docker to everyday
desktop environments most people use. Eventually they started supporting
Kubernetes as well and it looked like the world could not be more perfect
for a backend web developer, especially those dubbing into microservices.</p>
<p>In reality, the day-to-day experience of using them was quite hit-and-miss. I
use a fairly powerful late 2018s 13” MacBook Pro with i7 CPU and 16GB RAM. And
yet running docker via Docker4Mac certainly affects my battery life, as well as
CPU usage (often expressed in loud fan activity). As for Kubernetes - it gets so
bad that honestly I almost never enable it on my Mac (thankfully you can disable
that portion on Docker4Mac). I’ve heard similar complains from my friends and
co-workers. In addition to significant performance challenges, it’s also
worrisome that Docker4Mac only allows you to install one Docker instance and one
Kubernetes. If you experiment a lot you may want to have more freedome to break
things than just the one you can install/use.</p>
<p>Thankfully, there are alternatives. The obvious one is to install your own VM(s)
with VirtualBox or its commercial alternatives. My experience, however, has been
that these are so heavy - I don’t want to go anywhere near them, anymore.</p>
<p>One of the more interesting alternatives that I have recently started
experimenting with, however, is: <a href="https://multipass.run/">Multipass</a> - a slick
tool from Cannonical, the creators of Ubuntu, that allows you to very quckly
launch Ubuntu containers on your Mac, Windows (or even Linux). Multipass
supports a number of underlying VMs, but most importantly it defaults to
HyperKit on Mac, and Hyper-V on Windows, which are the more lightweight
ones, in my experience.</p>
<h3 id="installing-multipass">Installing Multipass</h3>
<p>Multipass installers, for various platforms, can be downloaded from their
website: https://multipass.run/. Once you have it installed, following are some
interesting things you can do on Mac (I am sure instructions on Windows are).</p>
<p>To launch a new ubuntu environment:</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="go">→ multipass launch docker
Launched: docker
→ multipass list
Name State IPv4 Image
docker Running 192.168.64.3 Ubuntu 18.04 LTS
</span></code></pre></div></div>
<p>By default multipass allocates 1GB RAM, 5GB Disk, and 1 CPU core to the new
machine. These may not be sufficient. In my experience, if you are using
something like Node.js or Python with MySQL, 1GB may be ok, but if you start
using heavy Java applications with Java-based DB systems such as Cassandra, you
need more memory. We can override the defaults at launch:</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="go">→ multipass launch -m 4G -n dubuntu
Launched: dubuntu
→ multipass list
Name State IPv4 Image
docker Running 192.168.64.3 Ubuntu 18.04 LTS
dubuntu Running 192.168.64.4 Ubuntu 18.04 LTS
→ multipass exec dubuntu -- bash
</span><span class="gp">To run a command as administrator (user "root"), use "sudo <command></span><span class="s2">".
</span><span class="go">See "man sudo_root" for details.
</span><span class="gp">ubuntu@dubuntu:~$</span><span class="w"> </span>free <span class="nt">-m</span>
<span class="go"> total used free shared buff/cache available
Mem: 3945 79 3640 0 225 3653
</span></code></pre></div></div>
<p><em>Caution:</em> while multipass does allow indicating more than one CPU with say
“-c 2”, it resulted in broken containers for me, on Mac. I assume it may have
something to do with limitations on Hypervisor implementation, but proceed
with caution. Increasing memory has been a no problem.</p>
<p>You could also increase memory of an existing container, e.g. if you launched
one and later found-out that you are running out of RAM but don’t want to
reinstall everything already set up. You have to be careful, since this process
can be fragile, but generally speaking you need to stop multipass process via
launchctl (otherwise it will overwrite your changes), edit configuration JSON and
relaunch the multipass process:</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="go">→ sudo launchctl unload /Library/LaunchDaemons/com.canonical.multipassd.plist
→ sudo vi "/var/root/Library/Application Support/multipassd/multipassd-vm-instances.json"
→ sudo launchctl load /Library/LaunchDaemons/com.canonical.multipassd.plist
</span></code></pre></div></div>
<p>The JSON file you will be editing (<code class="language-plaintext highlighter-rouge">multipassd-vm-instances.json</code>) should look
something like:</p>
<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
</span><span class="nl">"dubuntu"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="nl">"deleted"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w">
</span><span class="nl">"disk_space"</span><span class="p">:</span><span class="w"> </span><span class="s2">"5368709120"</span><span class="p">,</span><span class="w">
</span><span class="nl">"mac_addr"</span><span class="p">:</span><span class="w"> </span><span class="s2">"52:54:00:27:53:b4"</span><span class="p">,</span><span class="w">
</span><span class="nl">"mem_size"</span><span class="p">:</span><span class="w"> </span><span class="s2">"4294967296"</span><span class="p">,</span><span class="w">
</span><span class="nl">"metadata"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="p">},</span><span class="w">
</span><span class="nl">"mounts"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
</span><span class="p">],</span><span class="w">
</span><span class="nl">"num_cores"</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w">
</span><span class="nl">"ssh_username"</span><span class="p">:</span><span class="w"> </span><span class="s2">"ubuntu"</span><span class="p">,</span><span class="w">
</span><span class="nl">"state"</span><span class="p">:</span><span class="w"> </span><span class="mi">4</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>
<p>As you might guess, <code class="language-plaintext highlighter-rouge">mem_size</code> is what you want to override (in bytes). To avoid
headaches I would recommend indicating number that is properly devisible by one
GB. Since one GB is: <code class="language-plaintext highlighter-rouge">1024*1024*1024 = 1073741824</code> bytes, you should indicate
number that is multiple of 1073741824, e.g. for 8GB enter <code class="language-plaintext highlighter-rouge">1073741824 * 8 =
8589934592</code></p>
<h4 id="entering-the-container-and-mapping-folders">Entering the container and mapping folders.</h4>
<p>You can launch any command withing your container by a command like: <code class="language-plaintext highlighter-rouge">multipass
exec <containername> -- <command launched inside></code>. For instance, to see
free memory in the container or launch a bash shell:</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="go">→ multipass exec dubuntu -- free -m
total used free shared buff/cache available
Mem: 3945 77 3640 0 226 3654
Swap: 0 0 0
→ multipass exec dubuntu -- bash
</span><span class="gp">To run a command as administrator (user "root"), use "sudo <command></span><span class="s2">".
</span><span class="go">See "man sudo_root" for details.
</span><span class="gp">ubuntu@dubuntu:~$</span><span class="w"> </span><span class="nb">ls</span> <span class="nt">-al</span>
<span class="go">total 36
drwxr-xr-x 5 ubuntu ubuntu 4096 .
drwxr-xr-x 3 root root 4096 ..
-rw------- 1 ubuntu ubuntu 107 .bash_history
-rw-r--r-- 1 ubuntu ubuntu 220 .bash_logout
-rw-r--r-- 1 ubuntu ubuntu 3771 .bashrc
drwx------ 2 ubuntu ubuntu 4096 .cache
drwx------ 3 ubuntu ubuntu 4096 .gnupg
-rw-r--r-- 1 ubuntu ubuntu 807 .profile
drwx------ 2 ubuntu ubuntu 4096 .ssh
</span><span class="gp">ubuntu@dubuntu:~$</span><span class="w"> </span><span class="nb">exit</span>
<span class="go">exit
→
</span></code></pre></div></div>
<p>You can also make launching a shell of the primary container easier by
indicating which of your containers you want to set as primary and then you
can just type <code class="language-plaintext highlighter-rouge">multipass shell</code>:</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="go">→ multipass set client.primary-name=dubuntu
→ multipass shell
</span><span class="gp">ubuntu@dubuntu:~$</span><span class="w">
</span></code></pre></div></div>
<p>To map your home folder (on Mac) to a folder in the container, you can run:</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">→ multipass mount $</span>HOME dubuntu:/home/ubuntu/mac
<span class="go">Enabling support for mounting -
→ multipass exec dubuntu -- ls -ald mac
drwxr-xr-x 1 ubuntu ubuntu 3936 mac
→ multipass info dubuntu
Name: dubuntu
State: Running
IPv4: 192.168.64.4
Release: Ubuntu 18.04.4 LTS
Image hash: 2f6bc5e7d9ac (Ubuntu 18.04 LTS)
Load: 0.00 0.08 0.07
Disk usage: 1.1G out of 4.7G
Memory usage: 81.9M out of 3.9G
</span><span class="gp">Mounts: /Users/irakli =></span><span class="w"> </span>/home/ubuntu/mac
<span class="go">→ multipass exec dubuntu -- ls -al mac
total 240120
drwxr-xr-x 1 ubuntu ubuntu 3936 .
drwxr-xr-x 6 ubuntu ubuntu 4096 ..
-rw-r--r-- 1 ubuntu ubuntu 10244 .DS_Store
drwx------ 1 ubuntu ubuntu 64 .Trash
drwxr-xr-x 1 ubuntu ubuntu 512 .atom
drwxr-xr-x 1 ubuntu ubuntu 128 .aws
</span></code></pre></div></div>
<h3 id="installing-docker">Installing Docker</h3>
<p>You can install Docker inside a container following the usual Docker
installation process:</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="go">→ multipass shell
</span><span class="gp">ubuntu@dubuntu:~$</span><span class="w"> </span><span class="nb">sudo </span>apt-get update <span class="o">&&</span> <span class="nb">sudo </span>apt-get upgrade <span class="nt">-y</span>
<span class="gp">ubuntu@dubuntu:~$</span><span class="w"> </span><span class="nb">sudo </span>apt-get <span class="nb">install </span>build-essential <span class="nt">-y</span>
<span class="go">
</span><span class="gp">#</span><span class="w"> </span>Sanity Check
<span class="gp">ubuntu@dubuntu:~$</span><span class="w"> </span><span class="nb">sudo </span>apt-get remove docker docker-ce-cli docker-engine docker.io containerd runc
<span class="go">
</span><span class="gp">#</span><span class="w"> </span>Install Docker
<span class="gp">ubuntu@dubuntu:~$</span><span class="w"> </span>curl <span class="nt">-sSL</span> https://get.docker.com/ | sh
</code></pre></div></div>
<p>After completing these steps you should have working docker installation, but
it can only be run as root (via “sudo”) which is both insecure as well as
inconvenient. To fix it you should grant the default, non-privileged user
(<code class="language-plaintext highlighter-rouge">ubuntu</code> for this installation) group access to docker, as shown below. Please
note that you must log out of the Ubuntu and log back in, to have the change
take effect:</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">ubuntu@dubuntu:~$</span><span class="w"> </span><span class="nb">sudo </span>usermod <span class="nt">-aG</span> docker <span class="nv">$USER</span>
<span class="gp">ubuntu@dubuntu:~$</span><span class="w"> </span><span class="nb">exit</span>
<span class="go">logout
→ multipass shell
</span><span class="gp">ubuntu@dubuntu:~$</span><span class="w"> </span>docker ps
<span class="go">CONTAINER ID STATUS IMAGE PORTS NAMES
</span><span class="gp">ubuntu@dubuntu:~$</span><span class="w"> </span>docker version
<span class="go">Client: Docker Engine - Community
Version: 19.03.8
</span><span class="gp">ubuntu@dubuntu:~$</span><span class="w"> </span><span class="nb">sudo </span>curl <span class="nt">-L</span> <span class="s2">"https://github.com/docker/compose/releases/download/1.25.5/docker-compose-</span><span class="si">$(</span><span class="nb">uname</span> <span class="nt">-s</span><span class="si">)</span><span class="s2">-</span><span class="si">$(</span><span class="nb">uname</span> <span class="nt">-m</span><span class="si">)</span><span class="s2">"</span> <span class="nt">-o</span> /usr/local/bin/docker-compose
<span class="gp">#</span><span class="w"> </span>Substitute 1.25.5 with the latest version of Compose.
<span class="go">
</span><span class="gp">ubuntu@dubuntu:~$</span><span class="w"> </span><span class="nb">sudo chmod</span> +x /usr/local/bin/docker-compose
<span class="gp">ubuntu@dubuntu:~$</span><span class="w"> </span>docker-compose <span class="nt">--version</span>
<span class="go">docker-compose version 1.25.5, build 8a1c60f6
</span></code></pre></div></div>
<h3 id="testing-docker">Testing Docker</h3>
<p>Create mysql-stack.yml file:</p>
<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">version</span><span class="pi">:</span> <span class="s1">'</span><span class="s">3.1'</span>
<span class="na">services</span><span class="pi">:</span>
<span class="na">db</span><span class="pi">:</span>
<span class="na">image</span><span class="pi">:</span> <span class="s">mysql</span>
<span class="na">restart</span><span class="pi">:</span> <span class="s">always</span>
<span class="na">environment</span><span class="pi">:</span>
<span class="na">MYSQL_ROOT_PASSWORD</span><span class="pi">:</span> <span class="s">rootPass</span>
<span class="na">ports</span><span class="pi">:</span>
<span class="pi">-</span> <span class="s">33060:3306</span>
</code></pre></div></div>
<p>Launch in a docker container with:</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">ubuntu@dubuntu:~$</span><span class="w"> </span>docker-compose <span class="nt">-f</span> mysql-stack.yml up <span class="nt">-d</span>
<span class="go">
</span><span class="gp">ubuntu@dubuntu:~$</span><span class="w"> </span>docker ps
<span class="go">CONTAINER ID STATUS IMAGE PORTS NAMES
</span><span class="gp">e08f6f072c89 Up 3 seconds mysql 33060/tcp, 0.0.0.0:33060-></span>3306/tcp containers_db_1
</code></pre></div></div>
<h3 id="installing-kubernetes">Installing Kubernetes</h3>
<p>When it comes to installing kubernetes locally, there’re multiple nice options.
Two of my favorites are: Rancher’s k3s and Canonical’s MicroK8s.</p>
<p>With k3s:</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">ubuntu@dubuntu:~$</span><span class="w"> </span>curl <span class="nt">-sfL</span> https://get.k3s.io | sh -
<span class="go">[INFO] Finding release for channel stable
[INFO] Using v1.17.4+k3s1 as release
[INFO] Downloading hash https://github.com/rancher/k3s/releases/download/v1.17.4+k3s1/sha256sum-amd64.txt
[INFO] Downloading binary https://github.com/rancher/k3s/releases/download/v1.17.4+k3s1/k3s
[INFO] Verifying binary download
[INFO] Installing k3s to /usr/local/bin/k3s
</span><span class="c">...
</span><span class="go">
</span><span class="gp">ubuntu@dubuntu:~$</span><span class="w"> </span><span class="nb">sudo </span>k3s kubectl get nodes
<span class="go">NAME STATUS ROLES AGE VERSION
dubuntu Ready master 104s v1.17.4+k3s1
</span></code></pre></div></div>
<p>With MicroK8s (please note that we are adding current user to a group, here
as well, and need to re-login just like we did with Docker):</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">ubuntu@dubuntu:~$</span><span class="w"> </span><span class="nb">sudo </span>snap <span class="nb">install </span>microk8s <span class="nt">--classic</span>
<span class="go">microk8s v1.18.1 from Canonical✓ installed
</span><span class="gp">ubuntu@dubuntu:~$</span><span class="w"> </span><span class="nb">sudo </span>usermod <span class="nt">-a</span> <span class="nt">-G</span> microk8s <span class="nv">$USER</span>
<span class="gp">ubuntu@dubuntu:~$</span><span class="w"> </span><span class="nb">sudo chown</span> <span class="nt">-f</span> <span class="nt">-R</span> <span class="nv">$USER</span> ~/.kube
<span class="gp">ubuntu@dubuntu:~$</span><span class="w"> </span><span class="nb">exit</span>
<span class="go">logout
→ multipass shell
</span><span class="gp">ubuntu@dubuntu:~$</span><span class="w"> </span>microk8s.kubectl get services <span class="nt">--all-namespaces</span>
<span class="go">NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
</span><span class="gp">default kubernetes ClusterIP 10.152.183.1 <none></span><span class="w"> </span>443/TCP 3m22s
</code></pre></div></div>
<h3 id="bonus-installing-cassandra">Bonus: Installing Cassandra.</h3>
<p><em>Note:</em> Cassandra requires more than the default 1GB RAM so make sure your
multipass container has more memory (e.g. 4GB).</p>
<p>First, create a docker-compose.yml file with the following content, anywhere
in the container:</p>
<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">version</span><span class="pi">:</span> <span class="s1">'</span><span class="s">3'</span>
<span class="na">services</span><span class="pi">:</span>
<span class="na">cassandra-seed</span><span class="pi">:</span>
<span class="na">container_name</span><span class="pi">:</span> <span class="s">cassandra-seed</span>
<span class="na">image</span><span class="pi">:</span> <span class="s">cassandra:3.11</span>
<span class="na">ports</span><span class="pi">:</span>
<span class="pi">-</span> <span class="s2">"</span><span class="s">9042:9042"</span> <span class="c1"># Native protocol clients</span>
<span class="c1"># - "7199:7199" # JMX</span>
<span class="c1"># - "9160:9160" # Thrift clients</span>
<span class="na">volumes</span><span class="pi">:</span>
<span class="pi">-</span> <span class="s">local_cassandra_data_seed:/var/lib/cassandra</span>
<span class="na">volumes</span><span class="pi">:</span>
<span class="na">local_cassandra_data_seed</span><span class="pi">:</span>
</code></pre></div></div>
<p>Then run it and check that it worked:</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">ubuntu@dubuntu:~/cassandra$</span><span class="w"> </span>docker-compose up <span class="nt">-d</span>
<span class="go">Creating network "cassandra_default" with the default driver
Creating cassandra-seed ... done
</span><span class="gp">ubuntu@dubuntu:~/cassandra$</span><span class="w"> </span>docker-compose ps
<span class="go">Name Command State Ports
------------------------------------------------------------------------------------------
</span><span class="gp">cassandra-seed docker-entrypoint.sh cassa ... Up 7000/tcp, 7001/tcp, 7199/tcp, 0.0.0.0:9042-></span>9042/tcp, 9160/tcp
<span class="go">
</span><span class="gp">ubuntu@dubuntu:~/cassandra$</span><span class="w"> </span>docker <span class="nb">exec</span> <span class="nt">-it</span> cassandra-seed cqlsh
<span class="go">Connected to Test Cluster at 127.0.0.1:9042.
[cqlsh 5.0.1 | Cassandra 3.11.6 | CQL spec 3.4.4 | Native protocol v4]
Use HELP for help.
</span><span class="gp">cqlsh></span><span class="w"> </span>DESCRIBE keyspaces<span class="p">;</span>
</code></pre></div></div>
Turning iPad Pro Into a Serious Coding Machine
2019-05-27T00:00:00-04:00
http://www.freshblurbs.com/blog/2019/05/27/iPad-Coding-Docker-Golang.html
<p>There is a lot to love about the current iPad Pro - super-fast CPU, beautiful screen, a keyboard that doesn’t need to be charged separately, long battery life and wide selection of apps. Using iPad Pro as an everyday computing device is very tempting, but can it <del>replace</del> substitute your laptop if you are doing some serious coding? For me “serious” coding involves writing containerized microservices and APIs, in a variety of programming languages. To make the experience pleasant I also need coding to not happen in a browser and/or require high-bandwidth/low latency internet connection (not a reality on the go, yet).</p>
<p>I have been contemplating to find an answer to this question, for a while and have been itching to test-drive a user-friendly solution. I am sure I am not alone, either. If you travel for work a lot, you will understand how tempting it is to just grab your iPad and leave a bulky laptop behind. At this point, most things you need, for work or leisure, can be done on an iPad (especially if your work uses Google Suite for office productivity), but what if you need to write some non-trivial code and have nothing but an iPad with you?</p>
<p>Things for me got real on a recent vacation. Determined to take a break, I consciously left a laptop behind and only grabbed iPad with me. And that’s when temptation descended… Having found a tiny bug in one of my open-source projects – <a href="https://github.com/implementing-microservices/gevent-store">an event store implemented in Go</a> I suddenly felt huge urge to figure the setup out. So instead of enjoying a cheesy crime novel on a Kindle, the pool-side time was re-purposed for turning an iPad into a coding <del>beast</del> machine. What follows is a summary of findings. Spoiler alert: it worked and the result is surprisingly workable/awesome/pleasant.</p>
<h2 id="necessary-ingredients">Necessary Ingredients</h2>
<ul>
<li>An iPad Pro with the Apple keyboard. An LTE version is highly recommended so you are not at the mercy of finding a nearby Wi-Fi. Mobile internet connectivity with its instability and low bandwidth is still very usable for the setup, since it does not use much bandwidth and is resilient to intermittent connectivity.</li>
<li>An Ubuntu server you can SSH into. This is where your code will actually execute. After all iPad is still a mobile device with extremely sand-boxed access so yes - you do need this, if you need full flexibility and are doing something advanced. You can use any server, but I personally grabbed a $10/mo DigitalOcean droplet (2 GB RAM / 1 CPU, 50 GB SSD disk 2 TB transfer)</li>
<li><a href="https://itunes.apple.com/us/app/termius-ssh-client/id549039908?mt=8">Termius</a> or <a href="https://itunes.apple.com/us/app/blink-shell-mosh-ssh-client/id1156707581?mt=8">Blink Shell</a> as a shell client. Both of them support <a href="https://mosh.org">Mosh</a> protocol, but Termius also has non-Mosh keep-alive implementation. Overall both are great. I personally like Termius slightly better, especially because I like its tabbed interface for multiple connections. Blink will set you back $20 as one time cost, unless you can figure-out how to install the <a href="https://github.com/blinksh/blink">open-source version</a> on an iPad, yourself. Termius uses in-app purchase so you can try it 14 days for free. After that it becomes pretty expensive with a monthly (or annual) subscription. Please note that
for <code class="language-plaintext highlighter-rouge">ESC</code> key in Termius you can use “CMD+`” combination. Blink Shell allows you to re-purpose Caps Lock as ESC, which is also pretty cool.</li>
<li><a href="https://itunes.apple.com/us/app/textastic-code-editor-7/id1049254261?mt=8">Textastic</a> is a fantastic code editor, at a surprisingly low $10 that supports SFTP and works very nicely with major programming languages, including Go, Python and JavaScript (my favorites). If you are used to VS Code chances are you will like Textastic. This editor is cleverly resilient to poor network connections as it lets you easily download your entire project, edit it locally and then upload necessary files or folders when you are ready. Overall a very reasonable experience.</li>
<li>Since most of the time I write some APIs or microservices using HTTP, a mobile replacement for Postman was a must-have for me and I found a decent one in <a href="https://itunes.apple.com/us/app/httpbot/id1232603544?mt=8">HttpBot</a></li>
</ul>
<h2 id="server-setup">Server Setup</h2>
<p>iPad setup just needs you purchasing the aforementioned apps, so most of the setup is related to setting up your server (I use latest Ubuntu) and connecting the iPad apps to the server properly.</p>
<p>First I installed Mosh on the server. Mosh is an SSH substitute that allows better resilience with intermittent connectivity. Both Termius and Blink Shell support it.</p>
<h3 id="installing-mosh">Installing Mosh</h3>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">></span> <span class="nb">sudo </span>apt-get <span class="nb">install </span>python-software-properties
<span class="o">></span> <span class="nb">sudo </span>add-apt-repository ppa:keithw/mosh
<span class="o">></span> <span class="nb">sudo </span>apt-get update
<span class="o">></span> <span class="nb">sudo </span>apt-get <span class="nb">install </span>mosh
</code></pre></div></div>
<p>You may also need to allow the required UDP ports through a firewall:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># For IP Tables:</span>
<span class="o">></span> <span class="nb">sudo </span>iptables <span class="nt">-I</span> INPUT 1 <span class="nt">-p</span> udp <span class="nt">--dport</span> 60000:61000 <span class="nt">-j</span> ACCEPT
<span class="c"># Or for UFW:</span>
<span class="nb">sudo </span>ufw allow 60000:61000/udp
</code></pre></div></div>
<p><strong>Please note:</strong> while Mosh is generally great, there seems to be some bug with terminal output scroll-back. If you are tailing a large log and need to scroll up (see past messages), I’ve certainly had some issues doing it over a Mosh connection both with Termius and Blink, where doing exact same over an SSH connection was no problem. Please keep that in mind if you run into similar issues.</p>
<h3 id="installing-docker-toolkit">Installing Docker Toolkit</h3>
<p>All code I write these days is containerized. To avoid workspace and environment versioning problems, my code is containerized in local dev environments as well, not just on the servers. Over years I have created <a href="http://nodebootstrap.io">Node</a> and <a href="http://git.justgo.rocks">Go</a> blueprints to make such development easy. Long story short, the first thing we need to do on our server is get Docker and Docker Compose installed:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">></span> <span class="nb">sudo </span>apt-get <span class="nb">install </span>build-essential
<span class="o">></span> <span class="nb">sudo </span>apt-get remove docker docker-ce-cli docker-engine docker.io containerd runc
<span class="o">></span> curl <span class="nt">-sSL</span> https://get.docker.com/ | sh
<span class="o">></span> which docker
<span class="o">></span> <span class="nb">sudo </span>docker-compose ps
</code></pre></div></div>
<p>By default, on Linux, you can only run docker commands via <code class="language-plaintext highlighter-rouge">sudo</code>, which is obviously not great. Per Docker’s own <a href="https://docs.docker.com/install/linux/linux-postinstall/">documentation</a> you need to perform additional steps to fix this:</p>
<blockquote>
<p>The Docker daemon binds to a Unix socket instead of a TCP port. By default that Unix socket is owned by the user root and other users can only access it using sudo. The Docker daemon always runs as the root user.</p>
<p>If you don’t want to preface the docker command with sudo, create a Unix group called docker and add users to it.</p>
</blockquote>
<p>Meaning:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">></span> <span class="nb">sudo </span>groupadd docker
<span class="o">></span> <span class="nb">sudo </span>usermod <span class="nt">-aG</span> docker <username>
</code></pre></div></div>
<p><strong>ATTENTION:</strong> replace <code class="language-plaintext highlighter-rouge"><username></code> with your desired non-root username (e.g. “irakli” in my case).</p>
<h3 id="installing-python-3-and-aws-cli">Installing Python 3 and AWS CLI</h3>
<p>A lot of modern toolkit requires Python 3 installation. Linux distributions universally come pre-installed with Python 2. You cannot just upgrade (shouldn’t) since system tooling depends on Python 2, so there’s a bit of work installing Python 3 on Linux to get things like AWS CLI going.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">></span> <span class="nb">sudo </span>apt update
<span class="o">></span> <span class="nb">sudo </span>apt-get <span class="nb">install </span>python3
<span class="o">></span> python3 <span class="nt">--version</span>
<span class="o">></span> <span class="nb">sudo </span>apt <span class="nb">install </span>software-properties-common
<span class="o">></span> <span class="nb">sudo </span>apt-get <span class="nb">install </span>python3-pip
</code></pre></div></div>
<p>Once you have Python 3 you can install AWS CLI as easily as:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo</span> <span class="nt">-H</span> pip3 <span class="nb">install </span>awscli
</code></pre></div></div>
<p>While not strictly required, any Python installation would be incomplete and amateur hour :) if it didn’t include virtualenv and “workon” utilities, so here you are:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">></span> <span class="nb">sudo</span> <span class="nt">-H</span> pip3 <span class="nb">install</span> <span class="nt">--upgrade</span> pip setuptools wheel
<span class="o">></span> <span class="nb">sudo</span> <span class="nt">-H</span> pip3 <span class="nb">install </span>virtualenv
<span class="o">></span> <span class="nb">sudo</span> <span class="nt">-H</span> pip3 <span class="nb">install </span>virtualenvwrapper
<span class="o">></span> <span class="nb">mkdir</span> ~/.virtualenvs
</code></pre></div></div>
<p>and insert the following lines in your <code class="language-plaintext highlighter-rouge">~/.bashrc</code>:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">if</span> <span class="o">[</span> <span class="nt">-f</span> <span class="s2">"/usr/local/bin/virtualenvwrapper.sh"</span> <span class="o">]</span><span class="p">;</span> <span class="k">then
</span><span class="nb">export </span><span class="nv">WORKON_HOME</span><span class="o">=</span>~/.virtualenvs
<span class="nb">export </span><span class="nv">VIRTUALENVWRAPPER_PYTHON</span><span class="o">=</span>/usr/bin/python3
<span class="nb">export </span><span class="nv">VIRTUALENVWRAPPER_VIRRTUALENV</span><span class="o">=</span>/usr/local/bin/virtualenv
<span class="nb">source</span> /usr/local/bin/virtualenvwrapper.sh
<span class="k">fi</span>
</code></pre></div></div>
<p>Once you run <code class="language-plaintext highlighter-rouge">source ~/.bashrc</code> you can create new Python virtual environments simply by executing something like <code class="language-plaintext highlighter-rouge">mkvirtualenv p3-sweetproject</code> and you can switch to pre-existing python environments with something like <code class="language-plaintext highlighter-rouge">workon p3-sweetproject</code> where “p3-sweetproject” is the name of your python virtual environment. Substitute with whatever name you want to use.</p>
<h3 id="one-last-thing-jekyll">One last thing: Jekyll</h3>
<p>If you area Jekyll / Github Pages user, you may appreciate it. To write this blog post on the same iPad and be able to preview my Jekyll-powered blog in comfort, I also added Jekyll to the same Ubuntu server. Here’s what it took:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">></span> <span class="nb">sudo </span>apt-get <span class="nb">install </span>ruby-full build-essential zlib1g-dev
<span class="o">></span> <span class="nb">echo</span> <span class="s1">'# Install Ruby Gems to ~/gems'</span> <span class="o">>></span> ~/.bash_profile
<span class="o">></span> <span class="nb">echo</span> <span class="s1">'export GEM_HOME="$HOME/gems"'</span> <span class="o">>></span> ~/.bash_profile
<span class="o">></span> <span class="nb">echo</span> <span class="s1">'export PATH="$HOME/gems/bin:$PATH"'</span> <span class="o">>></span> ~/.bash_profile
<span class="o">></span> <span class="nb">source</span> ~/.bash_profile
<span class="o">></span> gem <span class="nb">install </span>jekyll bundler
</code></pre></div></div>
<h3 id="personal-touch">Personal touch.</h3>
<p>As a final touch, I also installed my dotfiles on the Ubuntu. You may have your own, or you may be curious enough to see <a href="https://github.com/inadarei/dotfiles">what I use</a>, either way, if you followed along you hopefully have a very capable developer setup on your iPad now (with a bit of help fro Ubuntu and possibly Digital Ocean).</p>
<h2 id="final-thoughts">Final Thoughts</h2>
<p>Overall, I really enjoyed the experience. The only thing that really bugs me is that Apple didn’t make iPad Pro’s keyboard illuminated so in dark environments you can hardly see what you are typing, especially if you use dark mode applications. But other than that I would say the setup allows you to do a lot. In some ways it is even more capable than installing Docker for Mac on your laptop. Docker for Mac immediately makes your Mac laptop run very hot, reduces battery life from 5-6 hours to less than 2 and causes agitation. In contrast, iPad is just fine (well, thanks to the Ubuntu server but still).</p>
<p>Granted, on iPad you don’t really get multi-window experience, but while I would very much like Apple to fix it in general, it wasn’t a huge issue for code writing.</p>
<p>Enjoy your new power developer machine, hope this write-up was useful.</p>
Fun with Python List Comprehensions and Generators
2019-05-07T00:00:00-04:00
http://www.freshblurbs.com/blog/2019/05/07/Python-List-Comprehensions-Generators.html
<p>Python is an incredibly expressive language. It’s also extremely fun to code
in, once you get hang of its idiomatic ways of succinctly expressing complex
expressions.</p>
<p>One of my favorite tricks, in Python, is using list comprehensions for things
that you would be writing long, boring loops for, in more primitive languages.</p>
<p>Let’s consider some fun examples. For most of the code samples, further in
this post, we assume Python 3.7+. We will also be working with this sample
list, as our input:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">products</span> <span class="o">=</span> <span class="p">[</span>
<span class="p">{</span><span class="s">"name"</span><span class="p">:</span> <span class="s">"Bike"</span><span class="p">,</span> <span class="s">"color"</span> <span class="p">:</span> <span class="s">"teal"</span><span class="p">,</span> <span class="s">"price"</span><span class="p">:</span> <span class="s">"311.00"</span><span class="p">},</span>
<span class="p">{</span><span class="s">"name"</span><span class="p">:</span> <span class="s">"Mechanical Keyboard"</span><span class="p">,</span> <span class="s">"color"</span> <span class="p">:</span> <span class="s">"brown"</span><span class="p">,</span> <span class="s">"price"</span><span class="p">:</span> <span class="s">"141.00"</span><span class="p">},</span>
<span class="p">{</span><span class="s">"name"</span><span class="p">:</span> <span class="s">"Frozen Chips"</span><span class="p">,</span> <span class="s">"price"</span><span class="p">:</span> <span class="s">"9.00"</span><span class="p">},</span>
<span class="p">{</span><span class="s">"name"</span><span class="p">:</span> <span class="s">"Shoes"</span><span class="p">,</span> <span class="s">"color"</span> <span class="p">:</span> <span class="s">"red"</span><span class="p">,</span> <span class="s">"price"</span><span class="p">:</span> <span class="s">"218.00"</span><span class="p">}</span>
<span class="p">]</span>
</code></pre></div></div>
<p>Let’s say we would like to create a new list of “labels” that contains formatted
<code class="language-plaintext highlighter-rouge">name - price</code> strings, for the products that are at least $100 or more. The
brute-force (a.k.a. boring and verbose) way would be to write a good ol’ loop:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">labels</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">products</span><span class="p">:</span>
<span class="k">if</span> <span class="p">(</span><span class="nb">float</span><span class="p">(</span><span class="n">p</span><span class="p">[</span><span class="s">'price'</span><span class="p">])</span> <span class="o">></span> <span class="mi">100</span><span class="p">):</span>
<span class="n">labels</span><span class="p">.</span><span class="n">append</span><span class="p">((</span><span class="sa">f</span><span class="s">"</span><span class="si">{</span><span class="n">p</span><span class="p">[</span><span class="s">'name'</span><span class="p">]</span><span class="si">}</span><span class="s"> - </span><span class="si">{</span><span class="n">p</span><span class="p">[</span><span class="s">'price'</span><span class="p">]</span><span class="si">}</span><span class="s">"</span><span class="p">))</span>
<span class="k">print</span> <span class="p">(</span><span class="n">labels</span><span class="p">)</span>
</code></pre></div></div>
<p>which generates output like:</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="go">['Bike - 311.00', 'Mechanical Keyboard - 141.00', 'Frozen Chips - 9.00', 'Shoes - 218.00']
</span></code></pre></div></div>
<p>or we can use list comprehensions for the same, which is more expressive
and significantly more fun:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">fun_labels</span> <span class="o">=</span> <span class="p">[</span>
<span class="sa">f</span><span class="s">"</span><span class="si">{</span><span class="n">p</span><span class="p">[</span><span class="s">'name'</span><span class="p">]</span><span class="si">}</span><span class="s"> - </span><span class="si">{</span><span class="n">p</span><span class="p">[</span><span class="s">'price'</span><span class="p">]</span><span class="si">}</span><span class="s">"</span>
<span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">products</span>
<span class="k">if</span> <span class="nb">float</span><span class="p">(</span><span class="n">p</span><span class="p">[</span><span class="s">'price'</span><span class="p">])</span> <span class="o">></span> <span class="mi">100</span>
<span class="p">]</span>
<span class="k">print</span><span class="p">(</span><span class="n">fun_labels</span><span class="p">)</span>
</code></pre></div></div>
<p>Let’s now assume we would like to apply 20% discount to all products in the list.
A fairly functional, but still boring, code would look something like the
following:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">copy</span>
<span class="k">def</span> <span class="nf">apply_discounts</span><span class="p">(</span><span class="n">product</span><span class="p">):</span>
<span class="n">product</span><span class="p">[</span><span class="s">'price'</span><span class="p">]</span> <span class="o">=</span> <span class="n">product</span><span class="p">[</span><span class="s">'price'</span><span class="p">]</span><span class="o">*</span><span class="mf">0.8</span>
<span class="k">return</span> <span class="n">product</span>
<span class="n">discounted</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="nb">map</span><span class="p">(</span><span class="n">apply_discounts</span><span class="p">,</span> <span class="n">copy</span><span class="p">.</span><span class="n">deepcopy</span><span class="p">(</span><span class="n">products</span><span class="p">)))</span>
</code></pre></div></div>
<p>Please note that we need to use <code class="language-plaintext highlighter-rouge">copy.deepcopy()</code> over the original list unless
we are ok modifying the original, since <code class="language-plaintext highlighter-rouge">map()</code> changes elements in-place.</p>
<p>In contrast, this is what list comprehension way of achieving the same looks
like:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">fun_discounted</span> <span class="o">=</span> <span class="p">[{</span><span class="o">**</span><span class="n">p</span><span class="p">,</span> <span class="s">'price'</span><span class="p">:</span> <span class="n">p</span><span class="p">[</span><span class="s">'price'</span><span class="p">]</span><span class="o">*</span><span class="mf">0.8</span><span class="p">}</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">products</span><span class="p">]</span>
</code></pre></div></div>
<p>Fun! And please note that in this case we are not modifying the original list
so there is no need for a potentially expensive <code class="language-plaintext highlighter-rouge">copy.deepcopy()</code> call!</p>
<p>Moreover, the same technique can be used to add new attributes to the elements
in the list (in case they are dictionaries like in our case). Let’s say we
would like to add <code class="language-plaintext highlighter-rouge">"status": "available"</code> attribute to each element, it would
be the now-familiar:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">fun_mod_prods</span> <span class="o">=</span> <span class="p">[{</span><span class="o">**</span><span class="n">pr</span><span class="p">,</span> <span class="s">'status'</span><span class="p">:</span> <span class="s">"available"</span><span class="p">}</span> <span class="k">for</span> <span class="n">pr</span> <span class="ow">in</span> <span class="n">products</span><span class="p">]</span>
</code></pre></div></div>
<h2 id="generator-expressions">Generator Expressions</h2>
<p>Generators are constructs that yield one element at a time, when iterated over.
We can iterate over them very much like over lists, but while a list actually
allocates space, in memory, for its every element, generators can calculate
their next element on-the-fly, leading to much smaller memory footprint.</p>
<p>For instance, if you have 10,000 products in a list and you need to print-out
“labels” for each one of them with discounted price, using techniques we saw
above, you can write succinct and fun code like following:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">fun_discounted</span> <span class="o">=</span> <span class="p">[{</span><span class="o">**</span><span class="n">p</span><span class="p">,</span> <span class="s">'price'</span><span class="p">:</span> <span class="n">p</span><span class="p">[</span><span class="s">'price'</span><span class="p">]</span><span class="o">*</span><span class="mf">0.8</span><span class="p">}</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">products</span><span class="p">]</span>
<span class="n">fun_labels</span> <span class="o">=</span> <span class="p">[</span><span class="sa">f</span><span class="s">"</span><span class="si">{</span><span class="n">p</span><span class="p">[</span><span class="s">'name'</span><span class="p">]</span><span class="si">}</span><span class="s"> - </span><span class="si">{</span><span class="n">p</span><span class="p">[</span><span class="s">'price'</span><span class="p">]</span><span class="si">}</span><span class="s">"</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">fun_discounted</span><span class="p">]</span>
<span class="k">for</span> <span class="n">label</span> <span class="ow">in</span> <span class="n">fun_labels</span><span class="p">:</span>
<span class="k">print</span> <span class="p">(</span><span class="n">label</span><span class="p">)</span>
</code></pre></div></div>
<p>This reads great, but you can quickly notice how we created two whole lists
in-memory: the <code class="language-plaintext highlighter-rouge">fun_discounted</code> and <code class="language-plaintext highlighter-rouge">fun_labels</code> ones. If we are dealing with
large or complex lists, such extra memory allocation may not be quite desirable.
It’s also unnecessary, because we can easily substitute these lists with
generators, simply by using “()” instead of “[]” in the comprehension expression:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">gen_discounted</span> <span class="o">=</span> <span class="p">({</span><span class="o">**</span><span class="n">p</span><span class="p">,</span> <span class="s">'price'</span><span class="p">:</span> <span class="nb">float</span><span class="p">(</span><span class="n">p</span><span class="p">[</span><span class="s">'price'</span><span class="p">])</span><span class="o">*</span><span class="mf">0.8</span><span class="p">}</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">products</span><span class="p">)</span>
<span class="n">gen_labels</span> <span class="o">=</span> <span class="p">(</span><span class="sa">f</span><span class="s">"</span><span class="si">{</span><span class="n">p</span><span class="p">[</span><span class="s">'name'</span><span class="p">]</span><span class="si">}</span><span class="s"> - </span><span class="si">{</span><span class="n">p</span><span class="p">[</span><span class="s">'price'</span><span class="p">]</span><span class="si">}</span><span class="s">"</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">gen_discounted</span><span class="p">)</span>
<span class="k">for</span> <span class="n">label</span> <span class="ow">in</span> <span class="n">gen_labels</span><span class="p">:</span>
<span class="k">print</span> <span class="p">(</span><span class="n">label</span><span class="p">)</span>
</code></pre></div></div>
<p>As you can notice, the code looks virtually identical, except for three things:</p>
<ol>
<li>In case of the generators we call these “generator expressions” not
“generator comprehensions”, and use parentheses “()” instead of square
brackets “[]” to signify that we are creating generators, not lists.</li>
<li>Generators do not allocate memory for its elements and are memory-efficient.</li>
<li>With generators, pretty much the only thing we can do is iterate over them,
since they do not actually exist in memory. Meaning, you could have
printed-out <code class="language-plaintext highlighter-rouge">fun_labels</code> with <code class="language-plaintext highlighter-rouge">print(fun_labels)</code> but if you try the same with
<code class="language-plaintext highlighter-rouge">print(gen_labels)</code> all you are going to get is a reference to a
generator object, i.e. an output such as:</li>
</ol>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp"><generator object <genexpr></span><span class="w"> </span>at 0x103e11228>
</code></pre></div></div>
<p>In the above code, we explicitely introduced the intermediary <code class="language-plaintext highlighter-rouge">gen_discounted</code>
generator, to demonstrate generators in their simplest form, but we can also
nest generators, avoiding unnecessary extra variables. And, we can break code
onto multiple-lines for better readability:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">gen_labels</span> <span class="o">=</span> <span class="p">(</span>
<span class="sa">f</span><span class="s">"</span><span class="si">{</span><span class="n">p</span><span class="p">[</span><span class="s">'name'</span><span class="p">]</span><span class="si">}</span><span class="s"> - </span><span class="si">{</span><span class="n">p</span><span class="p">[</span><span class="s">'price'</span><span class="p">]</span><span class="si">}</span><span class="s">"</span>
<span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="p">(</span>
<span class="p">{</span><span class="o">**</span><span class="n">p</span><span class="p">,</span> <span class="s">'price'</span><span class="p">:</span> <span class="nb">round</span><span class="p">(</span><span class="nb">float</span><span class="p">(</span><span class="n">p</span><span class="p">[</span><span class="s">'price'</span><span class="p">])</span><span class="o">*</span><span class="mf">0.8</span><span class="p">,</span><span class="mi">2</span><span class="p">)}</span>
<span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">products</span>
<span class="p">)</span>
<span class="p">)</span>
<span class="k">for</span> <span class="n">label</span> <span class="ow">in</span> <span class="n">gen_labels</span><span class="p">:</span>
<span class="k">print</span> <span class="p">(</span><span class="n">label</span><span class="p">)</span>
</code></pre></div></div>
<h3 id="comprehensions-for-dictionaries">Comprehensions for Dictionaries</h3>
<p>Lists are not the only iterable that you can use comprehensions with, in Python.
Let’s see an example where we do it with Dictionaries.</p>
<p>Given a dictionary:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">merch</span> <span class="o">=</span> <span class="p">{</span>
<span class="s">'sid:001'</span><span class="p">:</span> <span class="p">{</span> <span class="s">'name'</span><span class="p">:</span> <span class="s">"pen"</span><span class="p">,</span> <span class="s">'price'</span><span class="p">:</span> <span class="mi">5</span><span class="p">},</span>
<span class="s">'sid:002'</span><span class="p">:</span> <span class="p">{</span> <span class="s">'name'</span><span class="p">:</span> <span class="s">"pencil"</span><span class="p">,</span> <span class="s">'price'</span><span class="p">:</span> <span class="mi">4</span><span class="p">},</span>
<span class="s">'sid:003'</span><span class="p">:</span> <span class="p">{</span> <span class="s">'name'</span><span class="p">:</span> <span class="s">"eraser"</span><span class="p">},</span>
<span class="p">}</span>
</code></pre></div></div>
<p>We can add default price of <code class="language-plaintext highlighter-rouge">2</code> to every item that is missing price with the
following code:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">defaults_applied</span> <span class="o">=</span> <span class="p">{</span>
<span class="n">k</span><span class="p">:</span> <span class="p">{</span><span class="o">**</span><span class="n">merch</span><span class="p">[</span><span class="n">k</span><span class="p">],</span>
<span class="s">'price'</span><span class="p">:</span> <span class="n">merch</span><span class="p">[</span><span class="n">k</span><span class="p">].</span><span class="n">get</span><span class="p">(</span><span class="s">'price'</span><span class="p">,</span> <span class="mi">2</span><span class="p">)}</span>
<span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="n">merch</span>
<span class="p">}</span>
<span class="k">print</span> <span class="p">(</span><span class="n">defaults_applied</span><span class="p">)</span>
</code></pre></div></div>
<h3 id="in-conclusion">In conclusion</h3>
<p>List comprehensions and generator expressions are very expressive and a lot
of fun in Python. I hope I was able to spark your interest in them, with this
blog post and you are going to enjoy them as much as many of us do.</p>
Recommended Visual Studio Extensions
2019-04-07T00:00:00-04:00
http://www.freshblurbs.com/blog/2019/04/07/Visual-Studio-Extensions.html
<p>Visual Studio Code has become an indispensable tool for my daily coding. Largely
due to its great performance, design and productivity, but also partly because
of the collection of great extensions you can find. As a side note, it’s also
fairly easy to write new VS Code extensions if you don’t find what you are
looking for, and I may be guilty of having done that, as well. But that aside
today I decided to share the list of extensions I use in my VS Code
installation, in hopes that somebody may find this useful.</p>
<h3 id="list-of-iraklis-extensions">List of Irakli’s Extensions:</h3>
<ol>
<li><a href="https://marketplace.visualstudio.com/items?itemName=haaaad.ansible">ansible</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=joaompinto.asciidoctor-vscode">asciidoctor-vscode</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=formulahendry.auto-close-tag">auto-close-tag</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=formulahendry.auto-rename-tag">auto-rename-tag</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=HookyQR.beautify">beautify</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=alefragnani.Bookmarks">Bookmarks</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=formulahendry.code-runner">code-runner</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=Shan.code-settings-sync">code-settings-sync</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=Compulim.compulim-vscode-closetag">compulim-vscode-closetag</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=carolynvs.dep">dep</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=rafaelmaiolla.diff">diff</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=joelday.docthis">docthis</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=waderyan.gitblame">gitblame</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=codezombiech.gitignore">gitignore</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=ms-vscode.Go">Go</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=andrejunges.Handlebars">Handlebars</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=Zignd.html-css-class-completion">html-css-class-completion</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=tht13.html-preview-vscode">html-preview-vscode</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=abusaidm.html-snippets">html-snippets</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=mkaufman.HTMLHint">HTMLHint</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=redhat.java">java</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=xabikos.JavaScriptSnippets">JavaScriptSnippets</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=wholroyd.jinja">jinja</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=TomiTurtiainen.js-complexity-analysis">js-complexity-analysis</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=inadarei.json-compact-prettifier">json-compact-prettifier</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=tuxtina.json2yaml">json2yaml</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=cmstead.jsrefactor">jsrefactor</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=inadarei.jwt">jwt</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=ipedrazas.kubernetes-snippets">kubernetes-snippets</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=emilast.LogFileHighlighter">LogFileHighlighter</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=Tyriar.lorem-ipsum">lorem-ipsum</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=christian-kohler.npm-intellisense">npm-intellisense</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=IBM.output-colorizer">output-colorizer</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=ryu1kn.partial-diff">partial-diff</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=christian-kohler.path-intellisense">path-intellisense</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=mohsen1.prettify-json">prettify-json</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=ms-python.python">python</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=2gua.rainbow-brackets">rainbow-brackets</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=xabikos.ReactSnippets">ReactSnippets</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=stkb.rewrap">rewrap</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=tht13.rst-vscode">rst-vscode</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=saviorisdead.RustyCode">RustyCode</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=Tyriar.sort-lines">sort-lines</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=Arjun.swagger-viewer">swagger-viewer</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=qnsolutions.swaggitor">swaggitor</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=krizzdewizz.tag-rename">tag-rename</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=mauve.terraform">terraform</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=Togusa09.tmlanguage">tmlanguage</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=dzannotti.vscode-babel-coloring">vscode-babel-coloring</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=akamud.vscode-caniuse">vscode-caniuse</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=anseki.vscode-color">vscode-color</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=yeluoqiuzhi.vscode-detect-charset">vscode-detect-charset</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=PeterJausovec.vscode-docker">vscode-docker</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=mrmlnc.vscode-duplicate">vscode-duplicate</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=mjmcloug.vscode-elixir">vscode-elixir</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint">vscode-eslint</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=vitorsalgado.vscode-glide">vscode-glide</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=heaths.vscode-guid">vscode-guid</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=deerawan.vscode-hasher">vscode-hasher</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=technosophos.vscode-helm">vscode-helm</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=ecmel.vscode-html-css">vscode-html-css</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=robertohuertasm.vscode-icons">vscode-icons</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=Compulim.vscode-ipaddress">vscode-ipaddress</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-java-debug">vscode-java-debug</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-java-dependency">vscode-java-dependency</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-java-pack">vscode-java-pack</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-java-test">vscode-java-test</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=ms-kubernetes-tools.vscode-kubernetes-tools">vscode-kubernetes-tools</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=jumpinjackie.vscode-map-preview">vscode-map-preview</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=DavidAnson.vscode-markdownlint">vscode-markdownlint</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-maven">vscode-maven</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=shanoor.vscode-nginx">vscode-nginx</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=fknop.vscode-npm">vscode-npm</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=eg2.vscode-npm-script">vscode-npm-script</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=adambaldwin.vscode-nsp">vscode-nsp</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=ziyasal.vscode-open-in-github">vscode-open-in-github</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=Compulim.vscode-qrcode">vscode-qrcode</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=vsmobile.vscode-react-native">vscode-react-native</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=redhat.vscode-yaml">vscode-yaml</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=ms-vscode.wordcount">wordcount</a></li>
</ol>
<h3 id="one-more-thing">One More Thing</h3>
<p>If you decide to publish your own list of extensions and need a quick
way to convert VS Code’s config file (JSON), which contains such list, to
markdown, this is the code I used (Python 3.7):</p>
<pre><code class="language-Python">import json
with open('raw.json') as f:
json_data = f.read()
f.closed
extensions = json.loads(json_data)
url_prefix = "https://marketplace.visualstudio.com/items?itemName="
out = [f"1. [{item['name']}]({url_prefix}{item['metadata']['publisherId']})"
for item in extensions]
print('\n'.join(out))
</code></pre>
Twitter Passwords 'Leak' - A Speculative Explanation
2018-05-04T00:00:00-04:00
http://www.freshblurbs.com/blog/2018/05/04/Twitter-Passwords-Security-Issue.html
<p>Yesterday, most Twitter users got a scary notice that their password could
have been compromised and the company was asking them to change the password
as a precaution:</p>
<p><img src="/img/content/2018-twitter-password-alert.png" alt="" /></p>
<p>This sparked a wide range of emotions on social media (shocker!), significant
number of users being mad at the company and some even questioning the skills
of Twitter’s engineering team…</p>
<p>Let me state some strong personal opinions:</p>
<ol>
<li>
<p>Twitter handled disclosure and mitigation superbly. Regardless of how
you feel about the likely unintentional turn of phrase from their CTO (<a href="https://www.fastcompany.com/40568055/twitter-cto-we-didnt-have-to-tell-users-about-the-password-debacle">source</a>),
the reality is that they didn’t try to hide it under the rug, and that is
uneqiovocally a great thing. Other companies should behave the same way.</p>
</li>
<li>
<p>What happened doesn’t indicate that Twitter lacks engineering skills. It much
more likely was just a very unfortunate sequence of events - a genuine accident.</p>
</li>
</ol>
<p>Specifically; it’s important to understand that at any but the most lousy tech
companies (which Twitter is definitely not) passwords are never stored in
clear-text or even encrypted. They are stored
“<a href="https://simple.wikipedia.org/wiki/Cryptographic_hash_function">hashed</a>”, i.e.
obscured in a way that cannot be ‘decrypted’ even by Twitter. Which means: the
only time clear-text password could be logged was <em>before</em> it was saved in a
database. And that leads us to the most likely scenario: if somebody turned on
logging of all HTTP traffic (with good intentions of monitoring health of the
system), without first excluding traffic that contained passwords, then they
would get the exact problem described in the disclosure: passwords would
unintentionally end-up in the logs. That doesn’t mean that engineers at twitter
are ‘stupid’, because it’s not an architectural/design problem per se, and
neither does it mean that they do not have ‘proper controls’ – such logging can
be turned on via simple misconfiguration and is too easy to miss in code reviews.
If anything, the fact that their monitoring noticed the problem indicates that
they are doing pretty well.</p>
<p>Accidents happen. It is unfortunate, but it is a reality. Nothing in the story
indicates that Twitter did anything careless or wrong. As for us, users we need
to always use two-factor authentication (which Twitter does support) and unique
passwords to protect ourselves from such accidents.</p>
<hr />
<p><strong>Disclaimer:</strong> I have no knowledge of what actually happened at Twitter. I don’t
work there, neither do I have secret sources. Following post is just a for-fun
exercise in guessing the most likely scenario. You can also call it “pure
speculation”, if you really have to.</p>
Serverless Is a Wrong Name. Fight it with FIRE
2018-01-10T00:00:00-05:00
http://www.freshblurbs.com/blog/2018/01/10/Stop-Serverless-Call-It-Fire.html
<p>Ever since the rise of the AWS Lambda, software engineers have been fascinated by the premise of “just writing code” and not having to worry about the execution or scaling of said code. Since then, the term “serverless” has been coined to describe the new class of solutions. We now have similar implementations from other major providers (Azure functions, Google Cloud Functions, IBM Cloud Functions etc.) as well as an impressive list of open-source solutions (<a href="https://github.com/nuclio/nuclio">Nuclio</a>, <a href="https://openwhisk.apache.org/">OpenWhisk</a> etc.) all happily referred to as “serverless”.</p>
<p>There is one big problem with all of this, however - the name “serverless” is a big, silly joke. Everybody admits it. Of course there is no such thing as “serverless” and at the end of the day there is somebody who is running the abstraction layer to get you to ‘serverless’. When that ‘somebody’ is a major cloud provider like AWS, Google, Azure or IBM the name is at least marginaly tollerable (ok, <strong>you</strong> dont have to care about servers), but as soon as we talk about frameworks like Nuclio, OpenWhisk etc. that supposedly you yourself would be running (possibly on a Kubernetes cluster) - the name “serverless” is plain bizarre. Not only you do have to administer your Kubernetes cluster, you also have to administer additional layer on top of it. So what is “serverless”?</p>
<p>Sometimes people use the term “FaaS” (Function-as-a-Service), instead of “serverless”, and it is not a bad name. FaaS pays omage to its predecessor Platform-as-a-Service (PaaS) and acknowledges that a preffered unit of deployment is now a function. However, FaaS is arguably just not “cool enough” and hasn’t taken off too much. So how do we end the silliness behind the term “serverless”?</p>
<p>Here’s an idea, what if we call it <em>Functional, Invocable Runtime Environment</em> or simply: <strong>FIRE</strong>.</p>
<p>Next time you describe what you have been doing, over the weekend, maybe skip the “serverless” thing and just say “I’ve been playing with FIRE”?</p>
<p>Future generations will thank you.</p>
<p>Cheers.</p>
Installing and Running Kubernetes Locally On a MacOS Sierra
2017-05-21T00:00:00-04:00
http://www.freshblurbs.com/blog/2017/05/21/Kubernetes-on-Mac.html
<p><a href="https://kubernetes.io/">Kubernetes</a> is probably the most popular
container-orchestration system, currently. It was originally developed and
eventually open-sourced by Google. Kubernetes competes with the likes of
<a href="https://docs.docker.com/engine/swarm/#whats-next">Swarm</a>,
<a href="https://dcos.io/">DC/OS</a> and AWS’s <a href="https://aws.amazon.com/ecs/">ECS</a>.</p>
<p>Kubernetes is a complex ecosystem of various software components that is
actually quite non-trivial to put together. It can be a great way of
orchestrating containers (e.g. Docker ones) in production, but if you need a
compatible local environment for development, setting such thing up yourself,
from scratch, can be a painful experience. Which is why the community has
created <a href="https://kubernetes.io/docs/getting-started-guides/Minikube/">Minikube</a></p>
<ul>
<li>a Kubernetes distribution for easy local installation.</li>
</ul>
<p>Minikube, by default, still requires a Docker-compatible VM. There are many ways
of getting one, but at the time of this writing, the most straightforward way,
on MacOS Sierra, is the installation of <a href="https://docs.docker.com/docker-for-mac/">Docker for
Mac</a>. The good news is: you won’t need
VirtualBox or some other kind of standalone VM environment to run the
installation.</p>
<p><strong>Note:</strong> some of the following instructions are specific to the component
versions available at the time of writing. If you are reading this post later,
please make sure to use commands that contain updated versions of the
corresponding software.</p>
<p>To run through the commands you will need a working Docker for Mac and
<a href="https://brew.sh/">Homebrew</a>. Make sure to install those, before executing the
following commands.</p>
<p>Once you have Docker for Mac and Homebrew, you can install Minikube:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>brew update
<span class="nv">$ </span>curl <span class="nt">-LO</span> https://storage.googleapis.com/minikube/releases/latest/docker-machine-driver-hyperkit <span class="se">\</span>
<span class="o">&&</span> <span class="nb">chmod</span> +x docker-machine-driver-hyperkit <span class="se">\</span>
<span class="o">&&</span> <span class="nb">sudo mv </span>docker-machine-driver-hyperkit /usr/local/bin/ <span class="se">\</span>
<span class="o">&&</span> <span class="nb">sudo chown </span>root:wheel /usr/local/bin/docker-machine-driver-hyperkit <span class="se">\</span>
<span class="o">&&</span> <span class="nb">sudo chmod </span>u+s /usr/local/bin/docker-machine-driver-hyperkit
<span class="nv">$ </span>curl <span class="nt">-Lo</span> minikube https://storage.googleapis.com/minikube/releases/latest/minikube-darwin-amd64 <span class="se">\</span>
<span class="o">&&</span> <span class="nb">chmod</span> +x minikube <span class="se">\</span>
<span class="o">&&</span> <span class="nb">sudo mv </span>minikube /usr/local/bin/
</code></pre></div></div>
<p>In addition to Minikube, you will also need Kubectl. You can install it one of
the two ways. Either by running the command below (please don’t forget to update
the version number to the current one at the time you are doing it):</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>curl <span class="nt">-Lo</span> kubectl https://storage.googleapis.com/kubernetes-release/release/v1.9.1/bin/darwin/amd64/kubectl <span class="se">\</span>
<span class="o">&&</span> <span class="nb">chmod</span> +x kubectl <span class="se">\</span>
<span class="o">&&</span> <span class="nb">sudo mv </span>kubectl /usr/local/bin/
</code></pre></div></div>
<p>or you can Install Google Cloud Tools SDK by following the instructions at the
quickstart for your platform: <a href="https://cloud.google.com/sdk/docs/quickstarts">https://cloud.google.com/sdk/docs/quickstarts</a>
(hint: do not download the sdk archive to a Downloads folder, you will need it
going folder, home is a better location) and once you have that, letting gcloud
tool install kubelet by running:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>gcloud components <span class="nb">install </span>kubectl
</code></pre></div></div>
<p>Once you have everything installed, you can start Minikube by running:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>minikube start <span class="nt">--vm-driver</span><span class="o">=</span>hyperkit
<span class="c"># or if you want to see logs:</span>
<span class="nv">$ </span>minikube start <span class="nt">--logtostderr</span> <span class="nt">--vm-driver</span><span class="o">=</span>hyperkit
</code></pre></div></div>
<p>If you are working behind a proxy, start minikube as:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ no_proxy</span><span class="o">=</span><span class="s2">"192.168.99.0/24,127.0.0.1,0.0.0"</span> <span class="se">\</span>
minikube start <span class="nt">--docker-env</span> <span class="nv">http_proxy</span><span class="o">=</span><span class="nv">$http_proxy</span> <span class="se">\</span>
<span class="nt">--docker-env</span> <span class="nv">https_proxy</span><span class="o">=</span><span class="nv">$https_proxy</span> <span class="se">\</span>
<span class="nt">--docker-env</span> <span class="nv">no_proxy</span><span class="o">=</span><span class="nv">$no_proxy</span>
</code></pre></div></div>
<p>where $http_proxy is full proxy URI, such as: http://proxy.example.com:8088</p>
<p>When Minikube launches it create a “minikube” context, and sets it to default in
kubectl. If you switch to another context in kubectl and need to switch back to
minikube context later, run: <code class="language-plaintext highlighter-rouge">kubectl config use-context minikube</code>.</p>
<h3 id="bash-completions">Bash Completions</h3>
<p>If you don’t already have bash completions installed, for the bas version
included with Mac OS (Bash 3.2) run:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>brew <span class="nb">install </span>bash-completion
</code></pre></div></div>
<p>or if you are running the upgraded bash 4.x version, run:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>brew <span class="nb">install </span>bash-completion@2
</code></pre></div></div>
<p>and follow the instructions in the “caveats” section of brew’s output to add the
appropriate bash completion path to your local .bash_profile or .bashrc.</p>
<p>To add kubectl completions to bash_completion:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>kubectl completion bash <span class="o">></span> <span class="se">\</span>
<span class="si">$(</span>brew <span class="nt">--prefix</span><span class="si">)</span>/etc/bash_completion.d/kubectl
</code></pre></div></div>
Inspecting Docker Volumes on a Mac/Windows the Easy Way
2017-04-16T00:00:00-04:00
http://www.freshblurbs.com/blog/2017/04/16/inspect-docker-volumes-on-mac.html
<p><strong>Please note:</strong> the described process should be virtually identical for the
Docker for Windows users, but I unfortunately don’t own a Windows and can’t test
it. Any comments would be greatly appreciated, if somebody wants to try this
approach on a Windows.</p>
<hr />
<p><a href="https://docs.docker.com/docker-for-mac/">Docker for Mac</a> is a great way of
using Docker on a modern Mac that gives you fully functional Docker environment,
in a very easy way. It is not a “native” solution however, meaning: there is
still an, albeit lightweight, VM running on your Mac. For the most part this
fact is completely transparent to you, especially compared to earlier solution
of running full VMs with VirtualBox, Parallels or VMWare, but in some cases you
will still run into the reality of there being a VM. One such case is when you
are working with Docker volumes.</p>
<p>Let’s assume you have a docker-compose file that creates multiple volumes. For
the sake of argument let’s assume you are running <a href="http://nodebootstrap.io">Node
Bootstrap</a>-created microservice. Out of the box, such
microservice will have some locally mounted volumes for code-editing and some
data volumes for database. What if you wanted to inspect them directly? Docker
provides a command to see all volumes:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>→ docker volume <span class="nb">ls
</span>DRIVER VOLUME NAME
<span class="nb">local </span>4cf5..708
<span class="nb">local </span>msfirst_ms_nb_example_db_data
</code></pre></div></div>
<p>and then inspect them, using a command like:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>→ docker volume inspect msfirst_ms_nb_example_db_data
</code></pre></div></div>
<p>with output such as:</p>
<pre><code class="language-JSON">[
{
"Driver": "local",
"Labels": {
"com.docker.compose.project": "msfirst",
"com.docker.compose.volume": "ms_nb_example_db_data"
},
"Mountpoint": "/var/lib/docker/volumes/msfirst_ms_nb_example_db_data/_data",
"Name": "msfirst_ms_nb_example_db_data",
"Options": {},
"Scope": "local"
}
]
</code></pre>
<p>Notice the <code class="language-plaintext highlighter-rouge">Mountpoint</code> attribute? It all sounds really promising until you try
to <code class="language-plaintext highlighter-rouge">ls /var/lib/docker/volumes..</code> only to find that there is no such folder on
your Mac. Now that is a disappointment! Except, we just need to realize that the
<code class="language-plaintext highlighter-rouge">/var/lib/docker</code> is a path in the Docker host VM, not on our Mac. And there is
actually a relatively straightforward way to get to it. We will see how to do
exactly that in a second, but before we do, to make things slightly more
convenient, and reduce on typing, you should create an alias:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>alias dm-disk='docker run --rm -it -v /:/docker alpine:edge $@'
</code></pre></div></div>
<p>after which you could see the path that <code class="language-plaintext highlighter-rouge">docker volume inspect</code> returns with a
command that looks something like the following:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>dm-disk ls -l /docker/var/lib/docker/volumes/msfirst_ms_nb_example_db_data/_data
</code></pre></div></div>
<h2 id="what-did-just-happen">What Did Just Happen?</h2>
<p>We ran a temporary, tiny container, in which we mounted the root of the host VM
to the <code class="language-plaintext highlighter-rouge">/docker</code> path. Once we have such container, we can run all kinds of
commands inside it to inspect Docker volumes. For instance, to see all available
volumes on the host you could run:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>dm-disk ls -l /docker/var/lib/docker/volumes/
</code></pre></div></div>
<p>That’s about it.</p>
Using JWTs and OAuth2 to Secure APIs and Microservices
2017-04-09T00:00:00-04:00
http://www.freshblurbs.com/blog/2017/04/09/json-web-tokens-oauth2.html
<h3 id="disclaimer">Disclaimer</h3>
<p>In this post we specifically discuss usage of JSON Web Tokens (JWT, pronounced
“jot”) with OAuth2. JWTs can certainly be used without OAuth2, by utilizing any
other authentication method (e.g. <a href="https://tools.ietf.org/html/rfc2617">Basic
Auth</a> over HTTPS), but in this opinionated
post we assume OAuth2 is usually a preferred method for performing API client
authentication and are mostly interested in how using JWT can improve an OAuth2
implementation.</p>
<p>We further assume that the reader is familiar with OAuth2.
If this is not the case, you may want to consult with Alex Bilbie’s <a href="https://alexbilbie.com/guide-to-oauth-2-grants/">wonderful
OAuth2 reference</a>.</p>
<h3 id="shortcomings-of-oauth2s-opaque-bearer-tokens">Shortcomings of OAuth2’s Opaque Bearer Tokens</h3>
<p>Various OAuth2 workflows all authenticate API clients and if auth passes, a
server issues API client a bearer token. API clients use the bearer token to
make subsequent API calls when accessing protected API endpoints.</p>
<p>OAuth2 spec doesn’t define the format of the bearer token or assign it any
meaning. In a lot of legacy implementations, bearer token is just a unique
string. To validate it (and determine any scopes associated with the token) API
endpoint may need to verify the token, provided by a client, using one of two
means:</p>
<ol>
<li>Calling Authorization service and supplying the token. This leads to a
network sub-call for every API call.</li>
<li>Assuming API Gateway is always in front of it, validating the token for the
API at every request. This approach will usually lead to a data-lookup by the
API gateway for each API call.</li>
</ol>
<p>In the two scenarios, either service itself or the API Gateway are performing a
database lookup to validate the token, at every API call. The lookup can be
cached, of course. Regardless, we are either sacrificying scalability
(server memory used for caching is limited) or speed (network calls can be
expensive).</p>
<p>JWT tokens give us a way of validating tokens that use some CPU but do not
require any RAM or a network call. Since CPU can easily be scaled horizontally
it can be a very interesting solution, in many cases.</p>
<h3 id="using-jwt-for-token-validation">Using JWT for Token Validation</h3>
<p>Instead of a opaque string, a bearer token can be a JSON Web Token (JWT).
A JWT is basically a base64-encoded JSON object represented as a string of
characters. Since the token is actually a JSON object, it can carry all kinds of
information (“claims”). Specifically, JWT can carry such “claims” as:
authenticated <code class="language-plaintext highlighter-rouge">client_id</code> of the API caller and all OAuth2 scopes associated with
the <code class="language-plaintext highlighter-rouge">client_id</code>.</p>
<p>How can we trust that information in JWT is valid and a client is not claiming
something it is not authorized for, or pretending to be someone else? We can
trust this because JWT tokens are cryptographically signed.</p>
<p>To be very clear: JWT tokens are <em>not</em> encrypted! A JWT can be decoded by
anybody. Which means: you should <strong>never</strong> include private information in it,
i.e. never encode passwords or secrets in a JWT! However you can verify whether
JWT is properly signed by an OAuth2 server. This can be done in two ways:</p>
<ol>
<li>Using a shared secret key (symmetric approach)</li>
<li>Using private/public key combo (assymetric approach).</li>
</ol>
<p>The latter is preferred. In the assymetric approach, OAuth2 Authorization Server
signs JWT token with a private key. All your API endpoints can possess
corresponding public key (which is not secret and can be widely distributed).
Using the public key, API endpoints can verify that the JWT was indeed issued by
a trusted authentication server (e.g. OAuth2 server) and therefore claims in the
token (the JSON object) can be trusted as made by the authorized server.</p>
<p>As you may have already guessed, the huge benefit of the JWT approach is its
scalability: an API endpoint verifying the JWT only needs to posess proper
public key, but doesn’t need to look anything up in a data storage or use memory
to cache lookups. Furthermore, public keys are not secrets and don’t need to be
secured in any special way, making logistics of the verification easy.</p>
<p>JWT tokens can be an extremely good solution for securing inter-service
communications in a Microservice Architecture, where speed and scalability can
be of paramount importance. Since JWTs can be issued by any authentication
server/process, using JWTs also allows entirely bypassing an API Gateway for
inter-microservice communications if and when appropriate.</p>
<h3 id="jwt-criticism-and-security-considerations">JWT Criticism and Security Considerations</h3>
<p>JWTs are not without limitations. Since API endpoints don’t consult a central
server, central revocation of credentials (an important feature of OAuth2) can
be challanging. JWT tokens do have expiration time and are not issued in
perpetuity, but if you detect that a set of tokens are compromised, triggering
an immediate revocation of those tokens across a distributed network can be
a non-trivial effort, at least: until the tokens expire.</p>
<p>Due to this limitation, it is recommended that expiration times of JWT tokens
issued be set to reasonably short periods. JWT supports token expiration out of
the box using <a href="https://tools.ietf.org/html/rfc7519#section-4.1.4">“exp” claims</a>.
How short the expiration times should be will depend on your use-cases and
requirements.</p>
<p><a name="jwt-nonces"></a>
Another notable capability that JWT spec offers to enhance security of the
tokens is the notion of <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-4.1.7">“jti” (JWT ID)
claims</a>,
also known as “JWT nonces”. A <code class="language-plaintext highlighter-rouge">jti</code> claim is basically a globally unique
identifier of a JWT token. It is optional, but if we include a <code class="language-plaintext highlighter-rouge">jti</code> in every
token issued, we will be able to identify individual tokens. We can then create
a blacklist of jtis when and if we learn that the specific JWTs are compromised.
This will allow clients validating the tokens to reject compromised tokens by
consulting with the master blacklist of compromised tokens. A jti can be
any globally unique identifier. A good and easy-to-generate candidate for
such identifier can be
<a href="https://en.wikipedia.org/wiki/Universally_unique_identifier">uuid</a> version 4.</p>
<p>At the first glance, notion of a master blacklist of compromised tokens may feel
like something that destroys the main benefit of JWTs: decentralized validation.
While jti validation can indeed reduce decentralization of JWT validation, in
general, we can greatly mitigate its negative affects with sensible caching. For
instance, you can utilize following two approaches to avoid the need of
consulting any central authority per each client request:</p>
<ol>
<li>Keep locally cached list of blacklisted JWTs. If a central authority can
know and reach all ‘local’ validators (e.g. microservices) it can push the
new list to them, when new entries are added. If not, utilize the method #2.</li>
<li>Keep locally cached list of blacklisted JWTs. Update this list as frequently
as it makes sense to your context. In most cases, you may be able to refresh
caches every few minutes, only giving compromised tokens very short time during
which they can be used.</li>
</ol>
<p>Please note that while first method is harder to implement (central authority
needs to know of and be able to update all local validators) it has a benefit of
zero-delay invalidations. In the second method there is some lag, but you can
tweak its duration based on your needs. In both scenarios you can increase
expiration time of JWT tokens, if needed, and it will be more secure compared to
when you don’t use ‘jti’ nonces. This is true because when using <code class="language-plaintext highlighter-rouge">jti</code>s a
revocation request can propagate quickly and you are not relying solely on JWTs
expiring to remove compromised ones.</p>
<p><em>Important Optimization:</em> if you implement a local cache of blacklisted JWT
tokens, make sure to regularly prune it by deleting expired tokens. This can
greatly help you keep the cache sizes reasonable and manageable.</p>
Microservices and Message Queues
2016-12-07T00:00:00-05:00
http://www.freshblurbs.com/blog/2016/12/07/microservices-message-queues.html
<p>While discussing Microservices best practices, questions about message queues
comes up often. Specifically, a question I have been asked many times is whether it
is OK for multiple microservices to access a shared message queue. This is a
fair and important question. In general, sharing data by multiple microservices
decreases independent deployability of those microservices and is therefore a
bad idea. Intuitively, sharing message queues should equally be frowned upon.
However, considering eventual and asynchronous character of many
microservice-to-microservice invocations, inter-service communications
could certainly benefit from queue-based message exchange. So, should and could
we share queues between Microservices or not?</p>
<p>The advice I have been giving, so far, is to step back from the implementation (queue)
and concentrate on a business capability that the queue provides, in each case.
By doing this we can implement the capability (which, admittedly, happens to use a queue)
but microservices in question will not be accessing a queue directly, instead
they will just be invoking yet another microservice.</p>
<p><em>IMPORTANT</em>: to be very clear, I am not advocating just hiding a queue behind an
HTTP API. That, to a large extent, is a waste of time since the initial problem
was not the transport protocol to begin with. Just substituting, say, AMQP with HTTP
is definitely not the solution here. It is very important that the newly-minted
microservice genuinely provides a real capability, even if the capability is more
technical than your subject-matter experts would like you to work on, on a regular
day.</p>
<p>Let me give couple examples to clarify what I mean. In one complex application,
recently, we avoided direct access to message queues by creating three capability-driven
microservices:</p>
<ol>
<li>Publish-subscribe hub.</li>
<li>Job scheduler</li>
<li>Batch job processor</li>
</ol>
<p>While each one of these microservices were backed by a message queue, behind
the scenes, the semantics of their APIs wasn’t that of a message queue and
we genuinely implemented three distinct capabilities (even if somewhat
infrastructural), instead of just mechanically wrapping a message queue with
HTTP protocol.</p>
<h3 id="real-life-example-of-an-api-vs-infrastructure">Real-Life Example of an API vs. Infrastructure</h3>
<p>We were recently discussing a related topic with my good friend
and a well-known API expert <a href="https://twitter.com/davidgoldberg">Dave Goldberg</a>
and we landed on an example that I think vividly exemplifies when an API is
much more than just an HTTP wrapper around an underlying infrastructure. This example
is not about queues, but the principles are identical and relevant.</p>
<p>Consider the example of a modern, transactional email API, such as Sendgrid, Postmark,
Mailjet or Mandrill, etc. Their APIs, while fundamentally just allowing to send e-mail,
are most certainly not mere wrappers around decades-old SMTP protocol. Rather,
these APIs provide novel, optimized semantics to the basic functionality and also
add features that were never present in SMTP, to begin with (e.g. status callbacks).
Obviously behind the scenes the above services all employ massively-scalable SMTP
deployments, but conceptually they are transactional email APIs, not: SMTP wrappers.</p>
<p>When we recommend avoiding direct exposure of message queues to the individual
microservices, in your architecture, we talk about an abstraction similar to what
Sendgrid et al. have achieved by concentrating on a capability and hiding low-level
infrastructure (SMTP) as a non-essential implementation detail. Only a handful of
your microservices should ever work directly with the likes of Kafka or RabbitMQ,
most of your services should instead “talk” to the capabilities that those few
services encapsulate.</p>
<h3 id="in-summary">In Summary</h3>
<p>I am sure, as understanding of Microservices evolves, we may find a better answer
to the original question, but from where things stand currently the above-described
technique seems to work. I hope it helps somebody else, just like it helped us.</p>
Microservices: Rule of Twos
2016-10-09T00:00:00-04:00
http://www.freshblurbs.com/blog/2016/10/09/microservicies-rule-of-twos.html
<p>In a recent post we discussed how <a href="/blog/2016/09/27/microservices-coordination-removal.html">Microservice Architecture is fundamentally all about avoiding need for coordination</a> and that all of its other often-cited principles are essentially derivatives of this fundamental goal. One such important, Microservices principle is: <em>avoiding shared libraries and binary coupling</em>. If you haven’t already, you should watch <a href="https://www.youtube.com/watch?v=-czp0Y4Z36Y">Ben Christensen’s wonderful talk</a> on the subject.</p>
<p>Early in Ben’s talk you will notice that while he is discussing a specific problem he is fundamentally addressing the same “avoiding coordination” issue, in context. Ben aptly explains that a decision of sharing binary libraries, frameworks, or platforms can lead to a gargantuan challenge when you eventually need to upgrade or replace that library in just one part of the product or organization. A task that should take a day or a short scrum cycle, at most, often turns into a multiple-months (sometimes: years) long project. As a matter of fact, such efforts are often entirely cancelled when stakeholders realize the magnitude of implications.</p>
<p>It’s easy to follow the logic Ben explains and to buy into it. However, it can be much harder to come to terms with its seemingly “devastating” implications. Is sharing of libraries across microservices indeed evil? If it is then how about the “reuse of code” being one of the most efficient practices in all of software engineering? What about leveraging open-source? Seriously, how many closely-held engineering principles is Microservice Architecture going to take a swing at? Is this rebellious architectural style even worth it, if it’s going to fight <em>every. single. principle.</em> that us, software engineers have come to appreciate, for decades?</p>
<p>Well, let’s pause for a second, before we reject Microservices and start “hating” it, or before we throw away everything we believed in, prior to Microservices. The reality is: Microservice Architecture is not against sharing of libraries per se. What it actually is against, is creating death-grip dependencies that would compromise our ability to practice the principle of Avoiding Coordination. While sharing of libraries, can often lead to significant challenges – it doesn’t have to. And sharing of libraries is not the only way to compromise Avoidance of Coordination, either. You can just as easily create costly lock-ins by choosing single media type (e.g. <a href="http://json-ld.org/">JSON-LD</a>, <a href="http://stateless.co/hal_specification.html">HAL</a>, <a href="https://github.com/kevinswiber/siren">Siren</a> or <a href="http://uberhypermedia.org">UBER</a>) for all your APIs. Or you can choose a single way of accomplishing fault-tolerance that can lead to the same implications. Examples are too many.</p>
<p>Fortunately, there’s a fairly simple principle, and some team discipline that goes with it, which can be exercised in implementing Microservice Architecture that can avoid all kinds of dependency lock-ins, including the one described by Ben. This principle was inspired by many conversations with my dear friend and renown expert of distributed systems: <a href="http://amundsen.com/">Mike Amundsen</a>. We have used this principle, in practice, very successfully at <a href="https://www.referwell.com">ReferWell</a> – a healthcare technology startup, where we have implemented an innovative physician-facing software product using APIs First approach and Microservice Architecture. I lovingly call this principle: Rule of Twos and have come to appreciate it a great deal.</p>
<h2 id="rule-of-twos">Rule of Twos</h2>
<p>The basic idea is that your choices won’t lock you-in if you constantly exercise your ability of supporting multiple choices:</p>
<blockquote>
<p>For any critical component in your system, make sure you use at least two alternatives, in production, at the same time – even when you only need one. Also make sure that you have infrastructure to support the two alternatives as easily as you would use single one.</p>
</blockquote>
<p>In practical terms, this leads to example guidances such as:</p>
<ol>
<li>
<p>Make sure some of your critical APIs are written in Go or Scala, even if most of them are written in Node and you are exerting huge organizational efficiencies by standardising on a single, efficient, common programming language.</p>
</li>
<li>
<p>Make sure some of your microservices use a document or NoSQL database, even if most of them use traditional, relational one. In making this happen, you will develop capabilities that will be invaluable for you, in the long-term.</p>
</li>
<li>
<p>Make sure some of your critical APIs are communicating with a media type that is different from the one you use everywhere, e.g. if you standardize on HAL, use UBER for some other, important ones. In making such multiple-message-format support happen you may end-up implementing a powerful design pattern such as: <a href="https://github.com/apiacademy/representor">Representor</a> that will make your APIs long-lasting, evolveable and adaptable.</p>
</li>
</ol>
<p>I won’t bore you with more examples. I know you can find a lot of them in your own contexts, but the main point I would like to communicate is: sharing of libraries or standardizing on other organizational choices is not always and necessarily toxic. The dangerous part is not having a flexible infrastructure to accommodate any non-standard alternatives. Most importantly – you will not be able to support such alternatives <strong>unless you practice your openness to choices</strong> every single day!</p>
<p>This is where Rule of Twos comes in: even if you don’t need alternatives today, do implement examples of them <em>today</em>, and tomorrow when you actually need it - you will be free to exercise free choice. Always implement critical decisions as two alternatives, from day one, and lay down infrastructure to seamlessly support them - that is the essence of the Rule of Twos.</p>
Microservices Are All About Avoiding Coordination Cost
2016-09-27T00:00:00-04:00
http://www.freshblurbs.com/blog/2016/09/27/microservices-coordination-removal.html
<p>One of the core themes of the <a href="http://www.msabook.com">Microservice Architecture</a> book my co-authors and I published with O’Reilly recently is: “Speed and Safety at Scale”. Whether you work in a large enterprise or are trying to grow a tiny startup, speed to market is equally crucial. We all operate in a global, highly competitive, digital market and race to success is fierce for organizations of all sizes.</p>
<p>Where things get complicated is in realization that, while important, speed is rarely the only business goal. For most businesses safety of making changes is equally paramount – sometimes even enforced by governments, e.g. in regulated industries such as: healthcare or finance. Unfortunately, speed and safety are in natural opposition - faster we move higher the chances of something falling through the cracks. The conflict between speed and safety gets further exacerbated with scale. Scale brings need of coordination. Every time we need to coordinate an activity across multiple teams, no matter how small each team is (even one person ‘team’ counts) – we inherently slow down overall progress. An assembly line-style interlinked chain of activities can only progress as fast as its slowest link.</p>
<p>However, once we identify cost of coordination as the killer of our speed at scale, we can design our organizational culture such that the need for cross-team coordination be minimized. Microservice Architecture is a software architecture style and the corresponding organizational culture that do exactly that: prioritize minimization of required coordination.</p>
<p>While it is still rare for Coordination Elimination to be explicitly called-out as THE core value of Microservice Architecture, we can successfully argue that <em>all</em> of the <a href="http://shop.oreilly.com/product/0636920033158.do">often-cited benefits of Microservice Architecture</a> are just derivatives of this core value:</p>
<ol>
<li>Technology Heterogeneity – removes need to coordinate programming languages, frameworks, libraries and technology platforms across multiple teams.</li>
<li>Partitioned Scalability and Independent Deployments – basically remove the need to coordinate deployments and operation of various parts of the system across teams.</li>
<li>Composability and Replaceability remove the need to coordinate life-cycle management of parts of the larger system, across various teams.</li>
</ol>
<p>Which brings us to the answer for the most confusing, and controversial, question in all of Microservice Architecture: <em>‘how “micro” (small) should a microservice be?’</em></p>
<p>The answer is obvious once we admit Microservice Architecture is all about avoiding need for coordination:</p>
<blockquote>
<p>A microservice should be <strong>small</strong> and <strong>simple</strong> enough that anybody in the organization be able to modify or rewrite it in a trivial amount of time.</p>
</blockquote>
<p>“Trivial amount of time” will vary depending on the context, from hours to days, but as a rule of thumb: it should not be longer than two weeks, at most.</p>
<p>If this notion makes sense to you, you may also be interested in watching my recent <a href="https://vimeo.com/184336536">talk at RestFest</a>, where I discussed cultural elements of Microservices and was unapologetic about calling Coordination “toxic”.</p>
Cultural Elements of Microservices: Service Ownership
2016-06-01T00:00:00-04:00
http://www.freshblurbs.com/blog/2016/06/01/microservice-culture-service-ownership.html
<p>One of the core tenets of the Microservice Architecture, quoted in the now-classic <a href="http://martinfowler.com/articles/microservices.html#ProductsNotProjects">Lewis and Fowler</a> list, is the principle of: Products not Projects. In brief, this principle explains that “a team should own a product over its full lifetime”, where by ‘product’ we imply an individual microservice.</p>
<p>It’s a great principle that promotes number of important messages, such as: development team taking responsibility for the software in production and developers’ relationship with the service not being done as soon as they ship the first version. However, when viewed from a team culture perspective, it carries significant risk of being misunderstood. Specifically, the emphasis on “owning the service” can be misleading. It does imply that there’s a dedicated team “owning” each service, which can easily be misconstrued as: nobody outside the “owning” team should modify the code of a service. This is the opposite of what a healthy microservices organization should aspire to.</p>
<p>Organizations adopting Microservice Architecture will eventually find themselves with large number of microservices. Many of those microservices will call each other to acquire the capability expressed by the microservice being called. If a fellow developer depends on “your” microservice and you are on vacation, or if you have moved-on to another job (which never happens in tech industry, right?), the worst thing would be nobody else, in the organization, having the understanding or experience with your microservice’s code. Indeed, one of the most important traits of Microservice Architecture is each service being small enough, hence: simple and clear enough, for any developer in the organization to quickly look at the code, comprehend it and modify it, when and if they need to. Obviously there is always certain QA process for accepting modifications, even within the service “owning” team, but service’s code should be open for collaboration to the entire organization, not just the “owning” team!</p>
<p>For a microservice architecture, ideal organizational culture is achieved when the ecosystem is run like an open-source community (think Github): lots of different repositories that many people have understanding of, since they not just use those, but also actively contribute to various “projects”.</p>
<p>If your organization is set up with rigid responsibility lines over service code ownership, or if service code-base is hard to “dive into” – you may want to rethink the culture of the team and its fit with the architectural style.</p>
Microservice User Interfaces?
2016-03-30T00:00:00-04:00
http://www.freshblurbs.com/blog/2016/03/30/user-interface-and-microservices.html
<p>Every so often I get asked a tough question that goes something like: “so, you are going to break up all your ‘backend’ into services but your front-end is still going to be a huge monolith?”. It’s a fair question. Fair enough that it deserves a short post to address it.</p>
<p>The main thing to keep in mind, when thinking of UI in the context of modern architecture, is that we live in a mobile-first, omni-channel world. The question of “what about the UI for this webapp?” used to make more sense when we were just building websites. Those “happy” times are long gone. Now we are building systems for a variety of platforms: web, iPhones, Androids etc. and the notion of what “user interface” is has significantly evolved.</p>
<p>Many software teams are now building systems with API-first architecture, not letting APIs have any hard dependencies on the target user-interface – which may end-up being a watch or a car dashboard, not just: smartphone or tablet. In this context, it becomes clear that, for most teams, Microservice Architecture only concerns your set of APIs (let’s all agree to not use hurtful words such as “backend”, we are all “full-stack developers”, by now, aren’t we?). The question of UI still stands, yes, and yes, you probably don’t want to build the user-interface part as a monolithic, single-component solution, but how you componentize your UI depends on whether you are building an iPhone app, Single-Page web app or Android app, so to large extent, that is an important, but a different question.</p>
Docker for Microservices Survival Guide
2016-02-27T00:00:00-05:00
http://www.freshblurbs.com/blog/2016/02/27/docker-microservices-survival-guide.html
<h2 id="building-your-first-containers">Building your First Containers</h2>
<p>Installing basic Docker tool-set is <a href="https://docs.docker.com/engine/installation/">quite trivial</a> on most platforms. On reasonably new versions of major Linux distributions you can add a repository provided by <a href="http://www.docker.com">Docker.com</a> and install Docker in one command from there on. “Reasonably new” means: distributions the kernels of which support <a href="https://en.wikipedia.org/wiki/LXC">LXC</a>.</p>
<p>Since MS Windows and Mac OS-X obviously do not have Linux kernels, in order to install Docker, at the time of this writing, we need to first install a virtual machine containing Linux distro in it and then install Docker in Linux, bridging networks and doing other “fun” things to make the environment easy-to-use. You can try it manually or you can install a <a href="https://docs.docker.com/engine/installation/#on-osx-and-windows">nicely put-together package</a> provided by Docker. This package is based on Docker Engine and Oracle VirtualBox VM. VirtualBox is not the only VM engine that is supported with this setup. You can also use latest version of <a href="https://github.com/Parallels/docker-machine-parallels/">Parallels</a> Pro/Business or <a href="https://docs.docker.com/machine/drivers/vm-fusion/">VMWare Fusion</a>, if they fit your needs or tastes better.</p>
<p>Interestingly enough, docker tool-set itself is an application that has client-server architecture. The docker CLI tool we use to execute most commands (“docker”) is an agent that talks to a corresponding daemon and passes our commands through. This is super convenient because it allows initiating docker commands locally even if they are executed “remotely”. For instance, if you work on Mac or a Windows PC, and install docker via Docker Engine bundle: you will not have to SSH into the virtual machine to run docker commands. You can still run docker commands locally in your terminal (OS-X) or powershell (Windows) and they get passed through to the docker daemon running on a Linux, inside the VM, serving as docker host.</p>
<p>Docker uses a special configuration file, called Dockerfile, to set up a container. A Dockerfile for setting up a Node.js environment may look like the following:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>FROM alpine:3.2
MAINTAINER Irakli Nadareishvili
ENV VERSION=v4.2.1
ENV REFRESHED_AT 2015-12-27-22_00EST
RUN apk upgrade --update \
&& apk add curl make gcc g++ linux-headers paxctl musl-dev \
libgcc libstdc++ python openssl-dev zlib-dev \
&& mkdir -p /root/src \
&& cd /root/src \
&& curl -sSL https://nodejs.org/dist/${VERSION}/node-${VERSION}.tar.gz | tar -xz \
&& cd /root/src/node-* \
&& ./configure --prefix=/usr \
&& make -j$(grep -c ^processor /proc/cpuinfo 2>/dev/null || 1) \
&& make install \
&& paxctl -cm /usr/bin/node \
&& npm cache clean \
&& apk del make gcc g++ python linux-headers \
&& rm -rf /root/src /tmp/* /usr/share/man /var/cache/apk/* \
/root/.npm /root/.node-gyp /usr/lib/node_modules/npm/man \
/usr/lib/node_modules/npm/doc /usr/lib/node_modules/npm/html \
&& apk search --update
</code></pre></div></div>
<p>You don’t need to worry about understanding every single line of this file, but as you can see it is very similar to a shell script and achieves several major tasks:</p>
<ol>
<li>At the very beginning it declares that the new container should be created based on an existing container. In this case: Alpine Linux container at version 3.2. Alpine is a super-slim Linux distribution (around 5MB) that is popular among Docker enthusiasts who care for creating super-small containers. In comparison, the smallest Ubuntu container is typically couple hundred megabytes.</li>
<li>Further we declare some environmental variables that can be used during build process. In this case we abstract-out the version of Node we need installed. This way we can use the same Dockerfile to build various versions of Node containers, by modifying the variable in only one spot.</li>
<li>Last, but not least, we execute a number of shell commands using the RUN instruction to get Node installed and to perform some post-installation clean-up. You may notice that we have coalesced many commands into one. Alternatively, we could have written a RUN command per each shell command. The reason we didn’t do it is: each RUN command creates intermediary containers. This can be super useful while debugging your Dockerfile (you can resume execution from the last RUN command) but may not be what you need in production. A lot of production Dockerfiles use the trick of merging multiple shell commands into a single RUN command, but it’s not a necessity.</li>
</ol>
<h2 id="docker-survival-guide">Docker Survival Guide</h2>
<h4 id="building-a-docker-image">Building a Docker Image</h4>
<p>Once we have a Dockerfile, we can get in the folder where it is located and run the following command to build the Dockerfile:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>> docker build -t nodejs .
</code></pre></div></div>
<p>the <code class="language-plaintext highlighter-rouge">-t</code> flag allows us to give the newly minted image a nice name (‘nodejs’ in this case). Once the building process is done, you should be able to see the newly minted image at the top of the images list: <img src="/img/content/dockerimages-nodejs.jpg" alt="" /></p>
<h3 id="running-a-container">Running a Container</h3>
<p>We can run a container from any image whether local or remote. The “docker images” command shows local images, but there’re thousands more on Docker Hub that we can also run. Let’s first see how to run a container from a local nodejs image we just built:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker run -ti nodejs /bin/sh
</code></pre></div></div>
<p>The ‘-ti’ combination of options ensures that the container starts with a pseudo-TTY, in an interactive mode. Following these options is the parameter that indicates which Docker image to start a new container from, which is: “nodejs”, in our case. The last parameter indicates what command to execute once the container is started. In our case that is: /bin/sh interactive shell, which we use to verify that the newly minted container does indeed have working node installation:</p>
<p><img src="/img/content/dockerrun-shell.jpg" alt="" /></p>
<p>Please note that in Docker, you can only indicate one executable command during a container startup. Containers are not like VMs, in that: you are not supposed to run multiple processes per container, not really. Technically, you can still do it, by making the “one command” you execute be a process launcher (such as: <a href="http://smarden.org/runit/">runit</a> init daemon) and then let the process launcher spawn other processes. Such “trickery” is not necessarily unheard of in the Docker world, but it is certainly frowned upon as it breaks the “<a href="https://en.wikipedia.org/wiki/Unix_philosophy#Do_One_Thing_and_Do_It_Well">UNIX philosophy</a>” of shipping containers that “do one thing, and do it well.”, which we have already mentioned.</p>
<h3 id="mapping-ports-and-volumes">Mapping Ports and Volumes</h3>
<p>Let’s create a container that is slightly more useful than what we did in the previous section. We’ll start by writing the world’s simplest Node server. If Node.js is not your kind of pie, don’t worry about it: the source-code is quite self-explanatory and the Node code per se, isn’t terribly important anyway.</p>
<p>Create some empty folder and put the following file inside it, by naming it: server.js:</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">var</span> <span class="nx">http</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">http</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">server</span> <span class="o">=</span> <span class="nx">http</span><span class="p">.</span><span class="nx">createServer</span><span class="p">(</span><span class="kd">function</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">res</span><span class="p">.</span><span class="nx">end</span><span class="p">(</span><span class="dl">"</span><span class="s2">Hello, Docker Enthusiast!</span><span class="se">\n</span><span class="dl">"</span><span class="p">);</span>
<span class="p">});</span>
<span class="nx">server</span><span class="p">.</span><span class="nx">listen</span><span class="p">(</span><span class="mi">3000</span><span class="p">);</span>
</code></pre></div></div>
<p>The gist of the script is that: it will launch a server on port 3000 and respond, to any HTTP GET request, with a welcoming message.</p>
<p>Let’s now see how we could launch this Node script using the node environment from the container.</p>
<p>This is an interesting case. We mentioned how Docker’s (containers’) main benefit is: creating installable packages for complex applications. That assumes that the application code will be part of the container image as well. Well, yes and no. For production deployments, the statement is certainly true. However, while we are actively developing code, if we had to rebuild the image every time we edit source code we would waste a lot of time and get annoyed pretty quickly. Especially those of us who use scripting programming languages a lot and have long forgotten what it feels like to wait for a build step after every code change.</p>
<p>Long story short: we don’t have to rebuild the image after every code change. Instead, what we can do is: mount host machine’s location into the container, launch the container once and then edit the source code “locally” as much as we desire.</p>
<p>To do so, in the folder where you created server.js, create a new Dockerfile:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>FROM irakli/alpine-nodejs:latest
RUN mkdir /home/app && npm install supervisor -g
WORKDIR /home/app
ENTRYPOINT [ "/usr/bin/supervisor", "-w", "." ]
</code></pre></div></div>
<p>Several things to note here:</p>
<ol>
<li>We are building our new contianer image based on a published image, at DockerHub: <a href="https://hub.docker.com/r/irakli/alpine-nodejs/">https://hub.docker.com/r/irakli/alpine-nodejs/</a>. If you follow the web URL to the DockerHub project, and then click on the “Dockerfile” link, you will notice that it is very similar to the one we wrote, earlier in this chapter. I just want to show you that the base images don’t always need to be local and docker will fetch them from remote registries, as needed.</li>
<li>Next command, in the Dockerfile, tells Docker to create a folder where we shall store our code and to install a Node module which provides hot-reloading capabilities. While Node is a scripted language it actually caches interpreted code and without this handy utility, we’d need to restart the server, every time we change code. That wouldn’t help what we are trying to demonstrate here (real-time code editing in a container).</li>
<li>The WORKDIR command changes current working directory. It’s somewhat identical to “cd” in Unix/Linux.</li>
<li>The last command in the Dockerfile is an interesting one. We already mentioned that you can indicate which command to execute, as the main container process, in a Dockerfile rather than on the command line. The Dockerfile instruction for it would be: <a href="https://docs.docker.com/engine/reference/builder/#cmd">“CMD”</a>. Here’s a pro-level twist to the story, however: we don’t want to indicate a fully-flashed-out command. We’d like to leave the name of the Node script as a parameter. This is where ENTRYPOINT command enters the scene: it is like CMD, but it will append whatever we indicate on the command-line (in a ‘docker run’ command) to the predefined starting portion of the shell command. You may also notice that the argument of the ENTRYPOINT instruction is an array, rather than a string. Both in case of CMD and ENTRYPOINT, Docker recommends passing different parts of the shell command as an array of arguments, instead of: one long string.</li>
</ol>
<p>To build this new container images, type:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker build -t node-code .
</code></pre></div></div>
<p>which will create a new image called: “node-code”. You can verify that it exists by typing: “docker images”.</p>
<p>Finally, to launch the container, type the following command:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker run -p 9999:3000 -v $PWD:/home/app node-code \
/home/app/server.js
</code></pre></div></div>
<p>You will notice that we are using some new options we haven’t used yet.</p>
<ol>
<li>The “-p” option allows us to re-map the port on which a service exposed by the container is available on the host. Meaning: if you remember the server.js’ source code: the service was running on port 3000. What if port 3000 is already occupied on the host, however? Or if we have some other reason why we don’t want to use 3000? No problem. A service can run on whatever port, inside the container, and we can expose it on any other, un-occupied port, on the host machine.</li>
<li>the “-v” option mounts current local folder on the host (where server.js is) to <code class="language-plaintext highlighter-rouge">/home/app</code> folder inside the container. The it instructs Docker to append <code class="language-plaintext highlighter-rouge">"/home/app/server.js"</code>` argument to the launch command already provided in the ENTRYPOINT, which will make the final executed command like something like:</li>
</ol>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/usr/bin/supervisor -w . /home/app/server.js
</code></pre></div></div>
<p>Once the container launchs successfully, you can go to the IP of your host machine. The IP will be: 0.0.0.0 if you are Unix/Linux or the IP of the docker machine if you are running Docker host via Docker Machine, on OS-X or Windows. To find-out what is the IP of the currently running docker machine, on OS-X you can run something like:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker-machine ip `docker-machine active`
</code></pre></div></div>
<p>Once you know your Docker host’s IP, point your browser to:
<code class="language-plaintext highlighter-rouge">http://<ip-address-of-the-host>:9999/</code> and you should see the cheerful greeting.</p>
<p>Now try to edit the server.js, e.g. by adding a smiley face to the greeting:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>res.end("Hello, Docker Enthusiast! :) \n");
</code></pre></div></div>
<p>Once you refresh the web page, you should see the new greeting with the smiley face!</p>
<p>Congratulations! You just coded and launched your first, containerized microservice! Exciting, right?</p>
<h3 id="docker-compose--linking-containers">Docker Compose – Linking Containers</h3>
<p>Aside from making code development, with containers, much easier the volume mounting capabilities of Docker (“-v” option) can be very useful for persisting data. You have to remember that Docker containers are inherently ephemeral: once the container process dies, everything is gone. If you are writing to some files within the container - they will disappear. That is not that great if you are writing a database-driven application, now - is it?</p>
<p>Volumes can help solve this problem, but before we dive into it, we need to explore the architecture of a database-backed, containerized application, a little further.</p>
<p>If you remember the “unix philosophy”, adopted by Docker, that we keep mentioning – putting a database and application in a single container is an extremely anti-Docker-y thing to do.</p>
<p>To do such thing properly, we need to launch a database in one container, application – in another and let the two containers “find” each other, also known as: link the containers, in Docker-world.</p>
<p>We can still do such things using docker executive, but there’s a significantly more elegant and easier way to orchestrate containers, when we deal with multiple. This ellegant tool is called: Docker Compose.</p>
<p>Docker compose uses YAML-based configuration files to orchestrate complex scenarios. For instance, if we need a Node.js app and a MySQL database, the corresponding Docker Compose configuration file, named docker-compose.yaml might look something like the following:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>api:
build: .
volumes:
- .:/opt/application
- /opt/application/node_modules
ports:
- "5000:3000"
links:
- db
db:
image: mysql
volumes:
- /data/mysql:/opt/data
environment:
- MYSQL_ROOT_PASSWORD=rootpwd
- MYSQL_USER=mysqluser
- MYSQL_PASSWORD=mysqlpwd
- MYSQL_DATABASE=onoroff
</code></pre></div></div>
<p>As you can see, we are making sure database files will not be lost by mounting a folder on the host filesystem into the “db” container.</p>
<p>If you are wondering why do we have second instruction with <code class="language-plaintext highlighter-rouge">- /opt/application/node_modules</code> in the volumes
description - the answer is: so that volume mounted from the host doesn’t overlap and hide, at runtime, node_modules
folder which is created during build-time. This is a well-known and elegant trick.</p>
<h4 id="data-only-containers">Data-Only Containers</h4>
<p>While using host folder mounting for data persistence is an acceptable approach, it is actually not the current best-practice in the “Dockerworld”. Big part of the reason being: while volume-mounting for the “api” is only for local development, we’ll have to perform volume-mounting for the database, even in production and host machine directly sharing disk space with the container is not an ideal level of isolation we are seeking. What if some other service also tries to write into /data/mysql on the host machine? T.R.O.U.B.L.E.!</p>
<p>Instead, what experienced Docker practitioners usually do is: creating so-called, “data-only” containers and using its volume in a database container. This approach gives us the best of both worlds: since “data-only” container is never launched, it won’t crash and its longevity is practically identical of the longevity of the host itself. On the other hand the disk space is encapsulated in a specific container and the chances of some service accidentally accessing it are much lower.</p>
<p>Let’s see how a Docker Compose file with data-only container may look like:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>api:
build: .
volumes:
- .:/opt/application
- /opt/application/node_modules
ports:
- "5000:3000"
links:
- db
db:
image: mysql
volumes_from:
- db_data
environment:
- MYSQL_ROOT_PASSWORD=rootpwd
- MYSQL_USER=mysqluser
- MYSQL_PASSWORD=mysqlpwd
- MYSQL_DATABASE=ourawesomemicroservice
db_data:
restart: always
image: alpine:latest
volumes:
- /var/lib/mysql
command: "true"
</code></pre></div></div>
<p>As you can see, for the data-only container, we are using tiny Linux distribution – Alpine, size of about 5MB, and the command being executed is “true”.</p>
Git Utilities - Files That Will Be Pushed and Feature Branch Creation
2016-01-24T00:00:00-05:00
http://www.freshblurbs.com/blog/2016/01/24/check-what-will-push-and-brnach-for-features.html
<p>It’s trivial in <a href="https://git-scm.com/">Git</a> to see what files haven’t yet been added or have changes that haven’t been committed yet (<code class="language-plaintext highlighter-rouge">git status</code>). However, once you commit the changes – there’s no easy command to see all the files that would be pushed to the remote repository if you ran “git push”… or: there wasn’t one, until now.</p>
<p>The small bash function below does exactly that: shows all the files that are commited and
will be pushed if you run “git push”. Just put following code in ~/.bash_profile or ~/.profile
in your environment:</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="go">function gitsanity() {
</span><span class="gp"> currbranch=$</span><span class="o">(</span>git branch | <span class="nb">grep</span> <span class="s2">"*"</span> | <span class="nb">awk</span> <span class="s1">'{ print $2 }'</span><span class="o">)</span>
<span class="gp"> git log origin/$</span>currbranch.. <span class="nt">--stat</span>
<span class="go">}
</span></code></pre></div></div>
<p>and when you type “gitsanity” in a git workspace you should get an output similar to:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>→ gitsanity
commit 82f5e470d317af6503d15b586d36058564c00c5d
Author: Irakli Nadareishvili <email redacted>
Date: Sun Jan 24 16:42:12 2016 -0500
edited for clarity
_posts/2016-01-24-check-what-will-push-and-brnach-for-features.md | 19 ++++++++++++++++---
1 file changed, 16 insertions(+), 3 deletions(-)
commit 95cf7fa0c6eb708080c46ba1799471ede5e435b2
Author: Irakli Nadareishvili <email redacted>
Date: Sun Jan 24 16:40:01 2016 -0500
fixed typo
_posts/2016-01-24-check-what-will-push-and-brnach-for-features.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
</code></pre></div></div>
<p>which shows the list of commits that haven’t been pushed to the remote server, yet. Voila!</p>
<h3 id="quickly-creating-feature-branches">Quickly creating feature branches</h3>
<p>While we are on the subject, making changes to the main branch is usually an anti-pattern
for code development. Most teams create <a href="http://martinfowler.com/bliki/FeatureBranch.html">“feature branches”</a> where they do development and submit the diff as “pull request” once
they are done.</p>
<p>Libraries such as <a href="https://github.com/nvie/gitflow">git flow</a> and Github’s UI help with
the creation of feature branches, under certain circumstances, but they are also quite
opinionated and overbearing. If you don’t need the rest of the baggage that comes with
larger frameworks and just need a quick way of branching for features, following bash
function will do it in a targeted way:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Branch code for feature development. $1 is the name of the new branch
function branchcode() {
if [ "$#" -ne 1 ]
then
# No parameter provided.
echo "Please provide single parameter that is the name of the feature branch"
return 1
fi
git checkout -b $1
git push --set-upstream origin $1
}
</code></pre></div></div>
Great Sublime Text Color Schemes for Javascript Development
2016-01-23T00:00:00-05:00
http://www.freshblurbs.com/blog/2016/01/23/great-sublime-text-themes-javascript-json.html
<p>One of the really great features of <a href="http://www.sublimetext.com/">Sublime Text</a> editor is that it allows setting syntax-specific color schemes – meaning: you can have a different syntax highlighting colors for your Markdown files as opposed to your Javascript files etc. You can do this, by opening a file of the corresponding type in Sublime and then from the menu go to: Preferences -> “Settings More” -> “Syntax Specific - User”</p>
<p><img src="/img/content/sublimetext-theme-per-type.png" width="575" /></p>
<p>By far the most popular family of color schemes, in Sublime-universe, is: Monokai family. That said, if you really care about the visual appeal of your text editor (you should: as a programmer you probably spend most of your day staring at it) you will set multiple color schemes depending on the file type.</p>
<p>Following is a list of various themes and the file types I use them with, that I have found super-convenient (please note: some of these themes assume that you already have <a href="https://packagecontrol.io/packages/SublimeLinter">SublimeLinter</a> package installed):</p>
<ol>
<li>
<p>General color scheme: <a href="https://packagecontrol.io/packages/Theme%20-%20Soda">Monokai Soda</a>. This is actually a Theme, rather than a color scheme, but when you install the theme, it also enables corresponding color schemes.</p>
<p><code class="language-plaintext highlighter-rouge">"color_scheme": "Packages/User/SublimeLinter/Monokai Soda (SL).tmTheme",</code></p>
</li>
<li>
<p>Markdown: <a href="https://packagecontrol.io/packages/MarkdownEditing">MarkdownEditing</a> is a very nice theme for editing Markdown files. It also comes with a light theme, which I use for the Distraction-Free mode.</p>
<p><code class="language-plaintext highlighter-rouge">"color_scheme": "Packages/MarkdownEditing/MarkdownEditor-Dark.tmTheme",</code></p>
</li>
<li>
<p>Javascript: <a href="https://packagecontrol.io/packages/Sunnyvale%20Color%20Scheme">SunnyVale</a>. I love Monokai color scheme, but have come to prefer much more subtle SunnyVale theme for Javascript files since I spend a lot of time editing those and the bright Monokai colors were becoming somewhat tiresome.</p>
<p><code class="language-plaintext highlighter-rouge">"color_scheme": "Packages/User/SublimeLinter/SunnyVale Theme Dark (SL).tmTheme",</code></p>
</li>
<li>
<p>JSON: <a href="https://packagecontrol.io/packages/Monokai%20Neue">Monokai Neue</a>. This is the only theme that highlights JSON keys deep down the hierarchy. Most themes only highlight top-level keys.</p>
<p><code class="language-plaintext highlighter-rouge">"color_scheme": "Packages/Monokai Neue/Monokai-Neue.tmTheme",</code></p>
</li>
</ol>
Front-End Web Development's DX Is Going Downhill
2016-01-18T00:00:00-05:00
http://www.freshblurbs.com/blog/2016/01/18/front-end-development-developer-experience.html
<p>Dont’ get me wrong: I appreciate the enormous conceptual breakthroughs we’ve made, by constantly revolutionizing how we develop front-end on the web. However, it’s become impossible to ignore how much more complicated the whole environment is now. And – how negatively it affects developer experience.</p>
<p>In an oversimplified view, this is what we have done with front-end development in the past 5 years:</p>
<h2 id="front-end-web-development-circa-2011">Front-end Web Development Circa 2011:</h2>
<ol>
<li>Master basic HTML & CSS (granted: spend ton of time struggling with cross-browser issues)</li>
<li>Find some useful jQuery plugins (didn’t really need to know jQuery that much, let’s be honest) + learn how to make jQuery Ajax calls.</li>
</ol>
<p>Result: you were the Resident Ruler of the Webs!</p>
<h2 id="front-end-web-development-circa-2016">Front-end Web Development Circa 2016:</h2>
<ol>
<li>Webpack or 5 other alternatives of the day</li>
<li>Gulp or Grunt (if you need dev/stage/prod environment - webpack won’t do it)</li>
<li>React (or Angular 2? Or Ember. OK, at least not Backbone)</li>
<li>Realize React alone does nothing. Look into Flux implementations (which of the 10?). Maybe Alt. People say it has great docs. Or Redux?</li>
<li>SASS… Wait – now you want Compass… Wait, now somebody told you: Bourbon is cooler…</li>
<li>At least you’ve already mastered Bootstrap? Nah, Material UI, you are doing React!</li>
<li>What do we do about “continuous integration” to make all these things actually work together and not drive everybody crazy? Choices, choices…</li>
<li>Not done yet: wanna play with GraphQL and Relay while you are at it?</li>
</ol>
<p>The most likely end-result: a month into ‘research’ and you haven’t accomplished anything…</p>
<p>And no: Yeomen doesn’t magically solve this problem.</p>
<p><img src="/img/content/yeoman-isnt-answer.jpg" alt="" /></p>
Microservices Is No Free Lunch - But It Is Smart Nutrition
2015-12-18T00:00:00-05:00
http://www.freshblurbs.com/blog/2015/12/18/microservices-smart-nutrition.html
<p>Pretty much every talk, conversation or blog post about Microservices architecture makes a point of warning its audience that this novel Architectural style, while bringing many benefits, does significantly increase operational complexity. One of the first and, probably, most cited writings on this subject is: <a href="http://highscalability.com/blog/2014/4/8/microservices-not-a-free-lunch.html">Microservices - Not A Free Lunch!</a> by <a href="https://twitter.com/benjaminwootton">Benjamin Wootton</a>. It was followed by Martin Fowler’s <a href="http://martinfowler.com/bliki/MicroservicePrerequisites.html">blog post</a> where he coined the ‘tall-enough to do Microservices’ meme.</p>
<p>While these warnings certainly have some ground, at least for now, I think they only tell a part of the story. I recently discussed the “partial truth” issue at the <a href="http://austin2015.apistrat.com/schedule/">API Strategy and Practice Conference</a> in Austin, TX (see: <a href="http://www.freshblurbs.com/pdfs/Microservices-Blind-Spots.pdf">Slide Deck</a> and <a href="http://www.freshblurbs.com/audio/apistrat2015.mp3">Audio</a>) and it was very kindly received, so I wanted to also explain my thoughts on this blog.</p>
<h2 id="what-do-we-gain-with-microservices">What Do We Gain with Microservices?</h2>
<p>The critical question to ask, when considering Microservices architecture is: why would we want it, if it significantly complicates operational complexity?</p>
<blockquote>
<p>“there is no single development, in either technology or management technique, which by itself promises even one order of magnitude [tenfold] improvement within a decade in productivity, in reliability, in simplicity.” - Fred Brooks, <a href="http://worrydream.com/refs/Brooks-NoSilverBullet.pdf">“No Silver Bullet”</a></p>
</blockquote>
<p>According to Fred Brooks, software systems have essential complexity that cannot be removed without also taking away essential functionality of the system. There’s part of the system complexity that can be optimized with better processes or better architecture (“Accidental Complexity”), but there’s limit to what we can optimize.</p>
<p>Larger the system, larger its functionality - therefore less is the part that we can “optimize”. This is especially true for so-called: enterprise systems, obviously. As my friend <a href="https://twitter.com/mitraman">Ronnie Mitra</a> aptly explains: generally speaking, we are not removing complexity, we are shifting it from one area to another. There’s also an excellent, deeper discussion of this point that you can find in <a href="https://twitter.com/mattmclartybc">Matt McLarty</a>’s recent blog post: <a href="http://www.apiacademy.co/calling-all-architects-its-time-to-develop-a-complex/">Calling All Architects: It’s Time to Develop a Complex!</a></p>
<p>I believe this “shifting complexity” point is extremely true for Microservices architecture. The claim that MSA “simplifies” system implementation, as opposed to its ‘arch-nemesis’ Monolith is generally untrue. What Microservices architecture actually does is: it shifts complexity from the space of code design and implementation, into: operations.</p>
<p>Why is this good, you may ask? If we are just shifting complexity from one place to another, what do we really gain?</p>
<p>What we gain is: moving complexity into the area where we know how to automate. We have learned <strong>a lot</strong> in the past decades about automation of operations, but we really haven’t had any significant success in automation of software architecture design or development. Remember all those RAD tools? Yeap, they didn’t really work. So:</p>
<blockquote>
<p>With Microservices architecture we are taking complexity out of the area we aren’t good automating (software design and development) and moving it into the area we have become good at automating: operations.</p>
</blockquote>
<p>And that really is the big, essential win with Microservices architecture. That is also why “increased complexity” of operations in Microservices is not scary (it’s by design) and why Microservices isn’t just “rebranded SOA”: Microservices is the child of its time – the time when we learned effective ways of automating OPs.</p>
How-to: HTTP Caching for RESTful and Hypermedia APIs
2015-12-12T00:00:00-05:00
http://www.freshblurbs.com/blog/2015/12/12/http-cache-restful-apis.html
<p>Cache headers have been an essential part of the HTTP spec from the very beginning. They have played crucial role in scaling web to the enormous size that it has today. Or, at least: the statement is true when we talk about the “human web”. Unfortunately, vast majority of APIs (the “machine web”) either completely ignore HTTP-level caching, or have implementations that are different levels of broken.</p>
<p>Following is a quick guide for implementing HTTP caching properly in your APIs.</p>
<h2 id="the-role-of-http-caching">The Role of HTTP Caching</h2>
<p>If you ask a randomly-selected developer what caching is for, more likely than not you will get an answer that it’s for “making things faster”. Now, that is a very generic answer and actually not accurate when we are talking about network-level caching (which HTTP caching is a part of). Network-level caching is not for making a slow computation faster. Its primary purpose is to increase scalability – throughput defined in requests/sec that we can process without degrading performance, compared to a single-user scenario. Generally speaking, speed of response when there’re few users connected should already be at the desired level, using other forms of optimization.</p>
<blockquote>
<p>Network-level caching is appropriate for improving throughput (scalability), but not: response time under low levels of load (speed).</p>
</blockquote>
<h2 id="two-use-cases-for-http-caching">Two Use-Cases for HTTP Caching</h2>
<p>Given the role of HTTP caching we explained above, you can use this type of caching for both mostly-static data, as well as: dynamic i.e. rapidly changing data.</p>
<p>If you are dealing with dynamic data, you cannot cache for long periods of time, such as: days, hours or sometimes even minutes because data becomes stale too quickly. That doesn’t mean, however, that such data shouldn’t be cached at all.</p>
<p>Since network-level caching is mostly used for increasing the throughput, it makes sense to cache responses even for very short periods of time. Let’s see how this works.</p>
<p>If you have low load-levels, there’s no sense in caching something for several seconds, as most clients won’t be able to reach cached data: the rate of cache misses compared to cache hits will be very high. However, when the load increases (let’s say to: hundreds of requests/sec) even a 5 second cache will be a lifesaver, satisfying thousands of requests from cache, rather than origin providing very effective protection for the backend systems by avoiding database hits etc. The amazing thing about this type of caching is that: it becomes more effective as the load on the system increases (more cache hits before cache expires).</p>
<p>When I worked at <a href="http://www.npr.org">NPR</a>, we were using this type of caching extensively. With a news website you obviously cannot cache content for too long: reporters and journalists will update an article as they see fit and they have very little patience for the article not refreshing despite the edit they made. However, if you cache content for even very short time periods, you get huge payback when millions of readers are simmultanously accessing the very same page/API, during a breaking news event of some kind.</p>
<p>This is the kind of scenario in which caching even dynamic content makes a lot of sense. Most people who have worked on high-traffic systems would have used this approach.</p>
<p>The second type of caching that can and should be used extensively deals with nearly-static data. In any application you have plenty of such data-sets, ranging from: list of coutries, states, cities (any domain), insurance providers (healthcare), podcasts, series and topics (news media), currencies (banking) etc. These lists do change, and generally we have no idea when they will change, but we do know that they change quite infrequently. Nearly-static data-sets are very effective target for long-term caching.</p>
<p>In general, the way we cache long-lasting data-sets vs dynamic data-sets in HTTP, is different.</p>
<h2 id="caching-dynamic-data-with-http">Caching Dynamic Data with HTTP</h2>
<p>If you have had an opportunity to hear <a href="https://twitter.com/mamund">Mike Amundsen</a> talk about distributed systems architecture, you may already know that in distributed systems deployed over large geographic areas (e.g.: the web) you cannot rely on the existance of shared understanding of “now” (or: time in general). This, among other things, has to do with basic physics: information cannot propagate instantenously due to the limit on speed of light. For instance, if a server in Chicago, at 11:55:00AM local time, tells a client in Melbourne, Australia that a response is valid until 11:55:02AM Chicago time:</p>
<ol>
<li>We will have to be sure that timezone conversions are done properly by every participant of that exchange.</li>
<li>We will need to assume clocks on Chicago server and Melbourne client are ideally synchronized (generally: a pipe dream).</li>
<li>For the client to leverage cache, response from Chicago server to Melbourne client will need to reach in less than 2 seconds, otherwise cache will be already invalid by the time response is recieved. Considering distance between Chicago and Melbourne, the theoretical limitation of speed of light and the actual speed of data-transmission on the public web, which is much slower: this goal may be very much unattainable.</li>
</ol>
<p>In distributed systems, deployed at large distances (such as: the web) the above assumptions are so unrealistic that using date-based caching instructions, such as: <a href="https://tools.ietf.org/html/rfc7234#section-5.3">Expires</a> header is <a href="https://www.mnot.net/cache_docs/#EXPIRES">highly ineffective</a>. Same is true for the combination of <a href="https://tools.ietf.org/html/rfc7232#section-2.2">Last-Modified</a> and <a href="https://tools.ietf.org/html/rfc7232#section-3.3">If-Modified-Since</a> headers which also rely on a shared understanding of date-time.</p>
<p>Instead, when caching resources for short periods of time you should be using HTTP caching instructions that do not rely on shared understanding of time, such as: <a href="https://tools.ietf.org/html/rfc7234#section-5.2.2.8">cache-control: max-age</a> and <a href="https://tools.ietf.org/html/rfc7232#section-2.3">ETags</a></p>
<h2 id="caching-near-static-data-sets">Caching Near-Static Data Sets</h2>
<p>If you are caching resources (API responses) for sufficiently long periods of time (hours, days, potentially: months) you usually do not have to worry about the issues related to date-time-based caching, that were described in the previous section.</p>
<p>For facilitating caching of near-static data, where we have no reliable clue about <strong>when</strong> data will become stale, but we know it won’t happen too soon and yet it will happen, you could use two approaches:</p>
<ol>
<li>Entity Tags (ETags) that don’t rely on shared agreement on time</li>
<li>Last-Modified HTTP header that is date-time-centric.</li>
</ol>
<p>Let’s see how each one of those works:</p>
<h4 id="using-entity-tags">Using Entity Tags</h4>
<p>In this workflow, for each response, server provides an ETag header in the response. For a specific “version” of the data, ETag has to be unique and constant, until the data changes:</p>
<div class="language-http highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">HTTP</span><span class="o">/</span><span class="m">1.1</span> <span class="m">200</span> <span class="ne">OK</span>
<span class="na">Content-Type</span><span class="p">:</span> <span class="s">application/vnd.uber+json; charset=UTF-8</span>
<span class="na">Expires</span><span class="p">:</span> <span class="s">Sat, 01 Jan 1970 00:00:00 GMT</span>
<span class="na">Pragma</span><span class="p">:</span> <span class="s">no-cache</span>
<span class="na">ETag</span><span class="p">:</span> <span class="s">"88d979a0a78942b5bda05ace4214556a"</span>
… the rest of the response …
</code></pre></div></div>
<p>In a number of implementations, ETag is some sort of a hash of the response payload, but it can really be anything as long as it’s unique and consistent with the change of data (same response = same ETag).</p>
<p><strong>Important:</strong> Please note that while we are discussing ETags in the context of caching, ETag HTTP header is not, technically, a “caching” header per se. It’s part of the <a href="https://tools.ietf.org/html/rfc7232">RFC7232 - Conditional Requests</a> specification, separate from the <a href="https://tools.ietf.org/html/rfc7234">RFC7234 - HTTP 1.1 Caching</a> spec. HTTP clients handle ETags in the response and cache instructions independently. This is why the example response above has <code class="language-plaintext highlighter-rouge">pragma: no-cache</code> and the Expires header set in distant past. That specific API wants you to use ETags for determining freshness of the response, but not: cache headers. The two approaches can get in each other’s way through double-caching, if they instruct the client with incosistent hints. In general, you should either always use only one approach in your responses (explicitely disabling the other) or make absolute sure that the two hints lead to the same result, regardless of which one the client is paying attention to, or even if the client respects both instructions (“good” clients should).</p>
<p>The reason the example API decided to explicitely disable caching is: some clients (e.g. web browsers) make some default assumptions about the cache-ability of content when no cache headers are present. To the best of my knowledge, no major HTTP client makes assumptions on ETags, so we typically don’t need to worry about undefined ETags.</p>
<p>Once client receives the response and sees the ETag value, it should save the ETag and the response in the local store and issue subsequent requests to the same data with the <code class="language-plaintext highlighter-rouge">If-None-Match</code> header that points to the value of the ETag saved:</p>
<div class="language-http highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">Get /countries HTTP/1.1
Host: api.example.org
Content-Type: application/vnd.uber+json
If-None-Match: "88d979a0a78942b5bda05ace4214556a"
</span></code></pre></div></div>
<p>If the data-set hasn’t modified on the server, the server must respond with HTTP 304 and an empty body:</p>
<div class="language-http highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">HTTP</span><span class="o">/</span><span class="m">1.1</span> <span class="m">304</span> <span class="ne">Not Modified</span>
<span class="na">Content-Type</span><span class="p">:</span> <span class="s">application/vnd.uber+json</span>
<span class="na">Expires</span><span class="p">:</span> <span class="s">Sat, 01 Jan 1970 00:00:00 GMT</span>
<span class="na">Pragma</span><span class="p">:</span> <span class="s">no-cache</span>
<span class="na">Content-Length</span><span class="p">:</span> <span class="s">0</span>
</code></pre></div></div>
<p>If the data-set has modified on the server, the server must respond with a full HTTP 200 response and the new value of ETag.</p>
<h4 id="using-last-modified">Using Last-Modified</h4>
<p>In this workflow, for each response, server provides a “Last-Modified” header in the response, containing the last date the specific data was modified:</p>
<div class="language-http highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">HTTP</span><span class="o">/</span><span class="m">1.1</span> <span class="m">200</span> <span class="ne">OK</span>
<span class="na">Last-Modified</span><span class="p">:</span> <span class="s">Mon, 7 Dec 2015 15:29:14 GMT</span>
<span class="na">Content-Length</span><span class="p">:</span> <span class="s">23456</span>
<span class="na">Content-Type</span><span class="p">:</span> <span class="s">application/vnd.uber+json; charset=UTF-8</span>
… the rest of the response …
</code></pre></div></div>
<p>Once client receives the response and sees the Last-Modified header, it should save the value of the Last-Modified date-time and the corresponding response in the local store (cache). Client should issue subsequent requests to the same data with the <code class="language-plaintext highlighter-rouge">If-Modified-Since</code> header that points to the value of the date-time saved:</p>
<div class="language-http highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">Get /countries HTTP/1.1
Host: api.example.org
Content-Type: application/vnd.uber+json
If-Modified-Since: Mon, 7 Dec 2015 15:29:14 GMT
</span></code></pre></div></div>
<p>If the data-set hasn’t modified on the server, since the date-time indicated, the server must respond with HTTP 304 and an empty body:</p>
<div class="language-http highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">HTTP</span><span class="o">/</span><span class="m">1.1</span> <span class="m">304</span> <span class="ne">Not Modified</span>
<span class="na">Content-Type</span><span class="p">:</span> <span class="s">application/vnd.uber+json</span>
<span class="na">Content-Length</span><span class="p">:</span> <span class="s">0</span>
</code></pre></div></div>
<p>If the data-set has modified on the server, the server must respond with a full HTTP 200 response and the new value of the “Last-Modified” header.</p>
<h4 id="one-more-thing-vary-header">One More Thing: Vary Header</h4>
<p>When using cache-controlling headers (such as: <code class="language-plaintext highlighter-rouge">Last-Modified</code>, <code class="language-plaintext highlighter-rouge">cache-control: max-age</code>, and <code class="language-plaintext highlighter-rouge">Expires</code>) the communicating parties have to determine what constitutes “access to the same resource representation”. This is generally determined based on: “is the full request URL the same between two interactions”. However, depending on what you are doing, two requests with the same full URL may be pointing to different resource representations, because some of the headers in the exchange are different. Case in point: you don’t want a client to cache JSON representation when you are asking for XML representation at the same API endpoint. In this two cases URL can be the same, between two interactions, but the expected content type of the payload will be different because of the HTTP header values.</p>
<p>If values of HTTP headers have to be taken into account during HTTP caching, you need to utilize a specialO HTTP header called: <a href="https://tools.ietf.org/html/rfc7234#section-4.1">Vary</a>. Basically, this header lets communicating parties know which other headers they need to pay attention to, besides the URL, in caching determinations.</p>
<p>You can see an example of effective usage of the Vary header in our recent blog post where we <a href="http://www.freshblurbs.com/blog/2015/06/25/api-representations-prefer.html">discussed usage of the Prefer header</a>.</p>
Optimizing Nginx Configuration for High Loads
2015-11-28T00:00:00-05:00
http://www.freshblurbs.com/blog/2015/11/28/high-load-nginx-config.html
<p>Following is a quick guide to optimizing Nginx configuration, which should help if you expect significantly high traffic loads on your website.</p>
<p><strong>ATTENTION</strong>: at the time of writing this post, latest stable version of Nginx is: 1.8.0. Instructions provided here are for that version and may or may not be applicable for later versions, if you are reading this post in a far future.</p>
<h3 id="general-section">General Section</h3>
<ol>
<li><code class="language-plaintext highlighter-rouge">worker_processes auto;</code> (default is: 1)<br />
Optimal number of worker processes is usually equal to the number of CPU cores. Setting a higher value doesn’t normally improve performance, unless your workers do a lot of disk I/O. Latest versions of Nginx can automatically determine the optimal value if you set the configuration to ‘auto’, as shown above.</li>
<li><code class="language-plaintext highlighter-rouge">worker_rlimit_nofile 10240;</code> <br />
Changes the limit on the maximum number of open files (RLIMIT_NOFILE) for worker processes. Used to increase the limit without restarting the main process.</li>
</ol>
<h3 id="events-handling-under-events-section">Events Handling (under events section)</h3>
<ol>
<li><code class="language-plaintext highlighter-rouge">use epoll;</code> <br />
@see: <a href="http://nginx.org/en/docs/events.html">epoll</a></li>
<li><code class="language-plaintext highlighter-rouge">multi_accept on;</code> (default: off) <br />
If multi_accept is disabled, a worker process will accept one new connection at a time. Otherwise, a worker process will accept all new connections immediately.</li>
<li><code class="language-plaintext highlighter-rouge">worker_connections 4096;</code> (default is: 512) <br />
The maximum number of connections that each worker process can handle simultaneously. Increase this number if you need to. Testing required to determine optimal value.</li>
</ol>
<h3 id="timeouts-all-of-these-go-under-the-http-section">Timeouts (all of these go under the ‘http’ section)</h3>
<ol>
<li><code class="language-plaintext highlighter-rouge">keepalive_timeout 10;</code> (default is: 75 seconds)<br />
This should be as close to your average response time as possible. Set it higher and you are wasting server resources, potentially: significantly affecting performance. Set it lower and you are not utilizing keep-alives on most of your requests, slowing down client. We assume that on a fast system, most requests return in under ~ 5seconds.</li>
<li><code class="language-plaintext highlighter-rouge">keepalive_requests 1024;</code> (default is: 100)</li>
<li><code class="language-plaintext highlighter-rouge">client_header_timeout 10;</code> (default is: 60 seconds)<br />
Defines a timeout for reading client request header. If a client does not transmit the entire header within this time, the 408 (Request Time-out) error is returned to the client.</li>
<li><code class="language-plaintext highlighter-rouge">client_body_timeout 10;</code> (default is: 60 seconds)</li>
<li><code class="language-plaintext highlighter-rouge">send_timeout 10;</code> (default is: 60 seconds) <br />
Sets a timeout for transmitting a response to the client. The timeout is set only between two successive write operations, not for the transmission of the whole response. If the client does not receive anything within this time, the connection is closed.</li>
<li><code class="language-plaintext highlighter-rouge">sendfile on;</code> (default: off) <br />
Sendfile optimizes serving large files, such as images and videos. When the setting is ‘on’ Nginx will use the kernel sendfile support instead of using its own resources.</li>
<li><code class="language-plaintext highlighter-rouge">tcp_nopush on;</code> (default: off) <br />
@see: <a href="http://nginx.org/en/docs/http/ngx_http_core_module.html#tcp_nopush">tcp_nopush documentation</a></li>
<li><code class="language-plaintext highlighter-rouge">tcp_nodelay on;</code> (default: on)</li>
</ol>
<h3 id="gzipping-output">GZipping Output</h3>
<ol>
<li><code class="language-plaintext highlighter-rouge">gzip on;</code></li>
<li><code class="language-plaintext highlighter-rouge">gzip_vary on;</code></li>
<li><code class="language-plaintext highlighter-rouge">gzip_comp_level 2;</code></li>
<li><code class="language-plaintext highlighter-rouge">gzip_buffers 4 8k;</code></li>
<li><code class="language-plaintext highlighter-rouge">gzip_min_length 1024;</code></li>
<li><code class="language-plaintext highlighter-rouge">gzip_proxied expired no-cache no-store private auth;</code></li>
<li><code class="language-plaintext highlighter-rouge">gzip_types text/plain application/javascript application/x-javascript text/xml text/css application/json</code>;</li>
<li><code class="language-plaintext highlighter-rouge">gzip_disable "MSIE [1-6]\.";</code> <br />
if for some unknown reason you still care about older IE versions. ¯_(ツ)_/¯</li>
</ol>
<h3 id="caching-static-resources">Caching Static Resources</h3>
<p>If you are <a href="https://developers.google.com/speed/docs/insights/LeverageBrowserCaching">fingerprinting</a> your static resources (you should be) then you can get very significant performance boost from letting clients cache these resources for a long time:</p>
<ol>
<li>
<p>This normally goes under your virtual host definition:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> location ~* .(ttf|mp3|mp4|webm|ogg|jpg|jpeg|png|gif|ico|css|js)$ {
expires 365d;
}
</code></pre></div> </div>
</li>
</ol>
<h3 id="simple-abuse-protection">Simple Abuse-Protection</h3>
<p>DDOS is a sophisticated attack that has no universal defense and a reasonable defense takes dedicated solutions, but you can improve your chances by dropping naive attacks, with a configuration such as:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> limit_conn_zone $binary_remote_addr zone=addr:10m;
limit_conn addr 100;
</code></pre></div></div>
<p>The first command allocates 10MB-large shared memory area that will keep track of metadata (key/values) of connections being made, and the second command uses it to limit connections from a single IP address to: 100. Thus you can effectively limit harm from people who may run load-generators from a small number of attack computers.</p>
<p>You can also add configurations such as:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Request bodies larger than this will be written into temp files.
client_body_buffer_size 64k;
# same for header buffers
client_header_buffer_size 64k;
large_client_header_buffers 4 64k;
</code></pre></div></div>
<h3 id="open-file-limits-in-linux">Open File Limits in Linux</h3>
<p>Nginx can use up to 2 file descriptors per connection (keep-alive helps this, though). If you are running out of available file descriptors tweak following values in <code class="language-plaintext highlighter-rouge">/etc/security/limits.conf</code>:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>soft nofile 10240
hard nofile 20480
</code></pre></div></div>
<h3 id="sysctl-configuration">Sysctl Configuration</h3>
<p>Nginx connection queue can be affected by the directives in /etc/sysctl.conf which sets Linux defaults for queues, buckets, limit on open files and timeouts. You can tweak these by updating the ‘net.core.somaxconn’, ‘net.ipv4.tcp_max_tw_buckets’, ‘fs.file-max’ and ‘net.ipv4.tcp_fin_timeout’ settings. If you see error messages in the kernel log, increase these values until the errors stop. Sample values:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>net.core.somaxconn = 65536
net.core.netdev_max_backlog – The rate at which packets are buffered by the network card before being handed off to the CPU. Increasing the value can improve performance on machines with a high amount of bandwidth. Check the kernel log for errors related to this setting, and consult the network card documentation for advice on changing it.
net.ipv4.tcp_max_tw_buckets = 1440000
fs.file-max = 20480
net.ipv4.tcp_fin_timeout 15 # default: 60 sec. Shorter values allow free-ing up temporart porst (used for backend connections) faster. Important for high loads.
</code></pre></div></div>
<p>Once you change the file you will need to run: <code class="language-plaintext highlighter-rouge">sudo sysctl -p</code>.</p>
<p>Please note that “open file” is not the same as “file descriptor” so sysctl settings are not the same as setting in the limits.conf.</p>
<p>You can tune more settings (e.g. <code class="language-plaintext highlighter-rouge">net.core.netdev_max_backlog</code>) in sysctl.conf to improve TCP performance, if you need to. ESNet has couple of in-depth articles on the subject:</p>
<ul>
<li><a href="https://fasterdata.es.net/host-tuning/linux/">https://fasterdata.es.net/host-tuning/linux/</a></li>
<li><a href="https://fasterdata.es.net/host-tuning/linux/expert/">https://fasterdata.es.net/host-tuning/linux/expert/</a></li>
</ul>
<h2 id="bonus-phpfpm-tuning">Bonus: PHP/FPM Tuning</h2>
<p>If you are using Nginx as a proxy for PHP/FPM, there are additional, helpful tuning instructions at <a href="http://tweaked.io/guide/nginx/">tweaked.io</a> that you probably will be interested in.</p>
PSA: Avoiding Auto-Advance Nightmare in Powerpoint
2015-11-13T00:00:00-05:00
http://www.freshblurbs.com/blog/2015/11/13/powerpoint-auto-advance.html
<p>A dreadful feeling: you are in the middle of an important presentation and suddenly your slide auto-advances to the next one, without you doing anything, ruining your carefully-choreographed narrative and spoiling any storyline you were trying to relay. Worse yet: this happens on the next slide, and then the next one, and next one… leaving you feeling stupid and helpless in front of your audience. Clicking on the “Pause” button in the presenter view or any other quick attempts to salvage the situation are completely useless.</p>
<p>This has happened to me couple times. The first time, I secretely blamed it on the event’s Audio/Video person (duh!) and raised an angry eyebrow. When it happened the second time, however, I knew I should stop blaming other people and dig into the source of the problem.</p>
<p>After some digging-around I found what was causing the headache, so I am sharing it here with you, with the hope that it will save somebody else from frustration and embarassment.</p>
<h2 id="the-cause">The Cause</h2>
<p>The culprit of the problem is apparently a little-known and little-used feature of Microsoft Powerpoint called: Rehearse Timings. It can be found under Slideshow menu item:</p>
<p><img src="http://www.freshblurbs.com/img/content/powerpoint-advance/ppt-rehearse.jpg" width="300" /></p>
<p>The feature itself sounds pretty innocuous, maybe even useful - one more tool to help you prepare better, right? The thing nobody tells you, however, is that: as soon as you use the feature, Powerpoint sets a switch on the presentation that makes it auto-advance slides based on the timings recorded in your last “rehearsal”. Ouch! There may be people who want this, but for the rest 99.999% of us, this is a complete surprise and a curse.</p>
<h2 id="solution">Solution</h2>
<p>You can turn off the evil mode by going to Slide Show tab in the Ribbon, and turning off the corresponding checkbox:</p>
<p><img src="http://www.freshblurbs.com/img/content/powerpoint-advance/ppt-timings.jpg" width="500" /></p>
<p>Alternatively, you can also disable this from the main menu: <code class="language-plaintext highlighter-rouge">Slide Show > Set Up Show > Advance Slides > Manually</code></p>
The Whole Truth About Embedding of Dependencies in Microservices
2015-10-03T00:00:00-04:00
http://www.freshblurbs.com/blog/2015/10/03/dependencies-of-microservices-database.html
<p>As the year counts-down its remaining months, we can safely assume that the 2015 will go down in the annals of software engineering as: <strong>The Year of the Rise of Microservices</strong>. Throughout 2015, it has been next to impossible to attend a tech conference or have a conversation with a person in the field, without the subject of Microservices rearing its curious head.</p>
<p>Ironically, as much as everybody is raving about Microservices, and despite what <a href="https://en.wikipedia.org/wiki/Microservices">Wikipedia would have you believe</a>, there <a href="http://martinfowler.com/articles/microservices.html#CharacteristicsOfAMicroserviceArchitecture">isn’t even a single, formal definition</a> of Microservices that people can agree to. And yet we all drank the Kool-Aid, and yet we all listened in awe to the fascinating Microservices success stories; some of us even getting our own hands “dirty” and developing our own success stories of the field. Exciting!</p>
<h2 id="what-is-this-thing-called-microservices">What Is This Thing Called Microservices?</h2>
<blockquote>
<p>To me, Microservices is an architectural style that designs a complex system as a distributed network of interacting, specialized, independently-deployable web APIs, which we call “Microservices”.</p>
</blockquote>
<p>The Microservices architectural style has clear similarities to what many consider its parent style: Service-Oriented Architecture (SOA), but it would be a grave mistake to declare the two identical.</p>
<p>SOA and Microservices are very vividly the children of their respective times. SOA had its heyday during the rise of the Enterprise Software movement: when Enterprise Service Busses (ESBs) ruled supreme and the markets were flooded with sophisticated, proprietary vendor tools to help Enterprise Architects manage the complexity.</p>
<p>Microservices style is a child of a very different era: the era of agile software development and DevOps. The era in which “supreme ruling” is shunned at, considered a <a href="http://127.0.0.1:4000/blog/2015/10/03/dependencies-of-microservices-database.html">single point of failure (SPOF)</a> and a strong preference is given to many equal-right teams/services coming together, usually: independently, in achieving a shared goal. The role of an architect is changing to that of a facilitator, rather than a [benevolent] dictator.</p>
<h2 id="decentralized-data-storage">Decentralized Data Storage</h2>
<p>The property of being “independently deployable” is the hallmark of a properly designed microservice. Most of everything else is either the consequence of this key property or a requirement to achieve it.</p>
<p>We can wrap our legacy Java application inside a Docker container, we can “break it up” into a set of WAR files, but if we don’t have Independent Deployability, then we are just fooling ourselves. A litmus test I use asks: “If your Microservices-designed, complex application is hosted at Amazon Web Services, can you take an arbitrary number of your microservices and move them to Google Cloud, Azure, Rackspace etc. (substitute with your favorite cloud here), without changing a single line of code? Will your overall application still be functional and usable?” It is important the answer to this question to be an unequivocal “yes”.</p>
<p>Independent Deployability is tricky because it seemingly requires decentralized data storage: when you move Microservice Foo from AWS to Google Cloud, you need to be able to move its data storage, as well, without affecting any other microservice. Yet, for decades we have designed our architectures with centralized data storage:</p>
<p><img src="/img/content/microservices-storage/centralized-storage.png" alt="" /></p>
<p>Centralized data storage was convenient: it allowed dedicated, specialized teams (DBAs, sysadmins) to maintain and fine-tune these complex systems, obscuring the complexity away from the developers.</p>
<p>You will often hear people advocate for having microservices <strong>independently embed all their dependencies</strong>, in order to achieve Independent Deployability. The idea is that if every microservice manages and embeds its database, key-value store, search index, queue etc. then moving this microservice anywhere becomes trivial. This is what such deployment would look like:</p>
<p><img src="/img/content/microservices-storage/ms-data-storage.png" alt="" /></p>
<p>The postulate of wholesale embedding of [data storage] dependencies looks beautiful, on its surface, but unfortunately it is extremely non-practical (or: impossible) for all but the simplest cases. It is quite obvious that you will have very hard time embedding entire Cassandra, Oracle or ElasticSearch clusters in each and every microservice you develop. Especially if you are far down the Microservices journey and possibly have hundreds of microservices. This is just not doable. Neither is it necessary.</p>
<h2 id="the-whole-truth-about-dependencies">The Whole Truth About Dependencies</h2>
<p>Microservices <a href="http://martinfowler.com/articles/microservice-trade-offs.html#ops">can be scary at times</a>. It is natural for Microservices to feel unfamiliar, confusing or complicated, because it is new and we are all still learning it. What is helpful, however is keeping the main goal in mind, at all times, and re-aligning our beliefs accordingly. Here’s the core goal:</p>
<blockquote>
<p>We build complex systems with a Microservices architecture, because we want to induce the property of independent development- and deployability of sub-components the complex system is comprised of. Everything else is secondary.</p>
</blockquote>
<p>As a Microservice, I don’t have to carry-along every single dependency (such as: data storage system) in order to be mobile and freely move across the data centers (remember our Litmus Test?).</p>
<p>In my current job, I travel a lot for work. I’ve acquired important tips for doing it efficiently that I was completely indifferent to, during my previous life of a casual traveller. As any frequent traveller will tell you: the most important rule for mobility is: <a href="https://youtu.be/cnNyUGhXTsw?t=30">keeping your luggage light</a>. You don’t have to pack everything you may possibly need yourself. Nobody packs showerheads and towels on a business trip: you know you will find those at the hotel. Likewise, the trick to a Microservice mobility is not packing everything in, but ensuring that the deployment destination provides heavy assets, such as: database clusters, in a usable form. And that the microservice is written in a way that it can use those assets.</p>
<p>There is one caveat: data-sharing between microservices is still evil. Sharing data creates tight coupling between microservices, which will kill their mobility. I’ve spoken about various <a href="http://www.slideshare.net/irakli/microservices-in-practice">techniques to avoid data sharing</a> in a Microservices architecture. However, sharing a database cluster is absolutely OK, given that each microservice only accesses isolated, namespaced portions of it. Following is a diagram showing what a proper, sophisticated Microservices deployment can look in practice:</p>
<p><img src="/img/content/microservices-storage/ms-pragmatic-mobility-east.png" alt="" /></p>
<p>If we decide to move Microservice1 to another data-center, it will expect that the new data-center also has a functioning Cassandra cluster with compatible version (in our earlier metaphor: the destination hotel provides towels) but it will find a way to move its slice of data and won’t depend on existence or state of any other microservice, at the destination:</p>
<p><img src="/img/content/microservices-storage/ms-pragmatic-mobility-eu.png" alt="" /></p>
<h2 id="in-summary">In Summary</h2>
<p>Microservices do not have to “travel” heavy and pack everything they may possibly require. In complicated cases it is OK to have some reasonable expectations about the destination environment, especially when it comes to data storage capabilities.</p>
<p>The most important question we need to ask, when deciding embedding dependencies vs. “expecting” traits in an environment is: will our decision increase or decrease mobility? Our goal is to maximize deployment mobility of a microservice, that may mean different things in different contexts.</p>
Creating Client-Optimized Resource Representations in APIs
2015-06-25T00:00:00-04:00
http://www.freshblurbs.com/blog/2015/06/25/api-representations-prefer.html
<p>One of the most important design principles for an API program is to <a href="https://www.youtube.com/watch?v=wv52InGVHtQ">embrace that APIs are products</a>. It follows that successful APIs, much like products, must provide user-optimized experiences. Case in point: it is clearly inappropriate to send a mobile application large response payloads. Your API may get away with it when responding to a request from an enterprise system communicating over a high-speed fiber-optic connection. Some clients may even <em>want</em> to get a rich response, but in general assuming that network is reliable and/or bandwidth is infinite <a href="https://en.wikipedia.org/wiki/Fallacies_of_distributed_computing">is a fallacy</a>, on the web.</p>
<h2 id="a-brute-force-approach-field-filtering">A Brute-Force Approach: Field Filtering</h2>
<p>The fact that mobile clients are not fans of large response payloads is hardly a shocking news.</p>
<p>API teams have historically allowed customization of API responses using a somewhat brute-force approach known as “field filtering” – allowing an API client to indicate a list of returned fields in the request. It can look something along the lines of:</p>
<div class="language-http highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err"> GET https://api.example.com/users/123?fields=firstname,lastname,age
</span></code></pre></div></div>
<p>We have also seen solutions where all default fields are allowed, but a client has ability to “ban” potentially expensive fields from the response:</p>
<div class="language-http highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err"> GET https://api.example.com/users/123?exclude=biography,resume
</span></code></pre></div></div>
<p>The extreme case of this approach is: <a href="https://facebook.github.io/react/blog/2015/05/01/graphql-introduction.html">GraphQL</a>, which is basically “SQL” over HTTP, entirely concentrated on querying data-storage on the server and thus tightly coupling clients with the data-models of the server.</p>
<h2 id="there-is-a-better-way">There Is a Better Way</h2>
<p>One of the main problems with Field Filtering is that it encourages tight coupling of a client with an API server. By allowing such solution, we expect clients to maintain too granular of understanding for your API implementation. This can lead to unnecessary breaking changes and API versioning, which as <a href="https://www.mnot.net/blog/2011/10/25/web_api_versioning_smackdown">Mark Nottingham would have you know</a> is evil.</p>
<p>Instead, what we can do is: we can create tiered representations of responses. Each tier of a resource representation can have size-oriented or some other logical name, satisfying the need of tailoring output to a client group, without leading to extraneous coupling. As luck would have it: IETF already has an RFC that suits this purpose: <a href="https://tools.ietf.org/html/rfc7240">RFC 7240 - Prefer Header for HTTP</a></p>
<p>This is how you could create “minimal” (vs full “representation”) outputs:</p>
<div class="language-http highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err"> Get /users/123 HTTP/1.1
Host: api.example.org
Content-Type: application/json
Prefer: return=minimal
Vary: Prefer,Accept,Accept-Encoding
</span><span class="k">HTTP</span><span class="o">/</span><span class="m">1.1</span> <span class="m">200</span> <span class="ne">OK</span>
<span class="s"> Server: nginx/1.4.6 (Ubuntu)</span>
<span class="s"> Date: Sat, 27 Jun 2015 11:03:32 GMT</span>
<span class="s"> Content-Type: application/json; charset=utf-8</span>
<span class="s"> Transfer-Encoding: chunked</span>
<span class="s"> Connection: close</span>
<span class="s"> Vary: Prefer,Accept,Accept-Encoding</span>
<span class="s"> Preference-Applied: return=minimal</span>
<span class="s"> Access-Control-Allow-Origin: *</span>
<span class="s"> Access-Control-Allow-Headers: Content-Type</span>
</code></pre></div></div>
<p>Please note that including “prefer” in the <code class="language-plaintext highlighter-rouge">Vary</code> header of the response is
required per RFC 7240. It makes sure that some caching infrastructure won’t
cache a wrong representation of the resource, since multiple representations
will have the same URL, only differentiated by the <code class="language-plaintext highlighter-rouge">Prefer</code> header.</p>
<p>You can also see that the response acknowledged the preference by including
<code class="language-plaintext highlighter-rouge">Preference-Applied: return=minimal</code> in the response.</p>
<p>The RFC only allows two values for the “return” prefer type: <code class="language-plaintext highlighter-rouge">minimal</code> and
<code class="language-plaintext highlighter-rouge">representation</code>. However, it allows defining new preferences. We can use it
to define a preference that hints the use-case a client is interested in, and
therefore: the fields in the response. Let’s call this preference <code class="language-plaintext highlighter-rouge">respond-for</code>.</p>
<p>The name of the preference batch doesn’t always have to be size-oriented. For
instance, in case of news media and blogosphere, a logical preference that might
make sense, could be:</p>
<div class="language-http highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err"> Get /blog/1223 HTTP/1.1
Host: api.example.org
Content-Type: application/json
Prefer: respond-for=teaser
Vary: Prefer,Accept,Accept-Encoding
</span></code></pre></div></div>
<p>We’ve also seen elegant uses of the <code class="language-plaintext highlighter-rouge">prefer</code> header when clients ask the API
server to transclude some of the data that would normally be just linked from
the API response. This can be especially useful if otherwise the client would
need to make too many (N+1?) additional requests to retrieve the same data. For
instance:</p>
<div class="language-http highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">Prefer: transclude=availibility_calendar
Vary: Prefer,Accept,Accept-Encoding
</span></code></pre></div></div>
<p><a name="use-business-terms"></a> Word of caution: we need to make sure that
prefer headers, in our designs, refer to logical batches and not: individual
fields. Just moving “Field Filtering” from URL to the HTTP Headers is not a
solution, obviously.</p>
<h2 id="use-business-terms-for-prefer">Use Business Terms for Prefer</h2>
<p>I couldn’t recommend enough the approach of using domain-driven/business terms
for batching in the HTTP Prefer approach. The reason being: it leads to batch
names that survive changes in your system. As <a href="https://twitter.com/gregyoung">Greg Young
(@gregyoung)</a>, of CQRS and Event Sourcing fame,
says:</p>
<blockquote>
<p>Structure changes more often than behavior.</p>
<p>Your use-cases of a system tend to be reasonably stable over long periods of
time. How you interpret your internal data: the structure that you use has a
tendency of changing a lot. (Source: <a href="https://youtu.be/JHGkaShoyNs?t=619">Code on The Beach
2014</a>)</p>
</blockquote>
<p>This has also been my experience in building complex systems, therefore: if you choose business terms for batch names in <code class="language-plaintext highlighter-rouge">Prefer</code>, you will be able to defer their change for longer, and as we know: <a href="https://www.mnot.net/blog/2011/10/25/web_api_versioning_smackdown">versioning is an evil we avoid, in APIs</a>.</p>
<h2 id="tldr---in-conclusion">TL;DR - In Conclusion</h2>
<p>Do not use “field filtering” to provide more sensibly-sized response payloads to mobile applications or other clients. This may create too tight of coupling between the client and the server. Instead, use <a href="https://tools.ietf.org/html/rfc7240">HTTP Prefer Header for HTTP - RFC 7240</a>.</p>
<h2 id="acknowledgements">Acknowledgements</h2>
<p>I first learned this technique (much like most things I know about APIs) from my dear friend and colleague <a href="https://twitter.com/mamund">Mike Amundsen</a>. It builds upon thinking and work by amazing IETF contributors: <a href="https://twitter.com/jasnell">James Snell</a> and <a href="https://twitter.com/mnot">Mark Nottingham</a>, as well as probably others in the web community. I apologize if I accidentally missed anybody, but I am very grateful to all who contribute to the future of the better web.</p>
Twitter Photo Previews: Avoiding Crops for Sharing Perfection
2015-03-08T00:00:00-05:00
http://www.freshblurbs.com/blog/2015/03/08/twitter-photo-previews.html
<p>Twitter has been embedding photo previews in tweets for a while now. A lot of people
have found creative uses for this feature. The <a href="http://pixelcite.com/">Pixelcite</a>
tool by friends at <a href="https://twitter.com/nprviz">NPR’s Visuals Team</a> and
<a href="https://twitter.com/mkramer">Melody Kramer</a> is a great example that I use often.</p>
<p>Unfortunately, not everybody is as apt at understanding how exactly Twitter
manages photo previews as the authors of Pixelcite: <a href="https://twitter.com/onyxfish">Chris Groskopf</a>,
Melody and <a href="https://twitter.com/dannydb">Danny DeBelius</a>, which means: you
can see a lot of weirdly-cropped photos in a typical timeline.</p>
<p>Do you want to know how to size your photos to get the perfect photo previews?
Even if you want to display two images side by side? How about four?</p>
<p>If you do, please ignore how much this just sounded like an
<a href="https://www.youtube.com/watch?v=tGvHNNOLnCk">old Microsoft commercial</a>,
or a run-of-the-mill diet pill one, focus on remembering how an imperfectly cropped
photo lost a key message for you, last time, and keep reading…</p>
<p>Couple days ago, a <a href="https://twitter.com/mbseid">friend of mine</a> tweeted a post that
<a href="http://www.tweetbrander.com/crop-images-in-twitter-for-preview-pane/">started to demystify</a>
the secrets of Twitter photo previews. It was a great post, but it mostly concentrated on
explaining how Twitter crops. Instead, I want to tell you how to entirely avoid any
side effects of unpredictable cropping, and do it in repeatable way.</p>
<h2 id="3-rules-for-perfect-twitter-photo-preview-cropping">3 Rules for Perfect Twitter Photo Preview Cropping:</h2>
<ol>
<li>Do not tweet photos the largest side of which is larger than 1024 pixels.</li>
<li>Do not tweet portrait-oriented photos (height > width).</li>
<li>Use proper aspect ratio for each scenario (see below).</li>
</ol>
<p>One more: Do not try to tweet photos larger than 3MB (you can’t).</p>
<h3 id="for-a-single-photo-in-a-tweet">For a single photo in a tweet:</h3>
<p>Use landscape photos with aspect ratio of 2:1 (width twice wider than the height).</p>
<blockquote class="twitter-tweet" lang="en"><p>Someone is always wrong… <a href="http://t.co/Ih9S5OAjL7">pic.twitter.com/Ih9S5OAjL7</a></p>— Irakli Nadareishvili (@inadarei) <a href="https://twitter.com/inadarei/status/574380332994203649">March 8, 2015</a></blockquote>
<script async="" src="//platform.twitter.com/widgets.js" charset="utf-8"></script>
<h3 id="for-two-photos-in-a-tweet">For two photos in a tweet:</h3>
<p>Use aspect ratio of 1:1 (a square photo).</p>
<blockquote class="twitter-tweet" lang="en"><p>You CAN get perfectly-cropped two photos side-by-side on Twitter! <a href="http://t.co/zfkoyYlYwB">pic.twitter.com/zfkoyYlYwB</a></p>— Irakli Nadareishvili (@inadarei) <a href="https://twitter.com/inadarei/status/574380849426227200">March 8, 2015</a></blockquote>
<script async="" src="//platform.twitter.com/widgets.js" charset="utf-8"></script>
<h3 id="for-four-photos-in-a-tweet">For four photos in a tweet:</h3>
<p>Use landscape photos with aspect ratio of 2:1 (width twice wider than the height).</p>
<blockquote class="twitter-tweet" lang="en"><p>This is a test for a blog post. You are being annoyed for a good cause. <a href="http://t.co/BFZsY2iD2A">pic.twitter.com/BFZsY2iD2A</a></p>— Irakli Nadareishvili (@inadarei) <a href="https://twitter.com/inadarei/status/574376231531057152">March 8, 2015</a></blockquote>
<script async="" src="//platform.twitter.com/widgets.js" charset="utf-8"></script>
<h2 id="but-how-do-i-get-exact-aspect-ratios">But How Do I Get Exact Aspect Ratios?</h2>
<p>If your tweets are not coming from a CMS of sorts where developers with
mad skills can make magic happen for you, you are still fine, because most
photo editing tools can do fixed-aspect-ratio selections easily.</p>
<p>I am going to describe how to do it in Photoshop. Now that they have affordable
monthly subscription, accessible to mere mortals like me, they are on my
favorites list, but if Gimp is more like your kind of pie, their <a href="http://docs.gimp.org/en/gimp-tool-rect-select.html">documentation
has detailed description</a>
of how to select a specific aspect ratio on an image. Just search for ‘aspect
ratio’ on the linked page.</p>
<p>In Photoshop, this is very easy: just use the familiar select tool, but switch
the selection style to “Fixed ratio”:</p>
<p><img src="http://media.froyo.io/image/2O1w330a263I/photoshop-fixed-ratio.png" alt="" /></p>
<h2 id="final-words">Final Words</h2>
<p>This is not exact science. You will get predictable and consistently good
results following the above rules, but you should know that Twitter
will <strong>always</strong> pre-process your photos.</p>
<p>It will also violate some of its own rules and display things slightly
<a href="http://media.froyo.io/image/3g0D3G3I1w0d/twitter-photo-previw-css.png">differently on the web</a>
than in its apps. But that’s OK because: who uses Twitter web app, anyway, right?
Besides, the differences are typically subtle enough that you are still
way ahead of the competition by following the aspect ratio rules.</p>
Linux: Determine Network Gateway on eth0 Interface
2015-03-04T00:00:00-05:00
http://www.freshblurbs.com/blog/2015/03/04/current-network-gateway-eth0.html
<p>Easy-peasy:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">></span> route <span class="nt">-n</span> | <span class="nb">grep</span> <span class="nt">-v</span> <span class="s2">" 0.0.0.0"</span> | <span class="nb">grep</span> <span class="s2">"eth0"</span> | <span class="nb">awk</span> <span class="s1">'{print $2}'</span> | <span class="nb">head</span> <span class="nt">-n</span> 1
</code></pre></div></div>
Code on Demand in APIs: Dumb Clients, Smart Endpoints
2015-02-27T00:00:00-05:00
http://www.freshblurbs.com/blog/2015/02/27/code-on-demand-in-apis.html
<p>About a year ago I wrote a <a href="http://www.freshblurbs.com/blog/2013/12/12/rest-apis-client-side-scripting.html">blog post</a> about <a href="http://www.freshblurbs.com/blog/2013/12/12/rest-apis-client-side-scripting.html">scriptable Hypermedia Clients</a> i.e. the role of the <a href="http://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm">Code on Demand</a> hypermedia constraint - the one from the seminal Fielding dissertation.</p>
<p>The post was hopefully OK, but much more interesting was the discussion that ensued, in the comments section, with <a href="https://twitter.com/mamund">Mike Amundsen</a> about the future role of Code on Demand in APIs. By the end of the debate, we sortof partied at: “it’s probably too early for CoD in APIs”.</p>
<p>A lot of things have happened since the blog post. Among other things: I got an exceptional privilege of spending last year working right next to Mike and the rest of the amazing team of API experts at the <a href="http://apiacademy.co">API Academy</a>. I also got much more time to research and think about API design, experiment with various things, since APIs are now my primary job. Independent from me, Hypermedia architectural style has also become significantly more accepted in the industry. We very rarely run into API teams, at this point, who are not either building Hypermedia APIs, have considered it or at least have heard of it. This was definitely not the case year and a half ago.</p>
<p>The need to possibly revisit the question of Code on Demand in Hypermedia, has been brewing in my mind…</p>
<p>Yesterday we had a wonderful <a href="http://www.apiacademy.co/api360/">API360 Summit in Dallas</a>. Since we were fortunate to have some of the brightest minds as guest speakers and panelists, Summit ended-up into very insightful API design discussions. Furthermore, in the evening Mike, <a href="https://twitter.com/mitraman">Ronnie</a>, <a href="https://twitter.com/jharmn">Jason Harmon</a> and I met for drinks where Jason brought the topic of Code on Demand up, again.</p>
<p>While the impressions from the Summit and the following alcohol-enlightened discussion are still fresh in my mind, I want to share with you where I think the status quo of Code on Demand is in APIs now.</p>
<h3 id="semantic-gap-is-still-very-real">Semantic Gap Is Still Very Real</h3>
<p>Hypermedia API design is all about bringing the benefits of the universal interfaces, which we enjoy in the Human Web, to the world of the “machine web”: the world of APIs. If we can eliminate the spread of wasted effort that stems from each API provider designing essentially the same things in completely incompatible ways and everybody having to write individual clients for each of the thousands of web APIs - we can spend time/talent on more productive work.</p>
<p>But we have a significant problem: Human Web can enjoy a “single” kind of client (a web browser) only because browsers are always operated by humans, and because humans are incredibly skilled in making semantic sense of most unstructured data displayed by web browsers. Machines are virtually incapable of understanding the meaning (“semantics”) of anything that is not preprogrammed into them. However “preprogramming” creates tight coupling between an API client and the server, and leads to the waste and breaking changes that we have already mentioned as a significant problem.</p>
<p>The missing ability of machines to understand semantics of the information received is what we commonly refer to as “Semantic Gap” in Hypermedia API design.</p>
<h3 id="semantic-gap">Semantic Gap</h3>
<p>There are really only two ways we can address Semantic Gap:</p>
<ol>
<li>Make clients “smarter”</li>
<li>Keep clients “dumb” but send them instructions they need on-demand so that preprogramming (and resulting coupling) is still avoided. Mike Amundsen aptly calls this: “late binding in APIs”.</li>
</ol>
<p>Choice number one is what we have been doing to date. While creating sufficient artificial intelligence is not an immediately viable solution, we can fake “enough” intelligence by limiting and standardizing common semantic vocabularies. Efforts such as: <a href="http://www.iana.org/assignments/link-relations/link-relations.xhtml">IANA Link Relations repository</a>, <a href="http://microformats.org/wiki/existing-rel-values">microformats</a> and <a href="http://schema.org">schema.org</a> are all geared towards creating such vocabularies. Once and if we have enough of such vocabularies, we can use them in APIs via profile link relation [<a href="https://tools.ietf.org/html/rfc6906">RFC6906</a>] and machine-readable profile definition standards such as: <a href="http://tools.ietf.org/html/draft-amundsen-richardson-foster-alps-00">ALPS</a>.</p>
<p>While significant amount of work is put in this direction, it is not without challenges. For one: due to human nature, it is quite hard to make people use common anything, let alone vocabularies or standards. And to be fair, it is also hard to reach a point where enough vocabularies are available.</p>
<p>Let’s talk about the second choice:</p>
<h3 id="dumb-clients-smart-endpoints">Dumb Clients, Smart Endpoints</h3>
<p>A seminal breakthrough in Information Theory and modern communications came from <a href="http://en.wikipedia.org/wiki/Shannon%E2%80%93Weaver_model">Shannon–Weaver model</a> of communication, which is based on the idea of “dumb pipes and smart endpoints”. This model has had vital consequences in everything information-exchange-related, including even things like: <a href="http://martinfowler.com/articles/microservices.html#SmartEndpointsAndDumbPipes">Microservices</a>.</p>
<p>I believe that a similar approach of: Dumb Clients, Smart Endpoints can alleviate a lot of challenges of the Semantic Gap. If we can come up with the model where the clients don’t need to understand the semantics of communication and can remain largely “dumb”, by just understanding processing rules, we can get benefits very similar to those that Shannon and Weaver achieved by keeping transport layer completely agnostic of the information being transmitted.</p>
<h3 id="so-what-are-we-waiting-for">So, What Are We Waiting For?</h3>
<p>I do strongly believe that Code on Demand in APIs will happen. There really is no avoiding it, but I also am very accepting of the idea that timing has to be right.</p>
<p>The analogy to this is Human Web again. In Human Web the “code on demand” is: Javascript-based scripting of HTML pages (really: messages).</p>
<p>(Sideline: I am well-aware of the correct capitalization of “JavaScript” but I refuse to imply that JavaScript is anything like Java scripting, so I never capitalize “S” on purpose).</p>
<p>For better or worse, Javascript is almost ubiquitous nowadays, but a lot of us still remember the time from web development when it was a badge of honor to build a website/webapp without using any Javascript. In early 2000s, a lot of organizations had coding guidelines prohibiting use of Javascript or at least requiring that everything still worked with Javascript turned off. Eventually those requirements turned into “graceful degradation” requirement for Javascript, but most teams today will think you are crazy if you ask whether their web app works without Javascript.</p>
<p>While most of anti-Javascriptism could be attributed to problems with Internet Explorer, I believe we had to go through the phase where using Javascript was a ‘bad taste’ for us to develop things like HTML and CSS properly. I also agree with Mike Amundsen when he thinks we are still abusing Javascript and using it where it shouldnt be used. For instance: there’re many components and elements implemented in Javascript which really should just be provided by HTML. In HTML5 the spec authors finally added some of those (e.g. date picker) but it’s quite abysmal how archaic, say, select boxes are in HTML.</p>
<blockquote>
<p>If we jump into code-on-demand too early, we can hurt ourselves</p>
</blockquote>
<p>That said, now that Hypermedia API design is much more widely accepted, now that we have many more people understanding it, I think we can start having intelligent discussions about what Code on Demand is for APIs, where it is appropriate, and how it may look if implemented outside the scope of a traditional web browser.</p>
<h3 id="is-this-all-just-talk">Is This All “Just Talk”?</h3>
<p>So, do we have anything even remotely like Code On Demand for APIs? Obviously Javascript is CoD for HTML, but what about “real APIs?” Is this all theoretical, or is there any substance?</p>
<p>We do, actually. And not just things archaic and ugly like Java applets or Flash/Silverlight etc. apps. I believe we can easily call Javascript embed codes from Google Analytics, Chartbeat etc. very successful examples of CoD targeted at APIs. These Javascript snippets are only embedded in your pages to interface with an API and they certainly have no intention of rendering any UI (traditional use of JS for HTML).</p>
<p>Granted, Google Analytics or Chartbeat’s Javascript is still running in a browser, but the client that first enabled such interaction is largely irrelevant for the underlying principle. Point is: these dynamically loaded code snippets serve as the glue between the client (web browser) that doesn’t understand the semantic of the interaction and the server (Google Analytics). This glue code can also easily change if server-side logic changes, providing high degree of backwards and future compatibility.</p>
Migrating Yodiz Issues to Pivotal Using CSV Import/Export
2015-01-17T00:00:00-05:00
http://www.freshblurbs.com/blog/2015/01/17/migrate-yodiz-pivotal-tracker.html
<p><a href="http://www.yodiz.com/">Yodiz</a> is an integrated Scrum and bug manager that I have used for a while. For a variety of reasons, largely irrelevant to this post, I decided to move to <a href="https://www.pivotaltracker.com">Pivotal Tracker</a>, instead. Hence I was faced with the necessity to migrate outstanding issues from Yodiz to Pivotal Tracker.</p>
<p>Now, both Yodiz and Pivotal allow import/export of issues via CSV. However the two CSV formats and metadata required are significantly different. I needed to create a migration/conversion script to make things work. After some messing with both formats the migration script was ready. I am publishing it here in case it may save somebody some time.</p>
<p>Disclaimer: this is a [very] quick and [very] dirty work, in no way generic or complete. It may, however, save you several hours if you need to do something similar. Feel free to modify and use in any way. Distributed under MIT license.</p>
<h3 id="how-to-use">How to use:</h3>
<ol>
<li>Copy/paste package.json and csv.js into some folder</li>
<li>Run <code class="language-plaintext highlighter-rouge">npm install</code></li>
<li>Edit the head part of csv.js to modify locations of yodiz and pivotal CSV files. Take a good look at what the script does to make sure it makes sense for you</li>
<li>Run: <code class="language-plaintext highlighter-rouge">./csv.js</code> from bash prompt</li>
</ol>
<h3 id="packagejson">package.json:</h3>
<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
</span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"yodiz_csv_import_for_pivotal"</span><span class="p">,</span><span class="w">
</span><span class="nl">"version"</span><span class="p">:</span><span class="w"> </span><span class="s2">"1.0.0"</span><span class="p">,</span><span class="w">
</span><span class="nl">"description"</span><span class="p">:</span><span class="w"> </span><span class="s2">""</span><span class="p">,</span><span class="w">
</span><span class="nl">"main"</span><span class="p">:</span><span class="w"> </span><span class="s2">"csv.js"</span><span class="p">,</span><span class="w">
</span><span class="nl">"dependencies"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="nl">"csv-parse"</span><span class="p">:</span><span class="w"> </span><span class="s2">"^0.0.6"</span><span class="p">,</span><span class="w">
</span><span class="nl">"fs"</span><span class="p">:</span><span class="w"> </span><span class="s2">"^0.0.2"</span><span class="p">,</span><span class="w">
</span><span class="nl">"stream-transform"</span><span class="p">:</span><span class="w"> </span><span class="s2">"^0.0.6"</span><span class="p">,</span><span class="w">
</span><span class="nl">"underscore"</span><span class="p">:</span><span class="w"> </span><span class="s2">"^1.7.0"</span><span class="p">,</span><span class="w">
</span><span class="nl">"underscore.string"</span><span class="p">:</span><span class="w"> </span><span class="s2">"^3.0.0"</span><span class="w">
</span><span class="p">},</span><span class="w">
</span><span class="nl">"devDependencies"</span><span class="p">:</span><span class="w"> </span><span class="p">{},</span><span class="w">
</span><span class="nl">"author"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Irakli Nadareishvili"</span><span class="p">,</span><span class="w">
</span><span class="nl">"license"</span><span class="p">:</span><span class="w"> </span><span class="s2">"MIT"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>
<h3 id="csvjs">csv.js</h3>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#!/usr/bin/env node
</span>
<span class="kd">var</span> <span class="nx">basePath</span> <span class="o">=</span> <span class="nx">__dirname</span><span class="p">,</span>
<span class="nx">yodizFilename</span> <span class="o">=</span> <span class="dl">'</span><span class="s1">/bugs-yodiz.csv</span><span class="dl">'</span><span class="p">,</span>
<span class="nx">pivotalFilename</span> <span class="o">=</span> <span class="dl">'</span><span class="s1">/bugs-pivotal.csv</span><span class="dl">'</span><span class="p">;</span>
<span class="cm">/***** End of configuration ****/</span>
<span class="kd">var</span> <span class="nx">fs</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">fs</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">parse</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">csv-parse</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">transform</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">stream-transform</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">_</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">underscore</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">_s</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">"</span><span class="s2">underscore.string</span><span class="dl">"</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">input</span> <span class="o">=</span> <span class="nx">fs</span><span class="p">.</span><span class="nx">createReadStream</span><span class="p">(</span><span class="nx">basePath</span> <span class="o">+</span> <span class="nx">yodizFilename</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">myFile</span> <span class="o">=</span> <span class="nx">fs</span><span class="p">.</span><span class="nx">createWriteStream</span><span class="p">(</span><span class="nx">basePath</span> <span class="o">+</span> <span class="nx">pivotalFilename</span><span class="p">);</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">"</span><span class="s2">Starting Migration from: </span><span class="dl">"</span> <span class="o">+</span> <span class="nx">basePath</span> <span class="o">+</span> <span class="nx">yodizFilename</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">output</span> <span class="o">=</span> <span class="p">[];</span>
<span class="kd">var</span> <span class="nx">parser</span> <span class="o">=</span> <span class="nx">parse</span><span class="p">({</span><span class="na">delimiter</span><span class="p">:</span> <span class="dl">'</span><span class="s1">,</span><span class="dl">'</span><span class="p">})</span>
<span class="kd">var</span> <span class="nx">fakeBugId</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="kd">var</span> <span class="nx">migration_date</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">Jan 17, 2015</span><span class="dl">"</span><span class="p">;</span> <span class="c1">// Yodiz doesn't export dates. Faking.</span>
<span class="kd">var</span> <span class="nx">pivotal</span> <span class="o">=</span> <span class="dl">""</span><span class="p">;</span>
<span class="kd">var</span> <span class="nx">old_bug_no</span><span class="p">,</span> <span class="nx">title</span><span class="p">,</span> <span class="nx">description</span><span class="p">,</span> <span class="nx">status</span><span class="p">,</span> <span class="nx">created</span><span class="p">,</span> <span class="nx">responsible</span><span class="p">,</span> <span class="nx">description_url</span><span class="p">;</span>
<span class="kd">var</span> <span class="nx">all_yodiz_statuses</span> <span class="o">=</span> <span class="p">[</span><span class="dl">'</span><span class="s1">New</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">In progress</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">Resolved</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">In Verification</span><span class="dl">'</span><span class="p">,</span>
<span class="dl">'</span><span class="s1">Closed</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">Rejected</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">Reopened</span><span class="dl">'</span><span class="p">];</span>
<span class="kd">var</span> <span class="nx">pivotal_statuses</span> <span class="o">=</span> <span class="p">[</span><span class="dl">'</span><span class="s1">unstarted</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">started</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">finished</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">delivered</span><span class="dl">'</span><span class="p">,</span>
<span class="dl">'</span><span class="s1">accepted</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">rejected</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">started</span><span class="dl">'</span><span class="p">];</span>
<span class="kd">function</span> <span class="nx">parse_status</span><span class="p">(</span><span class="nx">yodiz_status</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">yodiz_status</span> <span class="o">=</span> <span class="nx">_s</span><span class="p">.</span><span class="nx">trim</span><span class="p">(</span><span class="nx">yodiz_status</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">position</span> <span class="o">=</span> <span class="nx">_</span><span class="p">.</span><span class="nx">indexOf</span><span class="p">(</span><span class="nx">all_yodiz_statuses</span><span class="p">,</span> <span class="nx">yodiz_status</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">pivotal_status</span> <span class="o">=</span> <span class="nx">pivotal_statuses</span><span class="p">[</span><span class="nx">position</span><span class="p">];</span>
<span class="k">return</span> <span class="nx">pivotal_status</span><span class="p">;</span>
<span class="p">}</span>
<span class="kd">var</span> <span class="nx">transformer</span> <span class="o">=</span> <span class="nx">transform</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">record</span><span class="p">,</span> <span class="nx">callback</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">old_bug_no</span> <span class="o">=</span> <span class="nx">record</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>
<span class="nx">title</span> <span class="o">=</span> <span class="nx">record</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="nx">replace</span><span class="p">(</span><span class="sr">/"/g</span><span class="p">,</span> <span class="dl">'</span><span class="s1">""</span><span class="dl">'</span><span class="p">);</span>
<span class="nx">description</span> <span class="o">=</span> <span class="nx">record</span><span class="p">[</span><span class="mi">2</span><span class="p">].</span><span class="nx">replace</span><span class="p">(</span><span class="sr">/"/g</span><span class="p">,</span> <span class="dl">'</span><span class="s1">""</span><span class="dl">'</span><span class="p">);</span>
<span class="nx">status</span> <span class="o">=</span> <span class="nx">parse_status</span><span class="p">(</span><span class="nx">record</span><span class="p">[</span><span class="mi">6</span><span class="p">]);</span>
<span class="nx">created</span> <span class="o">=</span> <span class="nx">record</span><span class="p">[</span><span class="mi">9</span><span class="p">];</span>
<span class="nx">responsible</span> <span class="o">=</span> <span class="nx">record</span><span class="p">[</span><span class="mi">10</span><span class="p">];</span>
<span class="nx">description_url</span> <span class="o">=</span> <span class="dl">''</span><span class="p">;</span>
<span class="nx">pivotal</span> <span class="o">=</span> <span class="nx">fakeBugId</span> <span class="o">+</span> <span class="dl">'</span><span class="s1">,"[</span><span class="dl">'</span> <span class="o">+</span> <span class="nx">old_bug_no</span> <span class="o">+</span> <span class="dl">'</span><span class="s1">] </span><span class="dl">'</span> <span class="o">+</span> <span class="nx">title</span> <span class="o">+</span> <span class="dl">'</span><span class="s1">",</span><span class="dl">'</span> <span class="o">+</span> <span class="c1">// 2</span>
<span class="dl">'</span><span class="s1">"",1,"</span><span class="dl">'</span> <span class="o">+</span> <span class="nx">migration_date</span> <span class="o">+</span> <span class="dl">'</span><span class="s1">","</span><span class="dl">'</span> <span class="o">+</span> <span class="nx">migration_date</span> <span class="o">+</span> <span class="c1">// 5</span>
<span class="dl">'</span><span class="s1">","bug","",</span><span class="dl">'</span> <span class="o">+</span> <span class="nx">status</span> <span class="o">+</span> <span class="dl">'</span><span class="s1">,</span><span class="dl">'</span> <span class="o">+</span> <span class="c1">// 5</span>
<span class="dl">'</span><span class="s1">"</span><span class="dl">'</span> <span class="o">+</span> <span class="nx">migration_date</span> <span class="o">+</span> <span class="dl">'</span><span class="s1">","","","</span><span class="dl">'</span> <span class="o">+</span> <span class="nx">created</span> <span class="o">+</span> <span class="dl">'</span><span class="s1">",</span><span class="dl">'</span> <span class="o">+</span> <span class="c1">// 4</span>
<span class="dl">'</span><span class="s1">"</span><span class="dl">'</span> <span class="o">+</span> <span class="nx">description</span> <span class="o">+</span> <span class="dl">'</span><span class="s1">","</span><span class="dl">'</span> <span class="o">+</span> <span class="nx">description_url</span> <span class="o">+</span> <span class="c1">// 2</span>
<span class="dl">'</span><span class="s1">","</span><span class="dl">'</span> <span class="o">+</span> <span class="nx">responsible</span> <span class="o">+</span> <span class="dl">'</span><span class="s1">"</span><span class="dl">'</span> <span class="o">+</span> <span class="dl">"</span><span class="se">\n</span><span class="dl">"</span><span class="p">;</span> <span class="c1">// 1 </span>
<span class="k">if</span> <span class="p">(</span><span class="nx">old_bug_no</span> <span class="o">==</span> <span class="dl">'</span><span class="s1">ID</span><span class="dl">'</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// Title line</span>
<span class="nx">pivotal</span> <span class="o">=</span> <span class="dl">'</span><span class="s1">Id,Title,Labels,Iteration,Iteration Start,Iteration End,Type,Estimate,Current State,Created at,Accepted at,Deadline,Requested By,Description,URL,Owned By</span><span class="dl">'</span> <span class="o">+</span> <span class="dl">"</span><span class="se">\n</span><span class="dl">"</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">status</span> <span class="o">===</span> <span class="dl">'</span><span class="s1">accepted</span><span class="dl">'</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// I had no need to import closed issues</span>
<span class="nx">pivotal</span> <span class="o">=</span> <span class="dl">''</span><span class="p">;</span>
<span class="p">}</span>
<span class="nx">callback</span><span class="p">(</span><span class="kc">null</span><span class="p">,</span> <span class="nx">pivotal</span><span class="p">);</span>
<span class="p">},</span> <span class="p">{</span><span class="na">parallel</span><span class="p">:</span> <span class="mi">10</span><span class="p">});</span>
<span class="nx">input</span><span class="p">.</span><span class="nx">pipe</span><span class="p">(</span><span class="nx">parser</span><span class="p">).</span><span class="nx">pipe</span><span class="p">(</span><span class="nx">transformer</span><span class="p">).</span><span class="nx">pipe</span><span class="p">(</span><span class="nx">myFile</span><span class="p">);</span>
<span class="nx">input</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="dl">"</span><span class="s2">error</span><span class="dl">"</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nx">callback</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">dir</span><span class="p">(</span><span class="nx">err</span><span class="p">);</span>
<span class="p">});</span>
<span class="nx">myFile</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="dl">"</span><span class="s2">finish</span><span class="dl">"</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">"</span><span class="s2">Finished, Pivotal CSV for bugs is in: </span><span class="dl">"</span> <span class="o">+</span> <span class="nx">basePath</span> <span class="o">+</span> <span class="nx">yodizFilename</span><span class="p">);</span>
<span class="p">});</span>
</code></pre></div></div>
Julia CLI on Mac OS-X
2014-12-27T00:00:00-05:00
http://www.freshblurbs.com/blog/2014/12/27/julia-mac-os-x-cli.html
<p><a href="http://julialang.org/">Julia</a> is one of those “next-generation” languages that have gained a lot of spotlight. It’s a specialized language targeted at “technical computing” i.e. things you would normally do in Fortran or R. Except, as opposed to Fortran, it is a modern, dynamic language with parallelism and distributed computing support built right into its core. Thanks to Julia’s outstanding JIT compiler: it is significantly faster than R, even in a non-distributed environment.</p>
<p>Julia is very easy to install. On OS X (my development platform of choice) you can simply download a DMG installer and be done in a single click. Compared to complex installation procedures of some of the other programming languages — this is great.</p>
<p>However, by default, when you install Julia DMG you are left to having to launch a separate Julia app for CLI. This wasn’t sitting well with me: I want to use Julia in my own terminal, on my own terms (obviously!) and be able to write/run shell scripts using Julia interpreter.</p>
<p>To get all of that done, you need to put the following line in your shell startup script (e.g. in ~/.bash_profile) which adds Julia’s executable to your shell’s path:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">export </span><span class="nv">PATH</span><span class="o">=</span><span class="s2">"/Applications/Julia-0.3.3.app/Contents/Resources/julia/bin:</span><span class="nv">$PATH</span><span class="s2">"</span>
</code></pre></div></div>
<p>Note: Julia-0.3.3 is the latest at the time of this writing, replace with the version you actually end-up installing.</p>
<p>Once you have added Julia to your path, you will be able to run Julia interpreter directly in your terminal of choice by simply typing <code class="language-plaintext highlighter-rouge">julia</code> and you can write shell scripts seamlessly, using following syntax:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#! /usr/bin/env julia</span>
<span class="c">#</span>
<span class="c"># Hello.jl</span>
<span class="c">#</span>
println<span class="o">(</span><span class="s2">"Hello World"</span><span class="o">)</span><span class="p">;</span>
</code></pre></div></div>
Responsive Web Design or Native Mobile Apps?
2014-11-10T00:00:00-05:00
http://www.freshblurbs.com/blog/2014/11/10/responsive-web-design-vs-native-mobile-development.html
<p>I have been a fan of Responsive Web Design ever since <a href="https://twitter.com/beep">Ethan Marcotte</a> coined the term in his <a href="http://alistapart.com/article/responsive-web-design">wonderful A List Apart article</a>. So it was no surprise that the very first initiative I started championing, two days into my new job at <a href="http://www.npr.org">NPR</a> in April 2011, was: Responsive redesign of npr.org.</p>
<p>Taking a large media website, with decades worth of content, through a major overhaul was no small deed, however. And the website was far from being my only concern. As the head of software engineering for NPR’s Digital Media, making sure we had sustainable strategy for NPR’s existing suite of native mobile applications was my top priority. Having very limited resources, it was becoming increasingly hard for Digital Media’s tech team to maintain a fleet of native applications across multiple platforms. The obvious question we were getting asked frequently was: did our new commitment to Responsive Web Design mean NPR would abandon native mobile app development and move everything to web apps? It did not.</p>
<p>The question was fair, however. Back then, and ever since, there have been very vocal advocates of the imminent sunset of native mobile development, in our industry. A group of respected developers and designers have been insisting, for years, that native mobile development is a waste and that every application should eventually be built with HTML/CSS/Javascript front-end. Beyond those individual advocates, major tech companies have also entertained the thought: Apple’s first-gen iPhone only supported web apps, Windows 8 Metro UI tried to make “HTML5” apps into first-class citizens of Windows ecosystem, Google has been trying to promote its suite of web apps (among other things: in the Chromebook experiment) for years now.</p>
<blockquote>
<p>This is a question every content publisher has asked themselves at some point: is Responsive Web Design (RWD) the [only] answer? Are native mobile apps a relic of the past?</p>
</blockquote>
<p>Certainly, there are examples of <a href="http://www.theverge.com/2014/9/2/6096609/welcome-to-verge-2-0">popular publishers answering this question with a “yes”</a>. And yet, the choice these publishers have made is not a blueprint for the rest of the industry. Responsive Design is not here to kill native applications. Such choice is simply a fallacy.</p>
<p>Blame the <a href="http://en.wikipedia.org/wiki/Second_law_of_thermodynamics">Second Law of Thermodynamics</a> if you will, or anything else you prefer, but whether we like it or not, in real life nothing ever has a single answer and applications are not an exception from this rule. Just because web developers find standardising on a single UI technology (HTML5/CSS/Javascript) more efficient, doesn’t make end-users suddenly and magically believe in the same. Whether we like it or not: the reality is that in many contexts:</p>
<blockquote>
<p>“the best mobile experiences are native” ~ David Cohn (source: <a href="https://twitter.com/inadarei/status/531257138115792896">Twitter</a>)</p>
</blockquote>
<p>Looking back at the choices we’ve made: NPR had huge success with its Responsive Design initiative, increasing both traffic as well as engagement, but we also very successfully <a href="http://www.npr.org/about/products/npr-one/">doubled-down on native mobile experiences</a> when it made sense and it was the absolute right thing to do.</p>
<h2 id="responsive-web-design-is-not-an-alternative-to-native-experiences">Responsive Web Design is not an alternative to native experiences.</h2>
<p>It is very important we understand how misleading the ‘choice’ of “RWD or native app” is. It is as wrong as thinking that if you have a native application and a website then your website doesn’t have to be responsive.</p>
<p>The truth is: all websites must be responsive because increasingly people are browing the web on their mobile devices and it is your obligation, as a publisher, to make sure they have the best experience if they visit your website on their smartphone. That said:</p>
<blockquote>
<p>A web browser is not the only application on our smartphone, and won’t ever be, so just because you have a responsive website doesn’t mean that you cannot create compelling native experiences as well.</p>
</blockquote>
<p>Whether you choose to create these additional experiences is up to you. Some publishers may have decided that they don’t want to push the envelope in that direction, but that just means: others will pick up the opportunity.</p>
<p>Native mobile applications are not going anywhere and the future of all websites is to be responsive. These two assertions are not mutually exclusive, they are complementary – don’t create apps when what you actually need is a website; but also don’t pretend webapps can completely replace native applications, because they can’t.</p>
We Don't Need Many Hypermedia Formats
2014-10-24T00:00:00-04:00
http://www.freshblurbs.com/blog/2014/10/24/single-hypermedia-type-to-rule-them-all.html
<p>Earlier today, I had a very interesting Twitter exchange with <a href="https://twitter.com/darrel_miller">Darrel Miller</a>. That exchange inspired me to share some of my thoughts about media types, in the context of Hypermedia Architecture and APIs.</p>
<h2 id="how-many-media-types-do-we-need">How Many Media Types Do We Need?</h2>
<p>Before we ask that question, what we really should be asking is: why do we even need media types? Or Hypermedia architecture in APIs?</p>
<h3 id="we-want-hypermedia-architecture-when-we-care-about-evolvability">We Want Hypermedia Architecture When We Care About Evolvability</h3>
<p>Increasingly, we need architectures that last and don’t require versioning every year. Most software systems are actually not good at this. There’s one specific architectural style (that of World Wide Web) which has proven over 25 years that it is very good at evolvability:</p>
<blockquote>
<p>“[Hypermedia Arch. Style] is software design on the scale of decades: every detail is intended to promote software longevity and independent evolution.” - Roy. T. Fielding</p>
</blockquote>
<p>How does Hypermedia style achieve this? By breaking tight coupling of the client and the server. In Hypermedia style the server is guiding the client through communication of <a href="http://en.wikipedia.org/wiki/Affordance">affordances</a>, while client is exchanging messages with the server, moving the application from one state to another.</p>
<h3 id="road-signs">Road Signs</h3>
<p>Basically: <a href="http://en.wikipedia.org/wiki/Affordance">affordances</a> communicated by the server are like road signs, they tell you what, where and how you can do. At the end of the day, it’s still the API client which “drives” the API “roads”, but it can navigate paths dynamically if people responsible for the roads care to post signs about: direction, speed/weight limits, reroutes etc. Without road signs you would need to memorize the entire map before you could drive anywhere. And what happens when the map is outdated? Same thing when a documentation for an API is outdated: you get lost.</p>
<h3 id="are-road-signs-good">Are Road Signs Good?</h3>
<p>When the first cars started getting on the roads, we can be sure things were very simple: you didn’t have speed limits, you had very few roads, and people generally knew directions without any signs. Most certainly, when road signs first started appearing they were huge nuisance for the drivers: now you had to do more work to drive around, obey additional laws etc. And probably the road signs were not standardized initially, so they could be more confusing than helpful.</p>
<p>Today, good road signs are the major contributor to the usability of roads (we will get to the point of GPS, hang tight). As soon as you have many roads and many drivers, you cannot do without them. You wouldn’t dream doing without them.</p>
<p>But can’t we communicate directions without “media types”? There must surely be many ways a server can expose available controls to the client, right? Yes, there are, but if everybody did their own thing, it would be like road signs that are different in every municipality and all around the world.</p>
<h2 id="familiarity-is-a-major-usability-factor">Familiarity Is a Major Usability Factor.</h2>
<p>In the “Hypermedia world” we talk a lot about “<a href="http://en.wikipedia.org/wiki/Affordance">affordances</a>” and that when we see a chair we know it “affords to be sat on, to put things on, or to throw it”, but we often skip the bit about: how do we know all of that? We can only understand what objects afford doing with them if we are familiar with their affordances!</p>
<blockquote>
<p>“Objects are only useful to us if they communicate affordances in ways familiar to us” - yours truly.</p>
</blockquote>
<p>When we publish an API, the clients of the API are our users. As <a href="Honza Javorek">@honzajavorek</a> said at the latest Nordic APIs recently:</p>
<blockquote>
<p>“You are designing your APIs for your users, not your database tables!”</p>
</blockquote>
<p>Evolvability is the concern of the API Publishers. They are the ones that need to evolve server-side code, without breaking the clients. The clients themselves only care about it indirectly: when and if we break their code. What clients do care about directly is that: Hypermedia APIs do, currently, require more work on the client-side. This is due to the lack of <em>proper</em> standardization. No API client developer currently loves Hypermedia style. We can do better.</p>
<h3 id="layered-architecture">Layered Architecture</h3>
<p>Most APIs do things that are the same, regardless the industry or app-specific requirements of the API:</p>
<ul>
<li>Pagination</li>
<li>Internationalization</li>
<li>Rights Management</li>
<li>Linking to other data items</li>
<li>Templated querying</li>
<li>Facilities for content update</li>
<li>Ability to provide metadata about semantic meaning of app-specific attributes</li>
<li>etc.</li>
</ul>
<p>the mechanics of doing these is the same for every API. Yet, every API does this differently. Just using a hypermedia type doesn’t solve the problem of familiarity: if you invent a new media-type every time you write a new API, then from the perspective of the API client: you are just making my life harder. The win is very small: basically a promise that you won’t break my code in the future, but that’s your problem to solve, anyway!</p>
<p>We are currently posting road signs that are different from city to city, from state to state etc. That hugely decreases their usability!</p>
<p>Instead, we could use layered approach:</p>
<ol>
<li><strong>Media type</strong> addresses concerns that are the same for all APIs (kinda like HTML does for websites).</li>
<li><strong><a href="http://tools.ietf.org/html/rfc6906">Profiles</a></strong> allow definition of semantics specific to an industry or an application. They should be layered to create additional opportunities for familiarity: if I am aware of a <a href="http://tools.ietf.org/html/rfc6906">profile</a> standard in the news industry and I point my client that knows corresponding media type + news industry profiles, I should be able to extract 80% of value from CNN’s or NPR’s API, even if they have 20% of org-specific semantics they also expose.</li>
</ol>
<p>So in this sense:</p>
<ol>
<li>
<p>Media type is for standardizing a lot of mechanics of exchanging messages and everything that is definitely common for any API. It should be kept very small and it should concentrate on defining all H-Factors to achieve maximum generality.</p>
</li>
<li>
<p>Profiles are where you would define additional semantics, both: ontology-wise (attributes) as well as more link relations. There’re too many link relations (even standard ones) for media types to enforce their implementation in clients.</p>
</li>
</ol>
<p>It’s a dangerous analogy, because HTML/CSS combination is geared towards rendering of unstructured content, but if you can forget that for a second and remember that APIs are all about structured data, a media type/profile separation is as crucial as separating markup from stylesheets in HTML/CSS. It is the same basic layering of concerns, in different context.</p>
<h3 id="ratios-for-efficiency">Ratios for Efficiency</h3>
<p>Why is layering efficient and why can it solve the animosity client devs have towards Hypermedia APIs? Because there’s huge opportunity for “not repeating yourselves”. I reckon (call it <strong>Irakli’s Conjecture</strong> if you will) that, in most APIs:</p>
<ol>
<li>30% of requirements are standard-enough to be covered by a media type</li>
<li>50% of requirements are standard-enough to be covered by an industry- and market- specific profiles</li>
<li>Only 20% are really specific to your application.</li>
</ol>
<p>Now imagine that there are standard SDKs (like: CURL for HTTP) to cover #1-3, then an API client only has to write 20% of the code they would normally write. And if we reach the state at which Profiles can be made fully machine-readable and automated (<a href="http://alps.io/spec/">ALPS</a>?) then you get yourself something fully automated like a GPS for cars, and the life is truly beautiful.</p>
<p>Would client devs still “hate” Hypermedia when and if it can make their lives that much easier? No chance!</p>
<h2 id="so-how-many-media-types-do-we-need">So, How Many Media Types Do We Need?</h2>
<p>People won’t write standard SDKs for 100s of media types. To have good, solid solutions we need to constrain this space. Ideally, I think we really only need one media type. In reality, humans can never agree on one way of doing things (hey, we still drive on different sides of the road in diff countries!), so there will probably be handful. That is fine: it will create some competition. However, if there are more than 3-4 major media types, then we are doing things wrong and I think that could be the biggest threat to Hypermedia taking-off as a predominant API architectural style.</p>
<p>Don’t create media types unnecessarily! Profiles is what you need.</p>
Various Ways Something Can Load On Startup in Mac OS-X
2014-07-14T00:00:00-04:00
http://www.freshblurbs.com/blog/2014/07/14/startup-items-mac-osx.html
<p>Many of us, Mac users, have probably found ourselves in this situation: something annoying or unnecessary starts at system load on a Mac and we want it to just stop. Unfortunately, there’re a whole bunch of ways this can happen so hunting the culprit down can be a challenge.</p>
<p>Below you can find listed various ways something can launch on startup, in OS-X. If you know any other way: please post in the comments.</p>
<p>So, here we go:</p>
<h2 id="unix-startup-scripts">Unix Startup Scripts</h2>
<ol>
<li><code class="language-plaintext highlighter-rouge">/etc/profile</code> - for all users</li>
<li><code class="language-plaintext highlighter-rouge">/Users/$USER/.bash_profile</code> - only for current user</li>
</ol>
<h2 id="launchd-scripts">Launchd Scripts</h2>
<ol>
<li><code class="language-plaintext highlighter-rouge">/Library/LaunchDaemons</code> - for all users, runs as root.</li>
<li><code class="language-plaintext highlighter-rouge">/System/Library/LaunchDaemons</code> - for all users, runs as root.</li>
<li><code class="language-plaintext highlighter-rouge">/Library/LaunchAgents</code> - for all users</li>
<li><code class="language-plaintext highlighter-rouge">/System/Library/LaunchAgents</code> - for all users</li>
<li><code class="language-plaintext highlighter-rouge">/Users/$USER/Library/LaunchAgents</code> - for current users only</li>
</ol>
<blockquote>
<p><strong>CAUTION</strong>: OS-X stashes essential utilities in <code class="language-plaintext highlighter-rouge">/System/Library/LaunchDaemons</code> and <code class="language-plaintext highlighter-rouge">/System/Library/LaunchAgents</code> so make sure you know what you are doing, before altering them.</p>
</blockquote>
<p>Helpful utility:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">></span> launchctl list
</code></pre></div></div>
<h2 id="startup-items">Startup Items</h2>
<ol>
<li><code class="language-plaintext highlighter-rouge">/Library/StartupItems</code></li>
<li><code class="language-plaintext highlighter-rouge">/System/Library/StartupItems</code></li>
</ol>
<h2 id="login-items">Login Items</h2>
<p>System Preferences > Users & Groups > [specific user] > Login Items</p>
<p><img src="/img/loginitems.png" alt="Login Items Screenshot" /></p>
<h2 id="a-cron-job">A Cron Job</h2>
<p>While cron jobs don’t run on startup, they are a way to make sure some app or service gets to run without an explicit start.</p>
<ol>
<li><code class="language-plaintext highlighter-rouge">crontab -l</code> - for current user</li>
<li><code class="language-plaintext highlighter-rouge">sudo crontab -l -u root</code> - for all users, run as root</li>
</ol>
<p>Modifying:</p>
<ol>
<li><code class="language-plaintext highlighter-rouge">crontab -e</code> - as current user</li>
<li><code class="language-plaintext highlighter-rouge">sudo crontab -e -u root</code> - as root</li>
</ol>
<h2 id="login-scripts">Login Scripts</h2>
<p><a href="https://developer.apple.com/library/mac/documentation/macosx/conceptual/bpsystemstartup/chapters/CustomLogin.html">Login Scripts</a> are deprecated, but some old or malicious apps may still be able to exploit this method.</p>
<h2 id="kernel-extensions">Kernel Extensions</h2>
<p>No user application should ever need to use this method, but somebody <strong>could</strong> run some code as a <a href="https://developer.apple.com/library/mac/documentation/Darwin/Conceptual/KernelProgramming/Extend/Extend.html">Kernel Extension</a>. Fair warning: messing with these is extremely dangerous and you should definitely know what you are doing.</p>
Dark Art of APIs in Connected Cars - API Days San Francisco
2014-06-16T00:00:00-04:00
http://www.freshblurbs.com/blog/2014/06/16/connected-cars-apis-design.html
<p>Today I am going to share with you some of my extremely opinionated thoughts about APIs and the Connected Cars space.</p>
<p>Most of my opinions come from two sources: my more recent API work with <a href="http://apiacademy.co">The API Academy</a>, and my experience before that— leading tech team at a super-prominent media company in Washington, DC. This seezling hot media company, which should remain anonymous, to the best of my knowledge has highest number of car integrations in the United States. So plenty of battle scars, and fun experiences, with cars there.</p>
<p>I will also share with you some of my strong beliefs that aren’t based on any specific work experience and therefore could be called pure speculation. That is: if you decided to be really mean about it. However, I would much rather you viewed those beliefs as timeless wisdom and accepted them at face value.</p>
<p>Either way, let me share with you my first mind-blowing revelation: There’s an all-out, global “arms race” waging in the automotive industry.</p>
<p><img src="/img/content/carsapi-armsrace.png" alt="There's an all-out, global "Arms Race" waging in the automotive industry" /></p>
<p>As all wars “worth” fighting for go — this one is also primarily about survival and dominance. Car manufacturers, content providers, app developers are all trying to get ahead with the Connected Cars. Leadership in the Connected Cars space is no longer merely a desirable thing. It has become an immediate necessity of very primal and basic nature: one related to survival. Winners of the race will be heftily rewarded, losers may sink in oblivion.</p>
<p>Time is also of great essence:</p>
<p><img src="/img/content/carsapi-graph.png" alt="Graph of Connected Cars Penetration Growth - Machina, 2013" /></p>
<p>Conencted Cars space is evolving rapidly. The joint <a href="http://www.gsma.com/newsroom/gsma-announces-the-business-impact-of-connected-devices-could-be-worth-us4-5-trillion-in-2020/">report</a> published by GSMA and Machina Research anticipates that 90 per cent of new cars in 2020 will have some form of in-vehicle connectivity, adding US$600 billion to value of the Connected Life. Current percentage of new cars with connectivity is estimated at less than 10%. Mobile connectivity in cars is predicted to be the top connected application in 2020.</p>
<p>Overall, Connected Car is widely recognized as a game changer for the automotive industry. Experts all agree that selling ‘just’ cars is a thing of the past. Mobility, connectivity and in-car user-experience will be leading decision considerations for car sales.</p>
<h3 id="challenges">Challenges</h3>
<p>Unfortunately, alongside enormous opportunities, there’re also some significant challenges in the Connected Cars space. The infant state of this market can probably only be compared to the chaos of the smartphones one before iPhone and the App Store.</p>
<p>Last year, Telefonica interviewed most of the major car manufacturers and published a very <a href="http://websrvc.net/2013/telefonica/Telefonica%20Digital_Connected_Car_%20Exec%20Summary_English.pdf">thoughtful report</a> which summarized 10 principle beliefs that executives at the automotive OEMs hold:</p>
<ol>
<li>There is a disconnect between mobile and automotive industry life-cycles</li>
<li>Connectivity will be necessitated by regulatory mandates (such as the European Commission initiative eCall)</li>
<li>Car manufacturers are unable to choose between built-in versus brought-in connectivity</li>
<li>Operators make it a nightmare for OEMs to provide global connectivity (e.g. due to ban on “permanent roaming”).</li>
<li>The Connected Car will cause an upheaval in the traditional dealership model</li>
<li>Connected Car will lead to new types of ownership models being developed</li>
<li>Autonomous vehicles are not on the immediate agenda for most OEMs</li>
<li>Payment models for how consumers pay for Connected Car services are still not yet developed</li>
<li>Manufacturers remain cautious towards the open app ecosystem</li>
<li>A connected lifestyle is a given</li>
</ol>
<p>I am not going to analyze the list, in detail, right now. We unfortunately simply don’t have time for that, in this talk. You can download the original <a href="http://blog.digital.telefonica.com/?press-release=connected-cars-report-2013">report by Telefonica</a> if you are interested.</p>
<p>The striking thing about the list, however, is: how self-centered it is. It’s predominantly written from OEM’s perspective. It almost exclusively reflects worries, aspirations and interests of car manufacturers first and foremost.</p>
<p><img src="/img/content/carsapi-bastard.png" alt="Selfish Bastard joke with a shot from the New Girl TV show" /></p>
<p>However, Connected Car is inherently a joint ecosystem of: OEMs, aftermarket device manufacturers, content providers and app developers. It’s true that the car is the facilitator, so it may not be the union of the equals, but take away any of the participants and you simply don’t have a sustainable ecosystem, anymore.</p>
<p>To be fair, the desire of automotive OEMs to supremely reign Connected Car environments is understandable—it’s a matter of survival, in their eyes, and they are trying to stay in full control. There is but one problem with such approach, and it is most eloquently summarized in the famous quote by Richard Feynman:</p>
<blockquote>
<p>“For a successful technology, reality must take precedence over public relations, for Nature cannot be fooled”<br />
~ Richard Feynman</p>
</blockquote>
<p>or put more simply: our desires can’t override the reality.</p>
<p>Let me give you an example of such reality. As I mentioned before, in my previous job I worked for one of the most valuable content providers in the United States that every automotive OEM had significant interest to include in their connected cars. On our side, we also very much wanted to work with them, since connected cars were large potential audience for us. It should have been a highly symbiotic relationship. Yet, work with the OEMs, while rewarding, was also full of barriers and unnecessary pain points.</p>
<p>For each of the integrations, we had to do things completely differently: in one case we were writing a web app, in another: using OEM’s binary SDK in our iPhone app to communicate with the car, in yet another one: writing a full in-dashboard experience. And mind you, it is not just the initial development, maintenance of the highly fragmented ecosystem is a much larger headache. Not to mention that our ability to update the apps once they were released was quite limited.</p>
<p>As a content provider and app developer, our developer experience was similar (or even subpar) to what it would have been writing J2ME apps on early, pre-iPhone mobile phones. Nobody can be happy with that experience.</p>
<p>What is worse: because the efforts of integrating with various OEMs are so fragmented, the end-user experience is often also subpar. You do not get slick end-user experience of iPhone apps, you get something much more like J2ME apps. We are pretty sure that is not where user expectations lie, however.</p>
<h3 id="three-immediate-solutions-for-connected-cars">Three Immediate Solutions for Connected Cars</h3>
<p>There are three things that automotive industry can do to make things significantly better right away.</p>
<p><img src="/img/content/carsapi-sol01.png" alt="OEMs need to implement a standard hypermedia type for their APIs." /></p>
<p>Fragmentation is undoubtedly #1 most damaging issue in the Connected Car industry. OEMs all want to do their own thing since they see originality as a way to maintaining differentiation and therefore—competitive advantage. This view is a fallacy. There are way too many car manufacturers for content providers and app developers to keep up with the variety. “Doing your own thing” means that eventually you simply won’t have the amount and freshness of apps that your less “controlling” competitors will. OEMs that care about creaitng vibrant app variety in their cars must make app developers’ life easier. Wide variety of apps is exactly what users expect in connected cars.</p>
<p>As a solution, some people have suggested that all OEMs should just deploy Android as the base OS. I am not sure it’s necessarily the best idea, for couple of reasons:</p>
<ol>
<li>Android may objectively not be the best-suited core OS for connected car space. A real-time OS makes significantly more sense for the context. For instance, I would bet that QNX outperforms Android in most car-specific scenarios.</li>
<li>I have zero confidence that OEMs will be able to all agree on something as fundamental as the core OS. That seems like an unrealistic and unnecessary aspiration. We should shoot for something much more realistic.</li>
</ol>
<p>In distributed systems we’ve had much success with the usage of <a href="http://amundsen.com/hypermedia/">Hypermedia</a>. The most distributed system humankind has ever built — the world wide web — uses a hypermedia type: HTML as its engine. Hypermedia types can serve as the unified communication language for highly non-homogenous networks. This approach has been so effective that some people even tried using HTML5 in the car space. I see using HTML5 as a stretch, since HTML5 is a hypermedia format created for a different context and not optimized for cars, but the intent seems right.</p>
<p>I believe the silver lining to be in creating a Connected Car-optimized hypermedia format that can energize the space just like HTML did for the World Wide Web. There’s already a large body of work in custom hypermedia types. I believe Connected Cars hypermedia type can be based on an existing popular, generic type, such as: <a href="https://rawgit.com/mamund/media-types/master/uber-hypermedia.html">Uber</a>, <a href="http://stateless.co/hal_specification.html">HAL</a>, <a href="https://github.com/kevinswiber/siren">Siren</a> or <a href="http://amundsen.com/media-types/collection/">Collection.json</a>.</p>
<p>A good example of taking a generic hypermedia type and customizing it for industry-specific needs is: <a href="http://cdoc.io">Collection.Document</a>, which was based on Collection.json and created for news media industry.</p>
<p><img src="/img/content/carsapi-sol02.png" alt="OEMs need to adopt a standard delegated, context-aware security + identity system" /></p>
<p>There’s enormous anxiety related to security in the Connected Cars. People are terrified by a thought of cars getting “hacked”. This may be a bigger issue for “self-driving” cars, but the solution for Connected Cars lies in:</p>
<ol>
<li>Compartmentalization — core car functions should be highly guarded. No third-party app should ever get any access to core driving functions like handling and/or braking.</li>
<li>Using standard, proven, delegation-based and contextual security framework such as OAuth that allows granular access to specific system features.</li>
</ol>
<p>We are already very familiar with the second one: when I install an app on my mobile phone it doesn’t just get access to everything. My phone asks whether the app should get access to: GPS, contacts, internet etc. We have very granular control over deciding if app is doing what we assume it should be doing or want it to be doing. Automotive apps need same kind of granular access.</p>
<p><img src="/img/content/carsapi-sol03.png" alt="Self-service dev portals, Robust, public docs, Dev sandboxes, App marketplace" /></p>
<p>Currently, only the lucky few can get access to OEMs and get their apps in a Connected Car. Almost the only way to get your app in, is to have partnerships with the car manufacturers. In most cases you can’t even get access to documentation without a group of lawyers signing stacks of papers.</p>
<p>There’s absolutely no way to develop Connected Car space by keeping it as a tightly-held, closed system. On the contrary, OEMs should build developer communities by providing things that communities require: documentation, self-service portal, sandboxes, kits, marketplace etc.</p>
<h3 id="multiple-ways-to-view-the-world">Multiple Ways to View the World</h3>
<p>This is where I could have ended my talk—by outlining three immediate steps that can be taken to improve Connected Cars space significantly.</p>
<p>But I’m really passionate about this space and I feel like we often talk about specifics, without stepping back to analyze the big picture. To paraphrase the “give fish vs. teach fishing” saying: we often talk about how to fry the fish, and don’t spend enough time on figuring out how fish is caught in the first place.</p>
<p>Connected Cars is a special case of Internet of Things (IoT). The context of IoT, forces driving it, are different enough that it requires fundamentally different kind of thinking, different approach to system design/architecture.</p>
<p>The challenges facing the Connected Cars are significant enough that we are going to need little bit of help from some great minds. Specifically the following four:</p>
<p><img src="/img/content/carsapi-gang-of-four.jpg" alt="Newton, Einstein, Niels Bohr, Roy Fielding" /></p>
<p>Loosely, in the order or decreasing amount of hair, we have: Isaac Newton, Albert Einstein, Niels Bohr and Roy Fielding.</p>
<p>First three are important because they all had seminal impact on humankind’s understanding of how physical world works. Roy Fielding, I would argue, had similarly seminal impact on our understanding of how Internet, the world wide web specifically, works and scales.</p>
<p>Scale, in general, has a lot to do with what model of world-view is appropriate for a problem space.</p>
<p>Isaac Newton had very mechanistic, highly organized view of the world: actions have reactions, if we know all participants and all rules, we can predict the future based on solid physical rules. This view of the world is the most comfortable for us, humans, since it brings the comfort of order and predictability. As you may remember from high-school physics, Newton’s model works reasonably well in highly controlled, average-distance (scale) scenarios. In networked environments, I would compare this scale to that of enterprise systems: integration of units of a single organization or data-systems of partner organizations. Such environment is highly controlled, usually interactions are limited to within a single data-center or on excellent connectivity, behind trust boundaries, with high level of predictability.</p>
<p>Einstein turned Newton’s world upside down. He asserted that at large scale everything is relative: time is relative, distance is relative, signals don’t propagate instantaneously, speed of light is the highest theoretical speed possible. Many things we had held sacred and reliable, time most importantly, became relative for us. I would say, World Wide Web and Web APIs are a good analogy of Einstein’s world: distances are long enough that many of the relativisms Einstein preached kick in effect. We cannot, anymore, rely on instantaneous execution at large distances. Since time is relative, locks at distance are unreliable and hence transaction-management is often impossible.</p>
<p>The complications introduced by “web scale” are a good explanation to why old SOA architectures did not scale on the web. Web APIs aren’t just web services thrown at mobile applications. They are fundamentally different in having to work at large distances. We learned a lot about how to do Web APIs right thanks to iPhones and Androids, using RESTful and <a href="http://www.infoq.com/articles/hypermedia-api-tutorial-part-one">Hypermedia APIs</a>.</p>
<p>The story doesn’t end there, however. Somebody else turned upside down Einstein’s world as well. It was Niels Bohr and Quantum Mechanics. Bohr said that not only mechanistic laws fall apart at large distances, but Einstein’s enhancements to Newton’s formulas are insufficient when we want to operate at very <em>small</em>, atomic and molecular distances. At these distances, not only things are relative, but they are inherently probabilistic. You can never precisely measure anything, since the act of measurement alters the value being measured.</p>
<p>Ironically, the thought of inherently probabilistic values was so radical back in the day that even Einstein, brilliant mind that he was, never could accept such notion of randomness. To his death Einstein rejected Quantum theories and even famously declared that: “God doesn’t play dice”. Of course, since then Quantum Mechanics has been proven by series of experiments and its applicability has been widely established.</p>
<p>I believe that Quantum Mechanics is analogous to IoT in that both operate at scales with high density of things. If on the web we had hundreds of millions or handful of billions of connected devices, with IoT that number is expected to grow hundred or thousand times. The rules and laws that we used for the Web won’t necessarily be applicable with such dense space. Just like Einstein’s world-view had to be augmented by Bohr, we will see fundamentally different approaches to tackle IoT space.</p>
<p>At very small distances, in low-energy and small devices environments we need more peer-to-peer solutions, probabilistic, Fuzzy logic and architectures that work well in that context.</p>
<p>I believe that Connected Cars space will combine web technologies with IoT technologies. In-the-car communication may well be predominantly Bluetooth-based while car-to-cloud communication will use familiar APIs, possibly enhanced to withstand patchy connectivity.</p>
<h3 id="most-importantly-it-has-to-be-fun">Most Importantly: It Has to Be Fun.</h3>
<p>Connected Cars space is in its very early infancy. We will learn much more about how to do it right. As we learn, we must have fun, however.</p>
<p>Engineering is the field where excitement is crucial for achieving great results. We all got started in this “racket” because it was enormous fun to tinker with machines and make computers do things. That early excitement has to last if we are to create great products.</p>
<p>In the example I mentioned before, when we had to integrate with various car systems in various inefficient ways — yes it was unproductive, but most importantly it was wrong simply because: it wasn’t fun.</p>
<p>Have fun!</p>
Jailbreak Your APIs — Presented at Computers, Freedom and Privacy Conference
2014-06-09T00:00:00-04:00
http://www.freshblurbs.com/blog/2014/06/09/linked-apis-computers-freedom-and-privacy-conference.html
<p><strong>We live in interesting times.</strong></p>
<p>There used to be a popular saying that a single issue of New York Times contains more information than what the average 17th-century person encountered in their entire lifetime. Of course, this was when New York Times was still primarily thinking in terms of “printed editions”. Those times now feel like Ice Age. Now it’s all digital, and it’s pretty much a continuous stream of information that never stops or takes a break.</p>
<p>The global informational overload, that we are constantly exposed to, can be overwhelming. It’s only natural that sometimes we wish we lived in simpler, less turbulent times. We wish we could just disconnect. The so-called “Digital Detox” is a witty phrase for a useful concept that for many of us is a way to keep our relative sanity.</p>
<p>The explosive surge of available data is not all evil, however. In reality, it brings us beautiful things such as: transparency, openness and an unprecedented feeling of global connectedness. We’ve never felt more connected to the rest of the world that we do now.</p>
<p><strong>We live in interesting times.</strong></p>
<p>Technology, computers and the Internet have brought us closer than ever before. We now take it for granted that you can be pretty much anywhere in the world, yet: get a real-time, front-row view of the breaking news half-way around the globe.</p>
<p>Unfortunately, the disappearance of informational boundaries has also, very painfully, surfaced our most polarizing differences. The globalized world is the world of clashing dissents. It leaves very little space for disagreement in the comfort of isolation, or at distance. We are all in each other’s faces now.</p>
<p>And yet, we want information, because:</p>
<blockquote>
<p>when information is put in the hands of the public it is the most powerful weapon to guarantee our freedom and our liberties. It is no coincidence that the very first thing any dictatorship, any oppressive regime does is: restrict access to data and information.</p>
</blockquote>
<p><strong>We live in interesting times</strong></p>
<p>A lot has been done in the past years. The Open Data initiative is one of the most exciting initiatives that has been going for several years now. Never before has public had this much access to government information, at all levels, directly through the Internet, in near real-time. And I’m many advocates in the audience would agree that “timeliness” is super important for the freedom of information.</p>
<p>The key technology that facilitates this timely access is: APIs. API is an abbreviation for: Application Programming Interfaces. That doesn’t really explain much, but in more human terms: APIs are the informational “pipes” that allow various data-sets to be reliably and efficiently transmitted over the Internet.</p>
<p>APIs were not invented for Open Government or Open Data, however. Their initial development is related to our increasingly mobile lifestyle. APIs are what connect our mobile applications to the so-called “cloud” i.e. the data centers that provide centralized data storage and processing for the apps.</p>
<p>APIs have played an undeniably critical role in the mobile revolution of recent years. However, for APIs to play a similar role in the Open Data revolution we need them to become -much- better.</p>
<p>The problem with the current APIs is that: most APIs are, at best, creating narrow windows into solid walls surrounding the silo-ed data islands. Even the most well-known and large APIs – such as those provided by Twitter, Facebook or Google, to a lesser extent, – only operate on the data that is within their own databases.</p>
<p>To take Twitter as the example: there is a lot that you can do with their public API; but in the end all of the created content always resides on Twitter’s servers. The same is true for Facebook, of course. Most Government APIs don’t even allow any “write” functionality and are strictly read-only.</p>
<p>In that sense, current APIs create isolated, guarded data islands in the universe of the web. Which is very “anti-web” — the web was created in the spirit of decentralized equal participation. On the web, everybody publishes everywhere, owns their data, and then we have ways to reach that data through hyperlinks, through Google search and other methods. APIs have not really reached that stage of maturity yet. APIs are highly centralized, in terms of data storage, and virtually none of them ever link to other APIs.</p>
<p>We need a new breed of APIs: <a href="http://linkedapis.org/">Linked APIs</a>, based on the same hypermedia design that we have in the rest of the world wide web. Such APIs will have the biggest impact for Open Data, because they’re all about linking and making connections across data-sets and across organizational boundaries. Linked APIs are also very scalable and best suited to meet the modern challenges of Big Data. After all, world wide web is the largest, most distributed network of information, mankind has ever created. We know the architecture of the web can scale and <a href="http://linkedapis.org/">Linked APIs</a> have the same exact architecture, with Hypermedia as the engine.</p>
<p>For the freedom of data, we really need more Linked APIs.</p>
<blockquote>
<p>We can only truly have open and free data, if we jail-brake the data out of the silos that data is stashed-away at, currently.</p>
</blockquote>
<p>Linked APIs provide us the keys to the data fortresses where large aggregators, currently hide data. Linked APIs ensure that our data isn’t stashed-away in some scary, centralized warehouses at the mercy of a handful of dominant players.</p>
<blockquote>
<p><a href="http://linkedapis.org/">Linked APIs</a> are the key to data freedom on the web. They are the engine of that freedom. Let’s get the engine cranking!</p>
</blockquote>
<p>Thank you!</p>
Setup Vagrant with VMWare and Ubuntu
2014-02-27T00:00:00-05:00
http://www.freshblurbs.com/blog/2014/02/27/vagrant-vmware-ubuntu.html
<p><a href="http://www.vagrantup.com/">Vagrant</a> is a very handy command-line tool for managing virtual machines (VMs) and orchestrating consistent developer environments across a team of developers.</p>
<p>By default, Vagrant uses <a href="https://www.virtualbox.org/">Virtualbox</a> VMs. However, it can integrate with other VM providers, as well.</p>
<p>I’ve been a huge fan of <a href="http://www.vmware.com/">VMWare</a> for more than a decade now. I really like it. It always felt cleaner and snappier than alternatives, to me. At least some industry analysis <a href="http://www.macworld.com/article/1164817/the_best_way_to_run_windows_on_your_mac.html">seem to agree</a> that it may be the fastest VM enclosure available.</p>
<p>Unfortunately, setting up Vagrant with VMWare isn’t very straight-forward. Information for various steps is scattered across multiple documentation pages. It took a while for me to piece everything together. In the hopes of saving that time for the next person, I decided to write this blog post.</p>
<h3 id="preparation">Preparation.</h3>
<p>To use Vagrant with VMWare, it’s not sufficient to have VMWare license (which you may already have). You need to also purchase a license for VMWare/Vagrant plugin. At the time of this writing, it <a href="http://www.vagrantup.com/vmware#buy-now">costs a hefty $79</a>. Once you purchase the license for the plugin, you get license.lic file. We will be using that file in our installation steps.</p>
<h3 id="installation">Installation</h3>
<p>Following is a log of installation steps. It should be pretty self-explanatory. We first</p>
<ol>
<li>Install vagrant-vmware-fusion plugin, then:</li>
<li>Install the license,</li>
<li>List plugins list to verify successful installation</li>
<li>Download Ubuntu12 vm box for VMware</li>
<li>Create an instance of Ubuntu12/VMware box, with “init”.</li>
<li>Launch the newly minted vagrant box with “up”.</li>
</ol>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">$</span><span class="w"> </span>vagrant plugin <span class="nb">install </span>vagrant-vmware-fusion
<span class="go">Installing the 'vagrant-vmware-fusion' plugin. This can take a few minutes...
Installed the plugin 'vagrant-vmware-fusion (2.3.2)'!
</span><span class="gp">$</span><span class="w"> </span>vagrant plugin license vagrant-vmware-fusion license.lic
<span class="go">Installing license for 'vagrant-vmware-fusion'...
The license for 'vagrant-vmware-fusion' was successfully installed!
</span><span class="gp">$</span><span class="w"> </span>vagrant plugin list
<span class="go">vagrant-vmware-fusion (2.3.2)
</span><span class="gp">$</span><span class="w"> </span>vagrant box add vmwareubuntu12 http://files.vagrantup.com/precise64_vmware.box
<span class="go">Downloading box from URL: http://files.vagrantup.com/precise64_vmware.box
Extracting box...te: 3485k/s, Estimated time remaining: 0:00:01)
Successfully added box 'vmwareubuntu12' with provider 'vmware_fusion'!
</span><span class="gp">$</span><span class="w"> </span>vagrant init vmwareubuntu12
<span class="go">A `Vagrantfile` has been placed in this directory. You are now
ready to `vagrant up` your first virtual environment! Please read
the comments in the Vagrantfile as well as documentation on
`vagrantup.com` for more information on using Vagrant.
</span><span class="gp">$</span><span class="w"> </span>vagrant up <span class="nt">--provider</span><span class="o">=</span>vmware_fusion
<span class="go">Bringing machine 'default' up with 'vmware_fusion' provider...
[default] VMware requires root privileges to make many of the changes
necessary for Vagrant to control it. In a moment, Vagrant will ask for
your administrator password in order to install a helper that will have
permissions to make these changes. Note that Vagrant itself continues
to run without administrative privileges.
Password:
[default] Cloning VMware VM: 'vmwareubuntu12'. This can take some time...
[default] Verifying vmnet devices are healthy...
[default] Preparing network adapters...
[default] Starting the VMware VM...
[default] Waiting for the VM to finish booting...
[default] The machine is booted and ready!
[default] Forwarding ports...
</span><span class="gp">[default] -- 22 =></span><span class="w"> </span>2222
<span class="go">[default] Configuring network adapters within the VM...
[default] Waiting for HGFS kernel module to load...
[default] Enabling and configuring shared folders...
[default] -- /Users/irakli/vagrants: /vagrant
</span></code></pre></div></div>
<p>Once the new Vagrant machine with Ubuntu is successfully up and running, you can ssh into it, by simply typing:</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">$</span><span class="w"> </span>vagrant ssh
<span class="go">Welcome to Ubuntu 12.04.1 LTS (GNU/Linux 3.2.0-29-virtual x86_64)
* Documentation: https://help.ubuntu.com/
Last login: Wed Feb 26 13:48:53 2014
</span><span class="gp">vagrant@precise64:~$</span><span class="w">
</span></code></pre></div></div>
Bitcoin Is Not Inherently Secure
2014-02-25T00:00:00-05:00
http://www.freshblurbs.com/blog/2014/02/25/bitcoin-troubles.html
<p>This comment was written in response to a <a href="http://avc.com/a_vc/2014/02/mt-gox.html">blog post</a> by <a href="https://twitter.com/fredwilson">Fred Wilson</a>.</p>
<hr />
<p>Specifically, I was reacting to the common “Bitcoin’s security is inherently inpenetrable” misconception, represented in the blog post as the following statement:</p>
<blockquote>
<p>“Bitcoin’s architecture is similar to the Internet’s architecture. There is no centralized control point. No single point of failure.”</p>
</blockquote>
<p>Welp, yes and no. Web’s architecture is amazing, and Bitcoin’s is pretty smart, too, but no technology system is ever absolutely secure. Simply because life doesn’t deal in absolutes. Ignoring the limits of security is one sure way to get compromised.</p>
<p>While Internet’s architecture is indeed exceptionally resilient, it is in no way bulletproof. By now we have amassed a lot of unfortunate examples of how it can be compromised. Internet can be controlled both locally (various country-level “walls” filtering access) as well as: globally (Net Neutrality issues, compromised security protocols, back-channel access into major systems).</p>
<p>To put it in the words of <a href="http://en.wikipedia.org/wiki/Bruce_Schneier">Bruce Schneier</a>:</p>
<blockquote>
<p>If you think technology can solve your security problems, then you don’t understand the problems and you don’t understand the technology.</p>
</blockquote>
<p>It’s one thing when compromised Internet means your Netflix video is slow and image quality is grained, it’s completely different when your money can get lost.</p>
<p>Not taking the risks that are present even in the most distributed architectures seriously is—irresponsible. There is no “purely technical” solution here. Bitcoin-like approach may be an improvement, and I am as excited about it as the next person, but I still want offline mechanisms to protect my money when all the tech fails. There is no purely technological solution for international monetary exchange. Outright ignoring all of the experience in the field, and being all radical about it is: well, somewhat childish, to be blunt about it.</p>
Why Have Open Data Initiatives Not Been More Successful?
2014-02-11T00:00:00-05:00
http://www.freshblurbs.com/blog/2014/02/11/why-open-data-fails-api-more-than-dataset-search.html
<p>It never fails to fascinate how differently do Open Data practitioners look at APIs, compared to applied API practitioners (i.e. people who build APIs for specific business needs).</p>
<p>Having spent years in the Open Data world, where I designed and built APIs for large data-publishers such as The World Bank, I sincerely appreciate the “liberate the data” mantra. Unfortunately, the data “liberation” alone often falls short of the intended goals.</p>
<!-- copy and paste this code wherever you'd like the gif to appear -->
<!-- it will automatically resize to fit its container -->
<div style="max-width: 500px;" id="_giphy_13ntwofffIcYq4"></div>
<script>var _giphy = _giphy || []; _giphy.push({id: '13ntwofffIcYq4',w: 320, h: 180});var g = document.createElement('script'); g.type = 'text/javascript'; g.async = true;g.src = ('https:' == document.location.protocol ? 'https://' : 'http://') + 'giphy.com/static/js/widgets/embed.js';var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(g, s);</script>
<p> </p>
<p>APIs shouldn’t be viewed as simply windows into data. Neither are APIs a slicing mechanism for data. I think both views greatly oversimplify matters. They diminish APIs to being a form of “typed, searchable CSVs on the Internet”. APIs can be, and should be, so much more!</p>
<blockquote>
<p>APIs are not merely windows into your datasets. Neither should they be glorified http searches against typed “CSVs”.</p>
</blockquote>
<p>Clayton Christensen (the author of the seminal <a href="http://www.amazon.com/The-Innovators-Dilemma-Revolutionary-Business/dp/0062060244">Innovator’s Dilemma</a> book) created a very interesting framework: <a href="http://www.christenseninstitute.org/key-concepts/jobs-to-be-done/">Jobs to Be Done</a>. The take-away of this framework, as it can be applied to Open Data, is that: people rarely need access to raw data per se. Data is just means to something else. People need certain jobs to be done. APIs that are windows to raw data do not directly get any jobs done.</p>
<p>Publishing massive amounts of government data is definitely a positive initiative. However, simply publishing raw data has not lead to the kind of innovation that people have hoped for. There has been some healthy debate regarding the cause of this shortcoming. My theory is that: just posting data online (even searchable), without tailoring it to any jobs to be done, is simply not very helpful. Not for the majority of consumers, at least.</p>
<p>I hope there will be more debate in this regard, in the future, and am eagerly looking forward to it.</p>
How Innovation Works
2014-02-09T00:00:00-05:00
http://www.freshblurbs.com/blog/2014/02/09/how-innovation-works.html
<p>A list of necessary, if not always sufficient, steps for inventing something new and valuable:</p>
<ol>
<li><strong>Obsess</strong>. <span style="color: gray">Get an obsession with an idea/vision to the extent that you are physically uncomfortable if you don’t work on it.</span></li>
<li><strong>Research</strong>. <span style="color: gray">Learn everything there is to learn about existing research/thinking related to the idea. In practice, this means learning as much as you can find and includes things that are even remotely related.</span></li>
<li><strong>Lose Sleep.</strong> <span style="color: gray">Now get obsessed to the extent that you randomly wake up at night and start working.</span></li>
<li><strong>Prototype.</strong> <span style="color: gray">Start creating prototypes. These could be anything from: mockups to designs to code.</span></li>
<li><strong>Seek feedback.</strong> <span style="color: gray">Discuss your ideas, prototypes and challenges with the smartest people you can find. If you’re already working with a team of smart people, talk to people outside your team and organization</span></li>
<li><strong>Adjust.</strong> <span style="color: gray">Be ready to be told you’re wrong. Listen to the arguments, adjust as necessary, but don’t abandon your idea.</span></li>
<li>
<p><strong>Ship it.</strong></p>
<p><!-- copy and paste this code wherever you'd like the gif to appear -->
<!-- it will automatically resize to fit its container --></p>
<div style="max-width: 500px;" id="_giphy_ta83CqOoRwfwQ"></div>
<script>var _giphy = _giphy || []; _giphy.push({id: 'ta83CqOoRwfwQ',w: 400, h: 306});var g = document.createElement('script'); g.type = 'text/javascript'; g.async = true;g.src = ('https:' == document.location.protocol ? 'https://' : 'http://') + 'giphy.com/static/js/widgets/embed.js';var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(g, s);</script>
</li>
</ol>
Asking the Right Questions — Lean Startup
2013-12-31T00:00:00-05:00
http://www.freshblurbs.com/blog/2013/12/31/asking-wrong-lean-questions.html
<p>Woke up this morning to this tweet from Hacker News:</p>
<blockquote class="twitter-tweet" lang="en"><p>Lessons learned from my failed startup after 2 years, 300 users and 0 revenue <a href="http://t.co/MowOCvwOjR">http://t.co/MowOCvwOjR</a></p>— news.yc Popular (@newsycombinator) <a href="https://twitter.com/newsycombinator/statuses/417990260153647104">December 31, 2013</a></blockquote>
<script async="" src="//platform.twitter.com/widgets.js" charset="utf-8"></script>
<p>Despite the somewhat cliché title, it ended-up being a very thoughtful, honest and interesting recap by <a href="https://twitter.com/sergiojota">@sergiojota</a></p>
<p>I think Sergio does a great job explaining many interesting pitfalls of running lean, but couple things caught my eye that I have seen as mistakes elsewhere and I wanted to chime-in about.</p>
<p>First-off:</p>
<blockquote>
<p>You have to ask the right questions.</p>
</blockquote>
<p>I agree with Sergio that one of his mistakes was: not asking the questions to his early adopters, but then he gives examples of what questions he’d ask:</p>
<ul>
<li>What were you looking for in Google when you found Teamometer? Why were you looking for it?</li>
<li>Why is it a problem for you/company?</li>
<li>How are you trying to solve this problem today?</li>
</ul>
<p>These are bad questions to ask!</p>
<p>They are way too open-ended and require a lot of time from somebody who casually stopped by your site from a Google ad. In addition to the time waste, you are asking questions that users most probably won’t even know the answers to. Just because they clicked on something that looked interesting, doesn’t mean they are experts on the subject. On the contrary: most people expect to learn something new from you.</p>
<p>To use a cliché analogy: imagine if Steve Jobs, while developing iPhone, asked future customers “what are you looking for”? Well, they weren’t looking for iPhone, that’s for sure.</p>
<p>When running lean, and developing a new product, you always, <strong>always</strong> have to observe behaviors rather than try “pick brains”. It’s the age-old adage that medical doctors have learned: you can’t trust what a patient tells you, but you can trust how they look, behave and what their vital signs are.</p>
<p>When conducting Lean learning you have to make it into an A/B exercise: observe the choices the users make (even if it is in answering a question) but never, NEVER ask open-ended questions, unless you are having a fireside chat with an expert. And even then take the answer with a grain of salt.</p>
<p>Next:</p>
<blockquote>
<p>Lean ≠ MVP!</p>
</blockquote>
<p>I see too many people, having just read <a href="http://theleanstartup.com/">Lean Startup</a>, equating Lean with building an MVP. It is dead wrong. MVP is just one of the tools of Lean, it is by no means the essense of Lean. Lean Startup is an adaptation of <a href="http://en.wikipedia.org/wiki/Lean_manufacturing">Lean Manufacturing</a> to the software realm. The two essential principles of Lean (manufacturing or otherwise) are:</p>
<ul>
<li>Continuous improvement (learning)</li>
<li>Minimization of batch size (elimination of waste).</li>
</ul>
<p>In that regard the point of MVP isn’t to build “minimal” version of your product, the point is to in each iteration build enough to learn more and then iterate again, again and again until you get to the PERFECT product, as soon as possible. If your “MVP approach” is making you get to the perfect product slower, you are doing it wrong.</p>
<p>Happy new year!</p>
Web Typography Quick Wins: Let Your Body Text Breathe
2013-12-25T00:00:00-05:00
http://www.freshblurbs.com/blog/2013/12/25/typography-legible-body-text.html
<p>The appearence of a text can have significant impact on our ability to: comprehend, enjoy or even be willing to finish reading the text. Unfortunately, default browser font styles still reflect the needs of devices from a different century, and as such are too dense and small, if we are honest about it.</p>
<p>While web typography is a very large subject, way beyond what can be covered in a short Christmas blog post, there are some quick style tweeks that can bring big wins. The tweaks are CSS rules/values commonly used by web typography enthusiasts that, I believe, greatly improve the reading pleasure when applied to body text.</p>
<p>Following are some sure-fire improvements for body text styling, per yours truly:</p>
<ul>
<li>Depending on a font and the UI, use font sizes 16px–22px for body text.</li>
<li>Make line height at least 1.3334, at most 1.6667 the size of the font.</li>
<li>Most fonts look better with font-weight: 300 or 200. Those values are slightly less than the default value corresponding to “normal”: 400. The slight reduction can, however, make body text look significantly more airy and pleasant on eyes.</li>
<li>Some fonts could use slightly increased letter-spacing when used on the web.</li>
<li>The “straight black” (#000000) is rarely a good font color choice (@see: <a href="http://ianstormtaylor.com/design-tip-never-use-black/">Ian Storm Taylor’s take</a> on why). A pleasant shade of gray is usually more suitable. Popular, easy-to-remember choices include: #333333 and #555555.</li>
</ul>
<p>Putting it all together:</p>
<div class="language-css highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">body</span> <span class="p">{</span>
<span class="nl">font-size</span><span class="p">:</span> <span class="m">16px</span><span class="p">;</span>
<span class="nl">font-weight</span><span class="p">:</span> <span class="m">300</span><span class="p">;</span>
<span class="nl">line-height</span><span class="p">:</span> <span class="m">1.5</span><span class="p">;</span>
<span class="nl">letter-spacing</span><span class="p">:</span> <span class="m">.04em</span><span class="p">;</span>
<span class="nl">color</span><span class="p">:</span> <span class="m">#555555</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Merry Christmas and Happy Holidays!</p>
Code-On-Demand in REST APIs: Scriptable Clients
2013-12-12T00:00:00-05:00
http://www.freshblurbs.com/blog/2013/12/12/rest-apis-client-side-scripting.html
<p>The relationship of the web APIs and the World Wide Web (the medium) has been complicated, to say the least. It feels like APIs constantly try to defy how web is supposed to work. Every time APIs do it, however <a href="http://en.wikipedia.org/wiki/Fallacies_of_Distributed_Computing">fundamental laws of distributed computing</a> inavitably punish the rebelious APIs and put them into the proverbial corner, forcing to “apologize” and retract.</p>
<style>
.item_content img {
width: 100%;
}
</style>
<p><img src="http://f.cl.ly/items/0y430g0J1P1O1L1F1v1D/screaming-kid.jpg" alt="Screming emotion - photo" /></p>
<p>We have heard the story… (If you don’t care to remember it, feel free to jump to <a href="#tldr">TL;DR Punchline</a>)</p>
<p>First came the attempts to implement RPC over HTTP (SOAP, XML-RPC…). Eventually we discovered the limitations of tight-coupling clients to proprietary procedure semantics and decided that we’d rather build resource-oriented APIs with actions limited to core HTTP verbs. What most people call “RESTful APIs” were born.</p>
<p>“RESTful APIs” in many cases worked better, simpler than RPC alternatives. For a while that made us happy. Then people who actually read <a href="http://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm">Chapter 5 of Roy’s dissertation</a> showed up and vocally pointed out that the “common REST” wasn’t actually very RESTful at all, since some of the most prominent “RESTful” APIs completely ignored such fundamental principles as, say: <a href="http://en.wikipedia.org/wiki/HATEOAS">Hypermedia As The Engine Of Application State (HATEOAS)</a>. We were set on the course of correcting our erroneous ways and the <a href="http://shop.oreilly.com/product/0636920028468.do">Hypermedia APIs</a> movement was born…</p>
<p>Hypermedia APIs <a href="http://www.freshblurbs.com/blog/2013/12/03/web-hypermedia-apis-node.html">can be very powerful</a>. Their current definition, however, is just a step in our continous journey of building better web APIs. It is not the end of the journey itself.</p>
<h2 id="tight-coupling-is-evil">Tight Coupling Is Evil</h2>
<p>On the journey of getting to an ideal API architecture, we are basically trying to scale all aspects of API infrastrucutre: make APIs capable of taking more load, ensuring <a href="http://www.freshblurbs.com/blog/2013/12/05/next-wave-big-data-hypermedia.html">they are not siloed</a> and that they do not lead to a <a href="http://localhost:4000/blog/2013/09/13/hypermedia-apis-api-governence.html">management nightmare</a></p>
<p>The number one enemy of any scalability effort is tight coupling. By de-coupling various aspects of the client-server interaction, we are getting to an increasingly more scalable API design. There <em>are</em> multiple facets to the de-coupling effort, however, and we haven’t figured all of them out, yet. <a name="tldr"> </a></p>
<h2 id="tldr-punchline-javascript-of-apis">TL;DR Punchline: “Javascript” of APIs</h2>
<p>Web APIs targeted at machines are behind the human-centric web in their maturity. By “Human-Centric Web” I mean the part of the web using standardized browers and the ability of human brains to process HTML-rendered content.</p>
<p>Comparing the progression of the “web of machines” (APIs) to that of “Human-Centric Web” (websites) we can map the milestone events of the two:</p>
<ul>
<li>APIs before “common REST” were like the age of <a href="http://en.wikipedia.org/wiki/Gopher_%28protocol%29">Gopher</a>, in Human-Centric Web terms: the messy era before the ubiquitousness of HTTP.</li>
<li>The advancement of Hypermedia APIs establishes standard media types and is equivalent to the establishment of HTML as the <em>lingua franca</em> for the Human-Centric Web.</li>
</ul>
<p>We however still do not have a “Javascript” of APIs. APIs still haven’t reached that milestone moment in the history of Human-Centric Web when Netscape launched the first Javascript implementation and forever changed how we use the world wide web.</p>
<p>Even the most by-the-book Hypermedia APIs currently send completely static content to the client. They do achieve one level of de-coupling by communicating controls in the response message, through link relations, but the communication is still limited to the semantics of the media type that the client knows beforehand and which would have to had been hard-coded in its implementation.</p>
<p>Case in point: media types can be extended with custom <a href="http://www.ietf.org/rfc/rfc6906.txt">profiles</a> but clients have little ability to do much interesting with the extended semantics unless they understand it beforehand. Servers are currently unable to send code leveraging the additional semantics, in the response message. This limitation obviously leads to some level of tight-coupling of server logic with client code that may be critical in certain scenarios.</p>
<h2 id="proper-hypermedia-clients-should-be-scriptable">Proper Hypermedia Clients Should Be Scriptable.</h2>
<p>To achieve the next level of de-coupling, servers can leverage the ability of sending API clients executable code as part of a response message. We need a “Javascript” for APIs much like we needed one for browsers back in the day.</p>
<p>What would anybody use scripting on the client-side in APIs for? Well, at the least, we’d use it for all the same use-cases which we use Javascript in browsers for:</p>
<ul>
<li>Client-side validation</li>
<li>Asynchronous, lightweight sub-requests (à la “AJAX”)</li>
<li>Dynamic processing of additional message semantics on top of the semantics contained in a core media type definition.</li>
</ul>
<p>Given how non-existent such capabilities are in current APIs, the idea may sound crazy, but Roy actually had “Code-On-Demand” as one of the core constraints that compose the REST style. It’s discussed in <a href="http://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm#sec_5_1_7">section 5.1.7</a> of the original dissertation. The idea is not really THAT crazy. Better yet, with the abundance of solutions for high-quality, embeddable scripting solutions and the wealth of experience securely sandboxing scripting in web browsers, it’s totally doable!</p>
“Hello Web” API In Go Programming Language
2013-12-07T00:00:00-05:00
http://www.freshblurbs.com/blog/2013/12/07/hello-web-golang.html
<p>Programming language <a href="http://golang.org/">Go</a> is one of a handful of popular, new ones aimed at modernizing conventional programming style established by C++ and Java. Go was originally designed at Google in 2007 by Robert Griesemer, Rob Pike, and Ken Thompson.</p>
<p>There’re many things that make Go a very interesting language. Some of them that I personally appreciate include:</p>
<ul>
<li>Compilation to optimized, statically linked native binaries without external dependencies.</li>
<li>Automatic memory management</li>
<li>Goroutines-based concurrency.</li>
<li>Native support for HTTP.</li>
<li>Built-in package manager: <a href="http://godoc.org/">http://godoc.org/</a></li>
</ul>
<p>As an introduction to Go language (or: “Golang”), let’s see an example of a very simple web API outputting: “Hello Web” JSON message.</p>
<h2 id="code">Code</h2>
<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="n">main</span>
<span class="k">import</span> <span class="p">(</span>
<span class="s">"fmt"</span>
<span class="s">"net/http"</span>
<span class="p">)</span>
<span class="k">func</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
<span class="n">http</span><span class="o">.</span><span class="n">HandleFunc</span><span class="p">(</span><span class="s">"/hello"</span><span class="p">,</span> <span class="n">viewHandler</span><span class="p">)</span>
<span class="n">http</span><span class="o">.</span><span class="n">ListenAndServe</span><span class="p">(</span><span class="s">":8080"</span><span class="p">,</span> <span class="no">nil</span><span class="p">)</span>
<span class="p">}</span>
<span class="k">func</span> <span class="n">viewHandler</span><span class="p">(</span><span class="n">w</span> <span class="n">http</span><span class="o">.</span><span class="n">ResponseWriter</span><span class="p">,</span> <span class="n">r</span> <span class="o">*</span><span class="n">http</span><span class="o">.</span><span class="n">Request</span><span class="p">)</span> <span class="p">{</span>
<span class="n">w</span><span class="o">.</span><span class="n">Header</span><span class="p">()</span><span class="o">.</span><span class="n">Set</span><span class="p">(</span><span class="s">"Content-type"</span><span class="p">,</span> <span class="s">"text/plain"</span><span class="p">)</span>
<span class="n">fmt</span><span class="o">.</span><span class="n">Fprintf</span><span class="p">(</span><span class="n">w</span><span class="p">,</span> <span class="n">jsonMsg</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Creating a more common JSON output takes a little more code:</p>
<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="n">main</span>
<span class="k">import</span> <span class="p">(</span>
<span class="s">"fmt"</span>
<span class="s">"net/http"</span>
<span class="s">"time"</span>
<span class="s">"encoding/json"</span>
<span class="p">)</span>
<span class="k">func</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
<span class="n">http</span><span class="o">.</span><span class="n">HandleFunc</span><span class="p">(</span><span class="s">"/hello"</span><span class="p">,</span> <span class="n">viewHandler</span><span class="p">)</span>
<span class="n">http</span><span class="o">.</span><span class="n">ListenAndServe</span><span class="p">(</span><span class="s">":8080"</span><span class="p">,</span> <span class="no">nil</span><span class="p">)</span>
<span class="p">}</span>
<span class="k">func</span> <span class="n">viewHandler</span><span class="p">(</span><span class="n">w</span> <span class="n">http</span><span class="o">.</span><span class="n">ResponseWriter</span><span class="p">,</span> <span class="n">r</span> <span class="o">*</span><span class="n">http</span><span class="o">.</span><span class="n">Request</span><span class="p">)</span> <span class="p">{</span>
<span class="n">w</span><span class="o">.</span><span class="n">Header</span><span class="p">()</span><span class="o">.</span><span class="n">Set</span><span class="p">(</span><span class="s">"Access-Control-Allow-Origin"</span><span class="p">,</span> <span class="s">"*"</span><span class="p">)</span>
<span class="n">w</span><span class="o">.</span><span class="n">Header</span><span class="p">()</span><span class="o">.</span><span class="n">Set</span><span class="p">(</span><span class="s">"Content-type"</span><span class="p">,</span> <span class="s">"application/json"</span><span class="p">)</span>
<span class="n">jsonMsg</span><span class="p">,</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">getResponse</span><span class="p">()</span>
<span class="k">if</span> <span class="n">err</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>
<span class="n">http</span><span class="o">.</span><span class="n">Error</span><span class="p">(</span><span class="n">w</span><span class="p">,</span> <span class="s">"Oops"</span><span class="p">,</span> <span class="n">http</span><span class="o">.</span><span class="n">StatusInternalServerError</span><span class="p">)</span>
<span class="p">}</span>
<span class="n">fmt</span><span class="o">.</span><span class="n">Fprintf</span><span class="p">(</span><span class="n">w</span><span class="p">,</span> <span class="n">jsonMsg</span><span class="p">)</span>
<span class="p">}</span>
<span class="k">func</span> <span class="n">getResponse</span><span class="p">()</span> <span class="p">(</span><span class="kt">string</span><span class="p">,</span> <span class="kt">error</span><span class="p">){</span>
<span class="n">unixtime</span> <span class="o">:=</span> <span class="kt">int32</span><span class="p">(</span><span class="n">time</span><span class="o">.</span><span class="n">Now</span><span class="p">()</span><span class="o">.</span><span class="n">Unix</span><span class="p">())</span>
<span class="n">msg</span> <span class="o">:=</span> <span class="n">Message</span><span class="p">{</span><span class="s">"Hi"</span><span class="p">,</span> <span class="s">"Hello Web!"</span><span class="p">,</span> <span class="n">unixtime</span><span class="p">}</span>
<span class="n">jbMsg</span><span class="p">,</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">json</span><span class="o">.</span><span class="n">Marshal</span><span class="p">(</span><span class="n">msg</span><span class="p">)</span>
<span class="k">if</span> <span class="n">err</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>
<span class="k">return</span> <span class="s">""</span><span class="p">,</span> <span class="n">err</span>
<span class="p">}</span>
<span class="n">jsonMsg</span> <span class="o">:=</span> <span class="kt">string</span><span class="p">(</span><span class="n">jbMsg</span><span class="p">[</span><span class="o">:</span><span class="p">])</span> <span class="c">// converting byte array to string</span>
<span class="k">return</span> <span class="n">jsonMsg</span><span class="p">,</span> <span class="no">nil</span>
<span class="p">}</span>
<span class="k">type</span> <span class="n">Message</span> <span class="k">struct</span> <span class="p">{</span>
<span class="n">Title</span> <span class="kt">string</span>
<span class="n">Body</span> <span class="kt">string</span>
<span class="n">Time</span> <span class="kt">int32</span>
<span class="p">}</span>
</code></pre></div></div>
<h2 id="how-to-execute">How to Execute</h2>
<p>Installing Go is easy on Mac. If you are using the <a href="http://brew.sh/">Homebrew</a> package manager, you can install Go by simply running:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>brew install go
</code></pre></div></div>
<p>If you save the source of the web API code above in a file called <code class="language-plaintext highlighter-rouge">server.go</code> you can directly run it with:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>go run server.go
</code></pre></div></div>
<p>or, you can first build the source to a binary executible with:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>go build server.go
</code></pre></div></div>
<p>and then run with:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>./server
</code></pre></div></div>
<p>You will be able to see the result in action, by pointing a browser to: <code class="language-plaintext highlighter-rouge">http://0.0.0.0:8080/hello</code></p>
<h2 id="further-reading">Further Reading</h2>
<ul>
<li><a href="http://golang.org/doc/effective_go.html#functions">Go Functions</a></li>
<li><a href="http://blog.golang.org/error-handling-and-go">Error Handling and Go</a></li>
<li><a href="http://golang.org/doc/effective_go.html#blank">The Blank Identifier</a></li>
<li><a href="http://golang.org/doc/articles/wiki/#tmp_9">Writing Web Applications in Go</a></li>
<li><a href="http://golang.org/doc/effective_go.html#concurrency">Go Concurrency</a></li>
<li><a href="http://matt.aimonetti.net/posts/2012/11/27/real-life-concurrency-in-go/">Concurrent HTTP Requests in GO</a></li>
<li><a href="http://justinas.org/writing-http-middleware-in-go/">Writing HTTP Middleware in Go</a></li>
<li><a href="https://gist.github.com/hgfischer/7965620">Benchmarking Nginx with Go</a></li>
</ul>
Next Wave of Big Data Will Be Hypermedia
2013-12-05T00:00:00-05:00
http://www.freshblurbs.com/blog/2013/12/05/next-wave-big-data-hypermedia.html
<p>Due to the explosive growth of the volume of the data we operate on, <a href="http://en.wikipedia.org/wiki/Big_data">Big Data</a> has been an increasingly hot topic for the past several years. However, on the journey of tackling the Big Data problem, we are still only seeing the tip of an iceberg.</p>
<p>Currently, Big Data is commonly defined as a data-set so large and complex that it becomes impossible to store and process it using traditional, vertically-scalable data management systems. To overcome this complexity, newer systems use horizontal partitioning and parallel processing of data-sets. But the data is still contained and processed in the isolation of a single organization, albeit using new kind of database systems. This will soon change—the end of the siloed Big Data is coming.</p>
<p>The future when Big Data will be more than merely a large and complex data-set is almost here.</p>
<blockquote>
<p>Next stage of Big Data is a data-set that crosses the organizational boundaries of a single entity.</p>
</blockquote>
<p>We are rapidly approaching the future where the various pieces of a data-set, we need to operate on, are contained in the systems of and owned by different organizations. These pieces will have to be connected over a network.</p>
<p><a href="http://healthcare.gov">healthcare.gov</a> is a good example of such distributed system. The main technical challenge of implementing healthcare.gov’s backend was that it had to integrate with many existing systems and those systems weren’t necessarily ready for such integration.</p>
<p>The <a href="http://www.washingtonpost.com/blogs/fact-checker/wp/2013/10/24/how-much-did-healthcare-gov-cost/">$500 million dollar</a>, public fiasco of <a href="http://healthcare.gov">healthcare.gov</a> is also a vivid indication of just how complex it is to build such systems. Almost the only successful implementation of such large, distributed system is World Wide Web. There’s a lot we can learn from the architecture of the web for how to build distributed systems at scale.</p>
<p>Luckily, a lot of effort has already been put in analyzing what in the web’s architecture makes it scale. It is: Hypermedia. Therefore it is very sensible to predict that the Big Data systems of the future will be Hypermedia-enabled systems.</p>
<p>I discussed how such hypermedia-enabled Big Data systems may be built in the future in my recent blog post: <a href="http://www.freshblurbs.com/blog/2013/12/03/web-hypermedia-apis-node.html">Web of APIs with Hypermedia and Node.js</a></p>
Web of APIs with Hypermedia and Node.js
2013-12-03T00:00:00-05:00
http://www.freshblurbs.com/blog/2013/12/03/web-hypermedia-apis-node.html
<p>Following is a transcript of a talk that was given at <a href="http://nodesummit.com/">NodeSummit</a> conference in San Francisco, in December 2013.</p>
<p><img src="http://f.cl.ly/items/1Y3f0N0L3Z003W1U431O/01-npr.png" alt="Title Slide - NPR HQ" /></p>
<h2 id="part-one-fragmented-world">Part One: Fragmented World.</h2>
<p>Good morning. Thank you for coming to such early talk.</p>
<p>I want to share a story with you—a story of how we built an infinitely scalable web API with Node.js. This API allows media organizations to publish and exchange massive amounts of digital content.</p>
<p>When architecting the system, the biggest challenge we faced was that:</p>
<blockquote>
<p>We live in an incredibly fragmented world.</p>
</blockquote>
<p>When you enjoy your New York Times article online or listen to NPR’s Morning Edition, various pieces of that content come from many different sources. Wire feeds such as Reuters and Associated Press, various social media outlets, partner news organizations–all contribute to the input.</p>
<p>The output is equally fragmented. Once a team of journalists produces the final content, it is pushed to many publishing channels: website, iOS and Android apps, sattelite distribution, as well as: back to the partner organizations and news networks.</p>
<p>Despite the apparent complexity of the process, it has to all work seamlessly. During breaking news or major events coverage, the allowed margin of error is pretty much: zero.</p>
<p>So imagine our excitement when we were asked to build a system that could scale such fully distributed operations for all of public media. The thought of: “Shit, we’re screwed” definitely crossed our minds more than once.</p>
<p>Building a fully distributed system at scale is hard and very risky. We immediately started looking for a success story of something similar. The answer was right in front of us: it’s called the World Wide Web, it’s the most distributed system in the world and we <em>know</em> it works.</p>
<p>Better yet, there’s a lot of research available that explains what makes web architecture scale; including <a href="http://en.wikipedia.org/wiki/Roy_Fielding">Roy Fielding</a>’s seminal dissertation abour REST architectural style, of course.</p>
<h2 id="part-two-hypermedia">Part Two: Hypermedia.</h2>
<p>The key to the scalability of web’s architecture is: Hypermedia.</p>
<p>Hypermedia is the matter of which the World Wide Web is made. Much like physical world is built of interacting elementary particles (Bosons and Fermions), the web is essentially the universe of myriad of interacting hypermedia documents.</p>
<p><img src="http://f.cl.ly/items/1Q3l2L1q1g1q1C2Q413y/02-webuniverse.png" alt="Web is the universe of hypermedia documents" /></p>
<p>Despite Hypermedia coming into the spotlight relatively recently, it is no baby. Hypermedia is more or less 23 years old. And much like we ourselves were at that age: it’s largely misunderstood, very rebellious, but also full of potential.</p>
<p>Most of Hypermedia’s potential comes from three core traits:</p>
<ul>
<li>the robustness of the HTTP protocol,</li>
<li>universal use of URLs</li>
<li>and the extremely versatile media types it uses: HTML and CSS.</li>
</ul>
<p>Now HTML is really special. It’s just a handful of tags, but the wealth of creative user-interfaces and user experiences that people are able to build with those tags is truly astounding. You have maybe a couple dozen simple rules and you get enormous creativity. With how in the news industry everybody is trying to be original, we knew we needed a media type as versatile as HTML.</p>
<p>Except HTML is mostly optimized for rendering content, and we needed a media type that is instead optimized for describing and publishing of structured content.</p>
<p>The media type we ended up designing is called: <a href="http://cdoc.io">Collection Document</a>. Its full specification is documented at the URL: <a href="http://cdoc.io">http://cdoc.io</a>. It is based on existing specifications by Hypermedia experts like Mike Amundsen and Mark Nottingham, among others.</p>
<p><img src="http://f.cl.ly/items/2H220Z3Y3a1u2C1F0K0a/cdoc-2.png" alt="Collection.Document media type diagram" /></p>
<p><a href="http://cdoc.io">Collection Document</a> is a recursive media type that is a document and a collection at the same time. As a document it can describe things. As a collection it contains other documents that can contain other documents etc. This recursion allows us to describe very complex domains.</p>
<p>But it’s also a very simple media type: it has only three top-level elements: attributes, links and errors. Links are basically URLs that describe relationships of various documents as well as: what you can do with the documents: the behaviours.</p>
<p>URLs are absolutely key to Collection Document. The primary key of any document is a URL. The way we describe collections of documents is also through URLs. Permissions, extensibility of semantic meanings of attributes, everything is expressed using URLs. This unified URL-oriented approach allows for some amazing things that I will tell you about a little bit later, but first let me say couple words about how we actually built the a scalable API using this media type and Node.js.</p>
<h3 id="part-three-the-implementation">Part Three: The Implementation</h3>
<p><img src="http://f.cl.ly/items/1d0h3W3e3F1X3O443Q3w/architecture.png" alt="Node Hypermedia API Architecture Diagram" /></p>
<p>NPR is somewhat famous as a champion in the API space. We have long history of building large web APIs. Building APIs, we learned long time ago that for APIs speed is a core feature. If you want people to really use your APIs you need to make them super fast.</p>
<p>This “fast” thing, however, can mean many things depending on a context. In case of a hypermedia API, code spends the majority of its time completing tasks that are I/O bound: most of the time we are storing data into and/or querying it from various services, waiting on input/output over HTTP or various TCP/IP protocols. Node.js was architected to be extremely efficient for such tasks, being non-blocking on I/O. Node was a great fit in that regard.</p>
<p>Node, however is not the only non-I/O-blocking programming environment. But compared to alternatives we really appreciated the community behind Node. Node has a very friendly, strong and healthy community that has produced a wealth of modules. Thanks to these modules, the Node Package Manager (npm) and Node Version Manager (nvm), Node is a very efficient environment for quick development.</p>
<p>There’s also a pragmatic reason for choosing Node. It’s much easier to hire Javascirpt developers or train existing ones on Node than to build a team of, say, Scala experts.</p>
<p>On top of Node.js, we are using Express.js. On top ot Express.js we use Node Bootstrap. Node Bootstrap is this MIT-licensed, open-source project we maintain at <a href="http://nodebootstrap.org">http://nodebootstrap.org</a>. It’s not a framework, but rather it’s a skeleton application that captures a lot of best practices of how to organize your project, do clustering and error handling properly, as well as write pluggable modules.</p>
<p>The concept of modules as plugins was essential for us. Operating in a startup-like mode, it was critical for us to be able to prototype quickly. So we designed every aspect of our code to be pluggable: search, storage, queuing system are all swappable.</p>
<p>For instance, search plays a huge role in our implementation. Since we are deployed on Amazon Cloud, we initially used Amazon’s CloudSearch service for search, just because it was readily available. Once we grew out of capabilities of CloudSearch we moved to a very powerful open-source search system: Elastic Search. We had to build our own ElasticSearch cluster at that point, but we didn’t have to rewrite too much of our code, because search implementation was largely pluggable in our system.</p>
<p>This approach of starting small and only hardening swappable components when you have to was monumental for us in being able to run the project in a Lean Startup way.</p>
<p>We ended up open-sourcing a bunch of components from the project at: <a href="http://oss.pmp.io">http://oss.pmp.io</a>. Specifically we were really missing some of the more advanced logging capabilities we were used to in other environments so we open-sourced a framework called metalogger. We also open-sources message-queue based task scheduling framework.</p>
<h3 id="one-more-thing-web-of-apis">“One More Thing”: Web of APIs</h3>
<p>Ok, so this is what we did. We designed some media type, built a Node.js API that we claim is very scalable and open-sourced some projects. What’s the big deal?</p>
<p>Well, it turns out by using Hypermedia architecture, designing the media type with URLs at the center and implementing it all with asynchronous Node.js, we did manage a little more than just ordinary. We ended up with an API that breaks through probably the most significant constraint of modern APIs.</p>
<p><img src="http://f.cl.ly/items/2z232H1r2U453d1I0g3L/irakli-nodesummit.pptx-2.png" alt="Web of API = No More Silos" /></p>
<p>One of the most limiting constraints of the modern APIs is that they are completely silo-ed.</p>
<p>Let’s take one of the most successful APIs we’re all familiar with: Twitter. It’s a landmark one, but it’s also isolated. You can only use the API against the content that is in Twitter’s database. It’s not like you can run a query against a “tweet” that is originated in another system, can you?</p>
<p>But if we think about it—that’s totally anti-web! Elsewhere on the web, you don’t save your page directly into Google’s database to make it searchable! And you don’t have to publish your webpage into somebody else’s database to link to it. You kindof had to do such silly things for the APIs, however.</p>
<p>Well, you don’t have to jail your APIs, anymore. You can set them free. With the API we built you can have core data elements of the API live anywhere on the web, as far as you can reference it! When you use Hypermedia properly and specifically if you use Collection Document media type, you end up with a true web of APIs—A properly interconnected network of APIs the way that web APIs were meant to be!</p>
<p>And u know what? That’s quite amazing. When u can do those kind if things—<em>anything</em> becomes possible!</p>
Mac OS-X Key Combinations for Some Common Characters
2013-11-30T00:00:00-05:00
http://www.freshblurbs.com/blog/2013/11/30/mac-keys-frequent-characters.html
<p><strong>Credit:</strong> this blog post was inspired by and CSS styles for it were shamelessly ripped off of: <a href="http://smartquotesforsmartpeople.com/">Smart Quotes for Smart People</a> website by <a href="https://twitter.com/jasonsantamaria">Jason Santa-Maria</a>.</p>
<p>Following is a list of key combinations for OS-X Latin standard keyboard that allow easy typing of some frequently-needed characters</p>
<style type="text/css">
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video, kbd {
margin: 0;
padding: 0;
border: 0;
font: inherit;
font-size: 100%;
vertical-align: baseline; }
* {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box; }
html { line-height: 1; }
table, tr, td {
font-family: Times;
}
table {
border-collapse: collapse;
border-spacing: 0; }
caption, th, td {
text-align: left;
font-weight: normal;
vertical-align: middle; }
.bigpunc {
display: block;
font-size: 2.0em;
text-align: left;
overflow: hidden;
line-height: 0.8em;
height: 60px !important; }
.bigpuncdef {
display: block;
font-size: 0.9em;
color: #888; }
table {
max-width: 100%;
background-color: transparent; }
th { text-align: left; }
th, td { width: 25%; }
.table {
width: 100%;
margin-bottom: 20px; }
.table thead > tr > th,
.table tbody > tr > th,
.table tfoot > tr > th,
.table thead > tr > td,
.table tbody > tr > td,
.table tfoot > tr > td {
padding: 14px;
line-height: 1.428571429;
vertical-align: middle;
border-top: 1px solid #dddddd; }
.table thead > tr > th {
vertical-align: top;
font-size: 1.75em;
border-bottom: 2px solid #dddddd; }
.table thead > tr > th span {
display: block;
font-weight: normal;
font-size: 0.5em;
color: #888; }
.table thead:first-child tr:first-child th,
.table thead:first-child tr:first-child td {
border-top: 0; }
.table tbody + tbody { border-top: 2px solid #dddddd; }
.nobr { white-space:nowrap; line-height: 1.2em; }
kbd {
background-color: #F9F9F9;
background-image: -webkit-linear-gradient(top, #EEE, #F9F9F9, #EEE);
box-shadow: 1px 2px 2px #DDD;
border: 1px solid #AAA;
border-radius: 2px;
padding: 2px 4px;
color: #333; }
</style>
<table class="table">
<thead><tr>
<th>Character</th>
<th>Name</th>
<th>Key Combo</th>
</tr></thead>
<tbody>
<tr>
<td><span class="bigpunc">©</span></td>
<td><span class="bigpuncdef">Copyright Sign.</span></td>
<td class="nobr"><kbd>Option</kbd> + <kbd>g</kbd></td>
</tr>
<tr>
<td><span class="bigpunc">™</span></td>
<td><span class="bigpuncdef">Trade Mark Sign.</span></td>
<td class="nobr"><kbd>Option</kbd> + <kbd>2 (@)</kbd></td>
</tr>
<tr>
<td><span class="bigpunc">®</span></td>
<td><span class="bigpuncdef">Registered Sign.</span></td>
<td class="nobr"><kbd>Option</kbd> + <kbd>r</kbd></td>
</tr>
<tr>
<td><span class="bigpunc">º</span></td>
<td><span class="bigpuncdef">Degree.</span></td>
<td class="nobr"><kbd>Option</kbd> + <kbd>0</kbd></td>
</tr>
<tr>
<td><span class="bigpunc">…</span></td>
<td><span class="bigpuncdef">Horizontal Ellipses.</span></td>
<td class="nobr"><kbd>Option</kbd> + <kbd>;</kbd></td>
</tr>
<tr>
<td><span class="bigpunc">∞</span></td>
<td><span class="bigpuncdef">Infinity.</span></td>
<td class="nobr"><kbd>Option</kbd> + <kbd>5 (%)</kbd></td>
</tr>
<tr>
<td><span class="bigpunc">≠</span></td>
<td><span class="bigpuncdef">Not Equals.</span></td>
<td class="nobr"><kbd>Option</kbd> + <kbd>=</kbd></td>
</tr>
<tr>
<td><span class="bigpunc">≈</span></td>
<td><span class="bigpuncdef">Almost equal to.</span></td>
<td class="nobr"><kbd>Option</kbd> + <kbd>x</kbd></td>
</tr>
<tr>
<td><span class="bigpunc">≤</span></td>
<td><span class="bigpuncdef">Less-than or equals to.</span></td>
<td class="nobr"><kbd>Option</kbd> + <kbd><</kbd></td>
</tr>
<tr>
<td><span class="bigpunc">≥</span></td>
<td><span class="bigpuncdef">More-than or equals to.</span></td>
<td class="nobr"><kbd>Option</kbd> + <kbd>></kbd></td>
</tr>
<tr>
<td><span class="bigpunc">ƒ</span></td>
<td><span class="bigpuncdef">Math: “function of” (Caution: it's a “Find” cmd key combo in many editors).</span></td>
<td class="nobr"><kbd>Option</kbd> + <kbd>f</kbd></td>
</tr>
<tr>
<td><span class="bigpunc">∑</span></td>
<td><span class="bigpuncdef">Math: “sum of”.</span></td>
<td class="nobr"><kbd>Option</kbd> + <kbd>w</kbd></td>
</tr>
<tr>
<td><span class="bigpunc">–</span></td>
<td><span class="bigpuncdef">En-dash.</span></td>
<td class="nobr"><kbd>Option</kbd> + <kbd>-</kbd></td>
</tr>
<tr>
<td><span class="bigpunc">—</span></td>
<td><span class="bigpuncdef">Em-dash.</span></td>
<td class="nobr"><kbd>Option</kbd> + <kbd>Shift</kbd> + <kbd>-</kbd></td>
</tr>
<tr>
<td><span class="bigpunc">“</span></td>
<td><span class="bigpuncdef">Left double quotation mark.</span></td>
<td class="nobr"><kbd>Option</kbd> + <kbd>[</kbd></td>
</tr>
<tr>
<td><span class="bigpunc">”</span></td>
<td><span class="bigpuncdef">Right double quotation mark.</span></td>
<td><kbd>Option</kbd> + <kbd>Shift</kbd> + <kbd>[</kbd></td>
</tr>
<tr>
<td><span class="bigpunc">‘</span></td>
<td><span class="bigpuncdef">Left single quotation mark.</span></td>
<td class="nobr"><kbd>Option</kbd> + <kbd>]</kbd></td>
</tr>
<tr>
<td><span class="bigpunc">’</span></td>
<td><span class="bigpuncdef">Right single quotation mark / apostrophe.</span></td>
<td><kbd>Option</kbd> + <kbd>Shift</kbd> + <kbd>]</kbd></td>
</tr>
<tr>
<td><span class="bigpunc"></span></td>
<td><span class="bigpuncdef">Apple!</span></td>
<td class="nobr"><kbd>Option</kbd> + <kbd>Shift</kbd> + <kbd>k</kbd></td>
</tr>
</tbody>
</table>
All Content Management Systems (CMS) Are Broken In a Bad Way.
2013-10-22T00:00:00-04:00
http://www.freshblurbs.com/blog/2013/10/22/web-of-apis-hypermedia-collection-document.html
<p>Following is a transcript of a talk that was given at the <a href="http://www.apistrategyconference.com/2013SF/index.php">APIStrategy and Practice Conference</a> in San Francisco, in October 2013.</p>
<p><img src="/files/breakingbad-pmp-h.jpg" alt="PMP Stylized as a Breaking Bad poster" /></p>
<h2 id="part-one-your-cms-is-broken-and-so-is-mine">Part One: Your CMS Is Broken. And So Is Mine.</h2>
<p>I was invited here, today, to tell you about a <a href="http://docs.pmp.io">massive content platform</a> that we built as a Hypermedia API and why it is revolutionary.</p>
<p>But before we get to the good part, I need to make a confession:</p>
<blockquote>
<p>All content management systems are broken in a bad way.</p>
</blockquote>
<p>How do I know? I know because I have been part of the problem. I have spent a decade building content management systems for large multinationals, US Federal Government and a number of leading news organizations. I’ve done my share of proprietary ones and for years I was also a top contributor to open-source Drupal, which some of you probably use.</p>
<p>This is my public confession that we, despite all our best intentions, have failed miserably. No modern CMS is really architected for what publishers need.</p>
<p>What do publishers need? They need:</p>
<ol>
<li>An easy way to connect to many content sources.</li>
<li>Ability to push content to many destinations: web, mobile and probably B2B.</li>
<li>They need their CMS to be architected for the “Cloud” so they don’t have to ever worry about silly things like: “are my servers up?”, or “do they scale?”</li>
</ol>
<p>Unfortuantely, these are not the concerns that any CMS is architected for.
.
The mismatch of needs and the solutions isn’t just a problem for NPR or New York Times or Reuters. We live in the age of ‘Everybody Is a Publisher’.</p>
<p>A very vivid example of how deeply broken content management systems are, is how many people are choosing Github for publishing websites. And these are not just some geeks. The website part of healthcare.gov was built on top of Git. Ironically it was also the only part that actually worked.</p>
<p>If people are choosing code versioning systems to publish <strong>content</strong>, it’s safe to say: “Houston, we have a problem”.</p>
<h2 id="part-two-public-media-platform-">Part Two: Public Media Platform <a name="pmp"></a></h2>
<p>The conditions of the discovery of the solution to this problem were somewhat serendipitous.</p>
<p>About a year ago I and my team were asked to develop a <a href="http://docs.pmp.io">content platform</a> where hundreds of publishers could easily store, exchange and explore content.</p>
<p>The system:</p>
<ol>
<li>had to be built for cloud/be scalable</li>
<li>had to facilitate decentralized content sourcing</li>
<li>and had to allow publishing to a wide variety of destinations</li>
</ol>
<p>The irony of these three requirements being exactly what I knew a modern content management system needed wasn’t lost on me.</p>
<p>Building this kind of distributed system is hard and very risky. We immediately started looking for a success story of anybody having built anything so decentralized. The answer was right in front of us: it’s called the World Wide Web and we <em>know</em> it works.</p>
<p>Better yet, very smart people, such as <a href="http://en.wikipedia.org/wiki/Roy_Fielding">Roy Fielding</a>, <a href="http://twitter.com/mamund">Mike Amundsen</a>, <a href="http://twitter.com/mnot">Mark Nottingham</a>, <a href="https://twitter.com/iosebi">Ioseb Dzmanashvili</a>, <a href="https://twitter.com/jon_moore">Jon Moore</a> and others have spent years analyzing what makes web’s architecture work.</p>
<p>The key to the web architecture is: Hypermedia.</p>
<h2 id="part-three-hypermedia-">Part Three: Hypermedia <a name="hypermedia"></a></h2>
<p>Hypermedia is the matter of which the World Wide Web is made. Much like physical world is built of interacting elementary particles (Bosons and Fermions), the web is essentially the universe of myriad of interacting hypermedia documents.</p>
<p>Despite Hypermedia coming into the spotlight relatively recently, it is no baby. Hypermedia is more than twenty years old. Twenty-three to be precise. And much like we ourselves were at that age: it’s largely misunderstood, very rebellious, but also full of potential.</p>
<p>Most of Hypermedia’s potential comes from three core traits:</p>
<ul>
<li>the robustness of the HTTP protocol,</li>
<li>universal use of URLs</li>
<li>and the extremely versatile media types it uses: HTML and CSS.</li>
</ul>
<p>Now HTML is really special. It’s just a handful of tags, but the wealth of creative user-interfaces and user experiences that people are able to build with them is truly astounding. You have a handful of simple rules and you get enormous creativity. That’s magical. That’s the kind of thing we wanted.</p>
<p>We didn’t want something too prescriptive. Such things are either dead-at-birth due to bloat or the least-common-denominator solutions like RSS. RSS is fine, but it already exists. We wanted a magic like HTML, not something like RSS.</p>
<p>To be able to achieve this challenging task we needed to “stand on the shoulders of the giants”. We started with <a href="http://twitter.com/mamund">Mike Amundsen’s</a> Collection+JSON media type, and <a href="http://twitter.com/mnot">Mark Nottingham’s</a> Home Document specification. We added years of our own experience with content APIs and content management systems and created a media type we called Collection Document.</p>
<p><a href="https://github.com/publicmediaplatform/pmpdocs/wiki/Collection.doc-JSON-Media-Type">Collection Document</a> is a recursive media type that is a document and a collection at the same time. As a collection it contains other documents that can contain other documents etc. This recursion allows to describe very complex domains.</p>
<p>But it’s also simple: it has only three top-level elements: attributes, links and errors. Links is the most important part since that’s what communicates the behavior and relationships of the content. For link types, rather then inventing new ones, we really tried to use popular, standard IETF link relation types whenever possible.</p>
<p><img src="https://raw.github.com/publicmediaplatform/pmpdocs/master/charts/collection+doc+json.png" alt="Collection.Document media type diagram" /></p>
<p>Following are the most important link relation types that Collection Document employs:</p>
<ul>
<li>Profile: allows defining additional semantics on top of the media type. This is how you would define attributes of specific content types, which is an important task in content publishing. Profiles are also inheritable allowing re-use and collaboration. Profile definitions are themselves instances of the collection document type and are saved just like any other document. Which means: to define a new profile, you don’t have to go through a standards body. Innovation around profiles is decentralized.</li>
</ul>
<p>Creating lists or buckets of documents is one of the most important task in content management, so we provide both of the two possible ways of doing so.</p>
<ul>
<li>
<p>Item link: is a way to define collections top-down. This is when a document points to other documents that it contains. It’s a ‘contains’ relationship, suitable for “blog contains blog posts” or “news story contains asset documents” scenarios.</p>
</li>
<li>
<p>Collection link: is a bottom-up approach. In this case child documents themselves are pointing to which parent document they’re associated with. It’s a ‘belongs to’ relationship, suitable for things like: topics.</p>
</li>
<li>
<p>Permission links define who can access and modify the documents and point to a type of Collection.document that contains such information.</p>
</li>
<li>
<p>Query links are parametrized search URLs that you can run to explore and segment data.</p>
</li>
<li>
<p>Edit links are the form templates that you can submit to modify data.</p>
</li>
</ul>
<p>All primary keys and relationships in a Collection Document are URL-based, allowing us to leverage a lot of built-in security, caching and routing capabilities of the HTTP protocol.</p>
<p>The current implementation of the media type is defined on top of JSON. Mostly because JSON is very simple and widely accepted format by API devs, but the media type itself is easily portable to XML or even as a microformats extension of HTML5.</p>
<p>We found that using these basic rules, Collection.doc media type can easily facilitate many use-cases. We can’t demonstrate all of them, but I would like to tell you about one that really brought this whole thing home for us.</p>
<h3 id="web-of-apis">Web of APIs</h3>
<p>When we started building Public Media Platform, we faced a dilemma. NPR already has a large API with hundreds of content producers in it. Once we launch PMP, what should they do? Will producers have to send content to both NPR API and PMP API? This was a big question we candidly had trouble answering.</p>
<p>So we did what all good engineers do (#chuckle): we ignored the problem and kept going forward.</p>
<p>When we were done building PMP the answer became obvious. Usage of Hypermedia and religious usage of URLs for referencing everything (even internally) allowed us to “break” the biggest constraint of traditional APIs: the silo-ing of the content. In “classical” APIs: all documents need to live within the API itself. It’s not like Twitter API can make sense of a tweet that was created and is stored in another API. But PMP can, because all of its content are just URLs to certain types of documents. Where these documents live is largely irrelevant.</p>
<p>I repeat: you can have core data that your API relies on live somewhere else, as far as you can reference it!</p>
<p>That is groundbreaking in the APIs world. But ironically it’s natural for the rest of the web. You don’t save your page directly into Google’s database to make it searchable. And you don’t have to publish your webpage into somebody else’s database to make linkages. You kindof had to do such silly things for the APIs, though. But now we don’t need to, anymore.</p>
<p>When you use Hypermedia properly and specifically if you use Collection.Document media type, you end up with a true web of APIs. A truly distributed, robust and versatile system. Something that APIs weren’t able to do before.</p>
<p>Now, that is quite magical.</p>
Deploying RapidSSL/GeoTrust SSL certificates to an AWS Elastic Load Balancer (ELB)
2013-09-21T00:00:00-04:00
http://www.freshblurbs.com/blog/2013/09/21/geotrust-rapidssl-amazon-aws-elb.html
<p>RapidSSL wildcard certificates are a relatively affordable (compared to most of its competition) wildcard SSL certificates that can be used to deploy HTTPS services using SSL encryption for any subdomains of your domain. If you need to provide several domains over HTTPS, buying separate SSL certificates for each one of them can be quite costly, therefore a cost-effective wildcard certificate provider becomes interesting.</p>
<p>RapidSSL certificates are signed by GeoTrust:</p>
<blockquote>
<p>RapidSSL Certificates are X.509 Certificates with SSL Extensions that chain to GeoTrust’s
trusted root(s) and that are vetted to a specified level domain and may be used in connection with
all next level higher domains that contain the specified vetted level domain.</p>
</blockquote>
<p>Source: http://www.geotrust.com/resources/cps/pdfs/RapidSSLCPS-Version1.0.pdf</p>
<h3 id="getting-started">Getting Started</h3>
<p>To obtain an SSL certificate you need to:</p>
<ol>
<li>Generate a private key</li>
<li>Generate and provide a Certificate Signing Request (CSR) file</li>
</ol>
<h4 id="generate-a-private-key">Generate a Private Key</h4>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ openssl genrsa -out private-key.pem 2048
</code></pre></div></div>
<h4 id="generate-a-csr">Generate a CSR</h4>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ openssl req -new -key private-key.pem -out csr.pem
</code></pre></div></div>
<p>CSR creation is an interactive process. You should respond to questions the script asks, as follows:</p>
<ul>
<li>Country Name: Use the two-letter ISO code for the country, for example: US or UK.</li>
<li>State or Province: Spell out the name in its entirety. For instance, type “New York”, not: “NY”</li>
<li>Company: Use only latin character of the name. Omit any other characters, including: ampersand.</li>
<li>Organizational Unit: indicate your wildcard domain, e.g.: *.example.com</li>
<li>Common Name: indicate your wildcard domain, e.g.: *.example.com</li>
</ul>
<p>Leave all other fields blank, including the e-mail.</p>
<h4 id="obtaining-certificate">Obtaining Certificate</h4>
<p>Once you purchase your certificate and submit the CSR, RapidSSL will e-mail you two keys: <code class="language-plaintext highlighter-rouge">Web Server CERTIFICATE</code> and <code class="language-plaintext highlighter-rouge">INTERMEDIATE CA</code>. Save them in files correspondingly named: <code class="language-plaintext highlighter-rouge">cert.pem</code> and <code class="language-plaintext highlighter-rouge">ca.pem</code></p>
<p>Check the two files to make they are valid and compatible using a handy online tool, such as: http://sslchecker.com/matcher</p>
<h3 id="option-1-deploying-through-the-aws-management-console">Option 1: Deploying through the AWS Management Console</h3>
<p>In the Listeners section of your AWS ELB configuration, add an HTTPS listener and add a new certificate. In the <code class="language-plaintext highlighter-rouge">Upload a new SSL Certificate</code> form, enter the contents of the cert.pem into <code class="language-plaintext highlighter-rouge">Public Key Certificate</code> field, contents of the private-key.pem into the <code class="language-plaintext highlighter-rouge">Private Key</code> field and the contents of the ca.pem into: the <code class="language-plaintext highlighter-rouge">Certificate Chain</code>field.</p>
<h3 id="using-aws-iam-tools">Using AWS IAM Tools</h3>
<p>Install AWS IAM Tools. On your Mac you can do it using Brew:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ brew install aws-iam-tools.
</code></pre></div></div>
<p>Follow the instructions provided by the brew post-install screen to configure IAM tools and set AWS credentials for it.</p>
<h4 id="uploading-a-new-cert">Uploading a new cert</h4>
<p>Once you have the IAM tools working:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ iam-servercertupload -b cert.pem -k private-key.pem -c ca.pem -s SomeWildcardCert
</code></pre></div></div>
<p>Replace <code class="language-plaintext highlighter-rouge">SomeWildcardCert</code> with whatever name you want the new cert to appear under in the AWS Admin Console.</p>
Hypermedia APIs vs. API Governance
2013-09-13T00:00:00-04:00
http://www.freshblurbs.com/blog/2013/09/13/hypermedia-apis-api-governence.html
<p>Organizations that take their tech teams down the “Everything is a Web Service” (à la: Jeff Bezos and Amazon Web Services) architectural route, often and quickly find that such approach can lead to a number of problems:</p>
<ul>
<li>uncontrolled explosion of the number of services,</li>
<li>duplication of code,</li>
<li>services of varying degree of reliability,</li>
<li>inability to evolve services due to tight coupling.</li>
</ul>
<h4 id="api-governance">API Governance</h4>
<p>A common “solution” to such problems is to enact “API Governance”: a committee that decides a process for the management of services and oversees their creation (typically: by green-lightning some and banning others). Aside from the obvious problems with the “design by a committee” such centralized decision-making has a problem of becoming a bottleneck and slowing-down or killing innovation. Obviously, that is a result opposite to what we would hope for when moving an organization to a service-centric architecture.</p>
<h4 id="hypermedia-apis">Hypermedia APIs</h4>
<p>I firmly believe that Hypermedia APIs, due to: their decoupled nature and focus on designing media types, rather than the endpoints and routes, have huge opportunity in providing more elegant solution to the complexity problem. Even at the very early stage of <a href="http://pmp.io">Public Media Platform</a> (which is a Hypermedia API), we are seeing this potential and I am very curious to see how the potential materializes.</p>
<p>Stay tuned.</p>
New York Times Snow Fall: Editorial Skeumorphism?
2013-07-17T00:00:00-04:00
http://www.freshblurbs.com/blog/2013/07/17/snowfall-editorial-skeumorphism.html
<p>New York Times’ <a href="http://www.nytimes.com/projects/2012/snow-fall/">Snow Fall</a> story has been a whopping success in attracting spotlight. It went viral immediately after publishing, and resulted in many imitations. It has also drawn some <a href="https://medium.com/editors-picks/66b9060333ad">constructive criticism</a>.</p>
<p>I think Snow Fall is a landmark example of technical excellence of implementation, pushing the boundaries of possible on the web and of bold experimentation. On a less exciting side, I also think it broke ground in a whole new category of <a href="http://en.wikipedia.org/wiki/Skeuomorph">skeumorphism</a>, something I would call: Editorial Skeumorphism.</p>
<blockquote>
<p>Editorial Skeumorphism is present when primary digital content is decorated with “ornaments” (auxiliary content treatment) that is not organic to the primary content. Such ornamentation serves the purpose of being attractive eye-candy, but can take attention away from the primary content.</p>
</blockquote>
<p>The main problem with Snow Fall design is the confusing visual hierarchy. The story is a great example of masterful long-form writing: 10,000+ words of captivating narrative, yet the story text is definitely not the center of attention in the design. The text of the story is set in small-by-modern-standards, 15px, font and the fabulous visual effects all around it provide enough distraction for probably very few people to concentrate on the actual story.</p>
<h3 id="what-was-the-goal">What was the goal?</h3>
<p>If the goal of NYT was to get many pageviews: they have succeeded beyond any doubt (was a single banner enough to capitalize on that success, though?). I have to question how many people have actually read the story, however? I obviously don’t have the data and I would love to be proven wrong, but large body of UX research in readership attention span and visual hierarchy, as well as non-scientific, anecdotal polling of a handful of people around me makes me think that: very small percentage did.</p>
<p>It makes me sad to think that an important, well-written 10,000+ word story may not have gotten read because text was overshadowed by [very creative] visual treatment that was probably supposed to be auxiliary to the story. Did too much “chrome” ruin the experience of reading?</p>
<p>If it did indeed happen, then this is the problem with Editorial Skeumorphism: we, the horrible modern humans have limited attention span and for us to spend any time with anything, it must be very clear what we are expected to do. Attracting us with great visuals and then expecting that it will make us also read long-form text is probably a very unrealistic expectation.</p>
<p>I think the visuals of Snow Fall were a clear editorial mismatch to the long-form text. It would have probably worked fantastically with audio, since audio doesn’t require the same kind of undivided attention that text does.</p>
Using Multiple SSH Keys with Github
2013-06-22T00:00:00-04:00
http://www.freshblurbs.com/blog/2013/06/22/github-multiple-ssh-keys.html
<p>Note: if you are too impatient to read the whole thing, feel free to jump to the <a href="#tldr">TL;DR Summary</a></p>
<h2 id="why-do-we-need-this">Why do we need this?</h2>
<p>As much as we love <a href="http://github.com">Github</a>, its approach to managing access to repositories can sometimes be quite frustrating. The core problem is that, for some mysterious reason, Github has decided that using the same SSH public key with multiple users or repositories (via Deploy Keys) is a bad idea. I have no idea why they decided so, since there’s no apparent security implication that I can think of, but since they have, we now have to deal with it.</p>
<p>To be fair, Github has implemented many convenient ways of managing access to repos: <a href="https://help.github.com/articles/managing-deploy-keys">https://help.github.com/articles/managing-deploy-keys</a> and one in particular: Deploy Keys is an extremely smart way for scripting deployments on a remote server with that server’s SSH Key. Actually, I stand corrected: it <em>would</em> have been very convenient if there were no <em>donot-reuse-the-keys</em> rule. It is very likely that you will need to work with multiple repos on the same server (duh!) and since you cannot associate the same key with multiple repos, Deploy Keys become quite limited.</p>
<p>The solution Github kindof suggests in such cases is to create and use <a href="https://help.github.com/articles/managing-deploy-keys">“Machine Users”</a>. I personally really hate this approach: creation of pseudo users shouldn’t be a solution for system’s shortcomings. Machines are not users and don’t have e-mails. That’s silly.</p>
<p>Since Github doesn’t allow us to reuse an SSH Key, the only sane solution is to jump through some hoops and generate + use multiple keys on the server itself. Let’s look at some effective approaches of doing that.</p>
<p>Let’s assume we have two repos on Github:</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">git@github.com:inadarei/foo.git</code> and</li>
<li><code class="language-plaintext highlighter-rouge">git@github.com:inadarei/bar.git</code></li>
</ul>
<p>which we need to script deployments of, on an imaginary myshinyserver.com Linux server.</p>
<h2 id="creation-of-multiple-ssh-keys">Creation of Multiple SSH Keys</h2>
<p>First things first. Let’s create SSH keys for each of our repos:</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">$</span><span class="w"> </span>ssh-keygen <span class="nt">-f</span> ~/.ssh/id_rsa.github.inadarei.foo
<span class="go">
Generating public/private rsa key pair.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/irakli/.ssh/id_rsa.github.inadarei.foo.
Your public key has been saved in /home/irakli/.ssh/id_rsa.github.inadarei.foo.pub.
</span><span class="gp">$</span><span class="w"> </span>ssh-keygen <span class="nt">-f</span> ~/.ssh/id_rsa.github.inadarei.bar
<span class="go">
Generating public/private rsa key pair.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/irakli/.ssh/id_rsa.github.inadarei.bar.
Your public key has been saved in /home/irakli/.ssh/id_rsa.github.inadarei.bar.pub.
</span></code></pre></div></div>
<p>Go on Github.com to the corresponding repositories and create Deploy Keys for each repo, where you will copy/paste the corresponding public keys (e.g. <code class="language-plaintext highlighter-rouge">~/.ssh/id_rsa.github.inadarei.foo.pub</code>)</p>
<p>Now that we have an SSH key per repo, there’re multiple ways for how we can actually use them. Let’s discuss some of [my] top choices.</p>
<h2 id="option-1-custom-hosts-in-an-ssh-config">Option 1: Custom Hosts in an SSH Config</h2>
<p>This is probably the most straightforward approach exploiting SSH’s capability of aliasing hostnames and allowing you to use distinct configuration per host (or aliased host).</p>
<p>Create a file <code class="language-plaintext highlighter-rouge">~/.ssh/config</code> if you do not already have it and place the following configuration in it:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># account for the foo repo</span>
Host github.com-foo
HostName github.com
User inadarei
IdentitiesOnly <span class="nb">yes
</span>IdentityFile ~/.ssh/id_rsa.github.inadarei.foo
<span class="c"># account for the bar repo</span>
Host github.com-bar
HostName github.com
User inadarei
IdentitiesOnly <span class="nb">yes
</span>IdentityFile ~/.ssh/id_rsa.github.inadarei.bar
</code></pre></div></div>
<p>Basically you are telling SSH (and correspondingly Git, when it uses SSH for repo access) to create multiple host aliases for the same hostname of github.com and that each alias should use distinct configurations. Please note the “IdentitiesOnly yes” directive. This config line is very important to make sure that SSH does actually use the identity file you indicate. Otherwise your configuration may be overridden by an SSH agent or other things on the system.</p>
<p><strong>IMPORTANT:</strong> When you check out a repository with this approach you <strong>cannot</strong> use the actual Git URL such as: <code class="language-plaintext highlighter-rouge">git@github.com:inadarei/foo.git</code>. Instead, you <strong>have</strong> to edit that URL to use the aliased hostname. For instance, the repo URL for the <code class="language-plaintext highlighter-rouge">foo</code> repository will be: <code class="language-plaintext highlighter-rouge">git@github.com-foo:inadarei/foo.git</code>. Please note the <code class="language-plaintext highlighter-rouge">github.com-foo</code> used as the hostname.</p>
<p>If you have an existing local checkout you should alter the URL of the remote by either:</p>
<ul>
<li>
<p>issuing a git command such as:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> git remote set-url origin git@github.com-foo:inadarei/foo.git
</code></pre></div> </div>
</li>
<li>
<p>or by editing the <code class="language-plaintext highlighter-rouge">url</code> parameter of the <code class="language-plaintext highlighter-rouge">[remote "origin"]</code> section in your local <code class="language-plaintext highlighter-rouge">.git/config</code> file of the checkout.</p>
</li>
</ul>
<h2 id="option-2-using-ssh-add">Option 2: Using SSH-Add</h2>
<p><code class="language-plaintext highlighter-rouge">ssh-add</code> utility on a Unix system allows you to quickly and affectively indicate which SSH key you want to use. This is a quicker, but probably less flexible approach.</p>
<p>To see the SSH Keys currently configured:</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">$</span><span class="w"> </span>ssh-add <span class="nt">-l</span>
<span class="go">2048 ...REDACTED... /home/irakli/.ssh/id_rsa (RSA)
2048 ...REDACTED... /home/irakli/.ssh/id_rsa.foo (RSA)
2048 ...REDACTED... /home/irakli/.ssh/id_rsa.bar (RSA)
</span></code></pre></div></div>
<p>In this example my SSH knows about three keys. This actually won’t work since git/Github will only pay attention to the first one and fail.</p>
<p>To delete all known keys:</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">$</span><span class="w"> </span>ssh-add <span class="nt">-D</span>
<span class="go">All identities removed.
</span></code></pre></div></div>
<p>To add a new key:</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">$</span><span class="w"> </span>ssh-add ~/.ssh/id_rsa.github.inadarei.foo
<span class="go">Identity added: /home/irakli/.ssh/id_rsa.github.inadarei.foo (/home/irakli/.ssh/id_rsa.github.inadarei.foo)
</span><span class="gp">$</span><span class="w"> </span>ssh-add <span class="nt">-l</span>
<span class="go">2048 ...REDACTED... /home/irakli/.ssh/id_rsa.foo (RSA)
</span></code></pre></div></div>
<p><strong>IMPORTANT:</strong> Do not forget to run <code class="language-plaintext highlighter-rouge">ssh-add -D</code> after you are done messing with Github in this approach, to go back to your default SSH private key.</p>
<p>If you have password-protected SSH private keys, you may want to use <code class="language-plaintext highlighter-rouge">ssh-agent</code> so it only asks the password once + saves it and doesn’t annoy you with asking the password all the time.</p>
<p>Also, if you want to ssh-add a key only temporarily (say, in a deployment script) you can do something like the following:</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">$</span><span class="w"> </span>ssh-agent bash <span class="nt">-c</span> <span class="s1">'ssh-add ~/.ssh/id_rsa.github.inadarei.foo; git clone git@github.com:inadarei/foo.git'</span>
</code></pre></div></div>
<p>This way ssh-agent will fork the process and ssh-add will only be effective for the duration of the execution of the <code class="language-plaintext highlighter-rouge">git clone</code> command (or whatever else git command you need to execute and end-up scripting).</p>
<p><a id="tldr"></a></p>
<h2 id="tldr-summary">TL;DR Summary</h2>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">$</span><span class="w"> </span>ssh-keygen <span class="nt">-f</span> ~/.ssh/id_rsa.github.inadarei.foo
</code></pre></div></div>
<p>In the ~/.ssh/config:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># account for the foo repo</span>
Host github.com-foo
HostName github.com
User inadarei
IdentitiesOnly <span class="nb">yes
</span>IdentityFile ~/.ssh/id_rsa.github.inadarei.foo
</code></pre></div></div>
<p>Make sure to check-out the repo with the aliased hostname (github.com-foo) or if you already have a checkout run something like:</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">$</span><span class="w"> </span>git remote set-url origin git@github.com-foo:inadarei/foo.git
</code></pre></div></div>
<h2 id="post-scriptum">Post Scriptum</h2>
<p>I hope that at some point Github will either remove the “donot reuse SSH keys” constraint or at least clearly explain to us why they are putting us through all the trouble.</p>
<p>Meanwhile, I hope this blog post is helpful to somebody.</p>
Easy Way To Daemonize Hubot (Hipchat) on Debian Linux
2013-06-16T00:00:00-04:00
http://www.freshblurbs.com/blog/2013/06/16/hubot-hipchat-daemon.html
<p><a href="https://npr.hipchat.com">HipChat</a> is a very nice chat software by Atlassian. <a href="http://hubot.github.com/">Hubot</a> is an amazing XMPP chat bot that makes usage of HipChat orders of magnitude more effective and FUN.</p>
<p>There’s a handy <a href="https://github.com/hipchat/hubot-hipchat">HipChat Hubot adapter</a> that brings Hubot awesomeness to HipChat. HipChat Hubot project’s README provides very well-documented installation instructions for Heroku or barebones OS-X/Debian/Ubuntu (hint: just skip the Heroku steps).</p>
<p>There are only two shortcomings that I ran into:</p>
<ul>
<li>Current version of the adapter seems to have a nasty problem with Redis-Brain extension: <a href="https://github.com/hipchat/hubot-hipchat/issues/109">https://github.com/hipchat/hubot-hipchat/issues/109</a>. Solution: remove redis-brain.coffee from hubot-scripts.json</li>
<li>Instructions come short on providing a nice daemon script if you do decide to host Hubot yourself and skip the whole Heroku thing.</li>
</ul>
<p>Following is what worked for me. Please note that sample code assumes you checked-out hubot under <code class="language-plaintext highlighter-rouge">/home/yourname/hubot</code> folder and intend to run it under <code class="language-plaintext highlighter-rouge">yourname</code> user. This is not an init.d script. If it were, you’d have to deal with sudoing into a user from root user, managing missing paths and a number of other things which which I had no patience dealing with.</p>
<p>First you need to create a config file under <code class="language-plaintext highlighter-rouge">/home/{change user}/hubot/bin</code>. Call it .hubotrc:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#---------------- HUBOT CONFIG -----------------------------------</span>
<span class="nb">export </span><span class="nv">HUBOT_HIPCHAT_JID</span><span class="o">=</span><span class="s2">"... fill this in ... "</span>
<span class="nb">export </span><span class="nv">HUBOT_HIPCHAT_PASSWORD</span><span class="o">=</span><span class="s2">"... fill this in ... "</span>
<span class="nb">export </span><span class="nv">HUBOT_AUTH_ADMIN</span><span class="o">=</span><span class="s2">"... fill this in ... "</span>
<span class="nb">export </span><span class="nv">HUBOT_ADAPTER</span><span class="o">=</span><span class="s2">"hipchat"</span>
<span class="nb">export </span><span class="nv">HUBOT_PATH</span><span class="o">=</span><span class="s2">"/home/{change user}/hubot"</span>
<span class="c">#---------------- END HUBOT CONFIG --------------------------------</span>
npm <span class="nb">install
export </span><span class="nv">PATH</span><span class="o">=</span><span class="s2">"node_modules/.bin:node_modules/hubot/node_modules/.bin:</span><span class="nv">$PATH</span><span class="s2">"</span>
</code></pre></div></div>
<p>Under the same folder, create a daemon.sh that looks something like following:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#!/bin/sh</span>
<span class="nv">USER_HOME</span><span class="o">=</span><span class="s2">"/home/</span><span class="nv">$USER</span><span class="s2">"</span>
<span class="nv">HUBOT_ROOT</span><span class="o">=</span><span class="s2">"</span><span class="nv">$USER_HOME</span><span class="s2">/hubot"</span>
<span class="nv">HUBOT_HOME</span><span class="o">=</span><span class="s2">"</span><span class="nv">$HUBOT_ROOT</span><span class="s2">/node_modules/hubot"</span>
<span class="nv">DAEMON</span><span class="o">=</span><span class="s2">"</span><span class="nv">$HUBOT_HOME</span><span class="s2">/bin/hubot"</span>
<span class="nv">PIDFILE</span><span class="o">=</span><span class="nv">$HUBOT_ROOT</span>/hubot.pid
<span class="k">case</span> <span class="s2">"</span><span class="nv">$1</span><span class="s2">"</span> <span class="k">in
</span>start<span class="p">)</span>
<span class="nb">echo</span> <span class="s2">"Starting"</span>
<span class="nb">.</span> <span class="nv">$HUBOT_ROOT</span>/bin/.hubotrc
/sbin/start-stop-daemon <span class="nt">--start</span> <span class="nt">--background</span> <span class="nt">--pidfile</span> <span class="nv">$PIDFILE</span> <span class="nt">--make-pidfile</span> <span class="nt">-d</span> <span class="nv">$HUBOT_ROOT</span> <span class="nt">--exec</span> <span class="nv">$DAEMON</span>
<span class="nb">echo</span> <span class="s2">"."</span>
<span class="p">;;</span>
debug<span class="p">)</span>
<span class="nb">echo</span> <span class="s2">"Debug mode: no backgrounding"</span>
<span class="nb">.</span> <span class="nv">$HUBOT_ROOT</span>/bin/.hubotrc
/sbin/start-stop-daemon <span class="nt">--start</span> <span class="nt">--pidfile</span> <span class="nv">$PIDFILE</span> <span class="nt">--make-pidfile</span> <span class="nt">-d</span> <span class="nv">$HUBOT_ROOT</span> <span class="nt">--exec</span> <span class="nv">$DAEMON</span>
<span class="nb">echo</span> <span class="s2">"."</span>
<span class="p">;;</span>
stop<span class="p">)</span>
<span class="nb">echo</span> <span class="s2">"Stopping"</span>
/sbin/start-stop-daemon <span class="nt">--stop</span> <span class="nt">--pidfile</span> <span class="nv">$PIDFILE</span>
<span class="nb">echo</span> <span class="s2">"."</span>
<span class="p">;;</span>
restart<span class="p">)</span>
<span class="nb">echo</span> <span class="s2">"Restarting"</span>
/sbin/start-stop-daemon <span class="nt">--stop</span> <span class="nt">--pidfile</span> <span class="nv">$PIDFILE</span>
<span class="nb">.</span> <span class="nv">$HUBOT_ROOT</span>/bin/.hubotrc
/sbin/start-stop-daemon <span class="nt">--start</span> <span class="nt">--pidfile</span> <span class="nv">$PIDFILE</span> <span class="nt">--make-pidfile</span> <span class="nt">--background</span> <span class="nt">-d</span> <span class="nv">$HUBOT_ROOT</span> <span class="nt">--exec</span> <span class="nv">$DAEMON</span>
<span class="nb">echo</span> <span class="s2">"."</span>
<span class="p">;;</span>
<span class="k">*</span><span class="p">)</span>
<span class="nb">echo</span> <span class="s2">"Usage: </span><span class="nv">$0</span><span class="s2"> {start|stop|restart|debug}"</span> <span class="o">></span>&2
<span class="nb">exit </span>1
<span class="p">;;</span>
<span class="k">esac</span>
<span class="nb">exit</span>
</code></pre></div></div>
<p>The <code class="language-plaintext highlighter-rouge">daemon</code> mode is useful when you do not want to background hubot because you are debugging some trouble and do need to actually see the output from the script.</p>
<p>Happy chatting and botting.</p>
Some Indications That Google Glass Will Not Be a Mass-Market Success
2013-05-04T00:00:00-04:00
http://www.freshblurbs.com/blog/2013/05/04/google-glass-will-not-be-mass-market-success.html
<p>Google Glass is probably the most polarizing tech gadget being discussed.
Most people are either convinced that it is the greatest
human innovation since Apollo 11 Moon landing or that it is yet another doomed
Google project. #Snark: It’s not like we have any shortage of the latter.</p>
<p>The excitement on the “next big thing” side is obvious and very understandable.
After all, we do live in the <a href="http://www.npr.org/2013/05/02/180556950/of-flybots-and-bug-eyes-insects-inspire-inventors">age of tools miniaturization</a>,
and there’s nothing surprising about the “wearable smartphone” idea capturing our
imaginations.</p>
<p>The big question, however, is: Is Google Glass it?</p>
<p>There are some strong indications that it is not. You have most certainly heard
the obvious ones: “Google does not know how to do hardware” and <a href="http://techcrunch.com/2013/04/26/eric-schmidt-is-right-using-google-glasses-is-weird-heres-my-experience/">“Glass is just
too weird”</a>.</p>
<p>I think the not-a-hardware-company argument may have some ground, but: Google
CAN hire, and indeed: has hired, people who do have track record of creating
successful hardware. There is however a significant leap from that to creating a breakthrough mass-market product. Additional factors, such as: company culture, massive global production logistics that needs to be built, etc. must be considered. Jury is still out on whether Google can pull the production and distribution of a mass-market hardware on its own.</p>
<p>The latter argument (Glass is too weird for a mass-market gadget) I do
agree with, but to be fair: it’s also a matter of taste. Additionally: breakthrough products can change
consumer aesthetics. There’re many examples of products that had looked weird at first
and have later become admired as iconic designs.</p>
<p>There is however one indicator of Google’s improbable success that I have not
seen discussed, so far: timing.</p>
<p>Google Glass was announced more than a year ago. It will be at least another year
untill general public can buy it. That is at least two years from public announcement
to launch!</p>
<p>While breakthrough technologies do often take years to develop, I have hard time
remembering a single breakthrough mass-market gadget that was announced two years
prior to its public sales and that has taken a market over.</p>
<p>There is a reason why Apple is so famously secretive. It could be that Jobs
learned a good lesson from his NeXT days: when he had a product years ahead of
its time, but one that never became a successful mass-market product.</p>
<h3 id="tldr">TL;DR</h3>
<p>Google could have done itself a favor to take a cue from its Silicon Valley
neighbour, limiting the fanfare so early before the public launch, but it’s
too late now, anyway.</p>
<p>Time will show if fanfare-to-market-time is a good indication of a gadget’s
projected [lack of] success. My gut tells me that it may be.</p>
<p>I believe that Google Glass will resonate strongly with hobbyists, but I am not
going to hold my breath for anything like the iPhone or iPad launches.</p>
Object Oriented JavaScript from Classical OO Perspective
2013-01-13T00:00:00-05:00
http://www.freshblurbs.com/blog/2013/01/13/object-oriented-javascript.html
<p>For programmers accustomed to conventional Object-Oriented languages, such as: Java or C++, JavaScript’s
Object-Oriented implementation can often be confusing. Contrary to the popular misconception, this is not
due to JavaScript’s “flawed object-orientedness”, but it is so because JavaScript is a functional
language and its approach to object-orientedness is simply different. Not flawed—just different.</p>
<p>Let’s elaborate on that.</p>
<p>JavaScript is a <strong>class-free</strong> object-oriented language. It uses prototypal inheritance rather than class-based
one. To properly understand how it works, we need to break away from the accustomed thinkning patterns, formed
by usage of languages like Java, Ruby or C++.</p>
<p>Rule #1: functions in Javascript are objects, and there are no classes! To fully understand
prototypal inheritance, we need to accept this as a fact and refuse the temptation
of creating faux notions of a class in Javascript. JavaScript is a functional language,
and functions are first-class citizens:</p>
<ul>
<li>Functions are objects, they are always instantiated and assigned to variables
<ul>
<li><code class="language-plaintext highlighter-rouge">function name() {}</code> is just a shortcut syntax to <code class="language-plaintext highlighter-rouge">var name = function() {}</code></li>
</ul>
</li>
<li>Since they are objects, functions can be passed as arguments to other functions</li>
<li>Functions have structure: properties (variables) that can point to other functions, objects or primitive types.</li>
<li>Functions have prototypes and can share features of other functions using prototypal inheritance.</li>
</ul>
<h3 id="but-how-do-you-do-oo-without-a-class">But How Do You Do OO Without a Class?</h3>
<p>The notion of a Class in conventional OO languages, provides two main features: type-checking
and code re-use. Given that JavaScript is a dynamically-typed language, there’s little to no
benefit using classes for typing. As for code re-use: due to increased flexibility, prototypal
inheritance can actually lead to more code re-use than class-based inheritance. So no
problem there, as well.</p>
<p>One last time: if you want to understand JavaScript’s OO and get productive in it, you should
not try to fall in a trap of figuring out “what is a class in JavaScript”?
There is no Class. By design. Make peace with it and enjoy.</p>
<p>Getting used to prototypal inheritance takes time and experience. Books like Douglas Crockford’s
<a href="http://shop.oreilly.com/product/9780596517748.do">JavaScript; The Good Parts</a> can be helpful,
but if you are just starting out it also helps to have examples of how you’d do things in Javascript
which you’d normally be using classes for.</p>
<h3 id="tldr-survival-guide-only">TL;DR: Survival Guide Only</h3>
<p>How do we create a ‘parent’ function (note: not ‘a class’) in Javascript and assign an inheritable function
prototypally to it? This is analogous to assigning a method to a class, in conventional languages.
Furthermore, how do we define a ‘child’ function, tell it to prototypally get features
from the ‘parent’ and re-use parent’s constructor? This would be analogous of
‘parent class constructor inheritance’ in the class-based object-oriented languages.</p>
<p>Following code snippet does all of that without using any third-party libraries:</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Parent definition</span>
<span class="kd">function</span> <span class="nx">Animal</span><span class="p">(</span><span class="nx">name</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">name</span><span class="p">)</span> <span class="k">return</span><span class="p">;</span>
<span class="k">this</span><span class="p">.</span><span class="nx">name</span> <span class="o">=</span> <span class="nx">name</span><span class="p">;</span>
<span class="p">}</span>
<span class="c1">// Defining a member function on the parent</span>
<span class="nx">Animal</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">getName</span> <span class="o">=</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="nx">name</span><span class="p">;</span>
<span class="p">}</span>
<span class="c1">// Function definition with constructor "inheritance"</span>
<span class="kd">function</span> <span class="nx">Cat</span><span class="p">(</span><span class="nx">name</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">Animal</span><span class="p">.</span><span class="nx">call</span><span class="p">(</span><span class="k">this</span><span class="p">,</span><span class="nx">name</span><span class="p">);</span> <span class="c1">// "inherit" constructor </span>
<span class="k">this</span><span class="p">.</span><span class="kd">constructor</span> <span class="o">=</span> <span class="nx">Cat</span><span class="p">;</span> <span class="c1">// "fix" constructor pointer. Read further for details.</span>
<span class="p">};</span>
<span class="c1">// Telling "child" to "extend" the "parent". This is sugar syntax.</span>
<span class="nx">Cat</span><span class="p">.</span><span class="nx">prototype</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Animal</span><span class="p">;</span>
<span class="c1">// Or, for server-side, V8 code, the preferred method is to use</span>
<span class="c1">// __proto__ because it does not "damage" Cat's constructor pointer and does</span>
<span class="c1">// not require the "fix" which we had to apply in the code above. Here's how </span>
<span class="c1">// you'd do it:</span>
<span class="c1">// Cat.prototype.__proto__ = Animal.prototype;</span>
<span class="c1">// Testing the whole thing</span>
<span class="kd">var</span> <span class="nx">kitty</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Cat</span><span class="p">(</span><span class="dl">"</span><span class="s2">Smokey</span><span class="dl">"</span><span class="p">);</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">kitty</span><span class="p">.</span><span class="nx">getName</span><span class="p">());</span>
<span class="c1">// Note the difference between the two when using __proto__ vs. not using it:</span>
<span class="c1">// console.dir(Cat);</span>
<span class="c1">// console.dir(Cat.prototype.constructor);</span>
</code></pre></div></div>
<p>A bunch of people try to think of “prototype” as being analogous to the
notion of a “class”. This is wrong, because the whole point of a class
is that you can instantiate it. You are not instantiating a “prototype” in
Javascript, you are instantiating functions.</p>
<p>I think the best way to think of a “prototype” is to look at it like a public/private
marker. Functions that are defined through a prototype are “public” for sharing the
functionality (call it “inheritance” if you will), whereas the functions that
you just attach to a function are instance-specific and “private” in regards with
sharing/inheriting.</p>
<p>There are also a handful of libraries that create “sugar” syntaxes and make prototypal
inheritance look more like “class”-based inheritance.</p>
<p>I believe attempts to create a notion of a “class” in Javascript are misguided.
There is no need to be stubborn about class-based
inheritance and reject prototype-based inheritance in JavaScript, just because we may
be used to class-based inheritance in other languages. It’s much better to embrace
full functional flexibility of what JavaScript provides out of the box.</p>
<p>There is no such thing as a “class” in Javascript. It is so by design.</p>
Fix for '[rejected] gh-pages -> gh-pages (non-fast-forward)' in GitHub
2012-09-15T00:00:00-04:00
http://www.freshblurbs.com/blog/2012/09/15/fixing-rejected-gh-pages-git.html
<h3 id="tldr">TL;DR</h3>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git config --global push.default tracking
</code></pre></div></div>
<h3 id="full-story">Full Story</h3>
<p><a href="https://help.github.com/articles/what-are-github-pages">GitHub Pages</a> are public webpages
freely hosted and easily published through <a href="http://github.com">github.com</a>. They are most commonly used to create
good-looking documentation for code hosted on GitHub
(case in point: <a href="http://npr.github.com/responsiveiframe/">http://npr.github.com/responsiveiframe/</a>).
GitHub Pages have also become a popular solution for hosting minimalistic websites and/or blogs.
That includes the blog you are reading: Fresh Blurbs is hosted on GitHub Pages.</p>
<p>You can manage Github Pages through
a web user interface, but often you may desire full control over the end result,
consequently going down the <a href="https://help.github.com/articles/creating-project-pages-manually">manual setup</a>
route.</p>
<p>When you set GitHub Pages up manually, you have to create an “orphaned” branch called <code class="language-plaintext highlighter-rouge">gh-pages</code>. This is
the branch where your <a href="https://github.com/mojombo/jekyll">Jekyll</a> templates or static HTML will reside.
For any repository GitHub also creates a <code class="language-plaintext highlighter-rouge">master</code> branch in your repo. For code pages, master branch usually hosts
the code part of the project. For websites and blogs <code class="language-plaintext highlighter-rouge">master</code> branch may be empty or the place where you
keep Jekyll source (if you use custom plugins and have to pre-build site before pushing to github.com).</p>
<p>To make the long story short, when using GitHub Pages you typically end up with at least two branches:
<code class="language-plaintext highlighter-rouge">master</code> and <code class="language-plaintext highlighter-rouge">gh-pages</code>. The two branches are not “branches” of each other in the classical version-management
sense: they were never intended to be merged or have anything in common.</p>
<p>This can create certain issues.</p>
<p>If you manually manage GitHub pages you most probably have <code class="language-plaintext highlighter-rouge">gh-pages</code> and <code class="language-plaintext highlighter-rouge">master</code> checked out in
separate folders, pulling and pushing the two from and to github.com independently. I would also guess
that when pushing you are frequently annoyed by an error message that looks something like:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> ! [rejected] gh-pages -> gh-pages (non-fast-forward)
</code></pre></div></div>
<p>or this (depending which workspace you are pushing from):</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>! [rejected] master -> master (non-fast-forward)
</code></pre></div></div>
<p>Here is why you are getting it: in each workspace Git tries to push <strong>all</strong> existing
branches to GitHub, not just the current one. Given how you have two independent branches, things frequently
go awry.</p>
<p>To solve the problem you can modify the default behavior. Typically, you don’t really need Git to push all
branches, just the one you are working on. So, why not tell Git that is what you want? Here is how you do
it:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git config --global push.default tracking
</code></pre></div></div>
<p>Easy peasy, no more annoying messages and we are back to being in love with Git (because it rocks).</p>
How To Daemonize PHP-FPM on Mac OS-X Mountain Lion with Brew
2012-08-25T00:00:00-04:00
http://www.freshblurbs.com/blog/2012/08/25/how-daemonize-php-fpm-mac-os-x-mountain-lion-brew.html
<p>One of the easiest ways to install/upgrade PHP on Mac OS-X is using
<a href="http://mxcl.github.com/homebrew/">brew</a>. In the current version, if you
install PHP 5.3 or 5.4 via brew using FPM, the php-fpm launcher installs
in the foreground mode, by default. That can be very inconvenient, since
it means that when you launch php-fpm it holds a terminal window and if
you close the window, the process dies.</p>
<p>Luckily it is also something very easy to fix.</p>
<p>First, locate php-fpm configuration file by running a configuration
test:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>php-fpm -t
</code></pre></div></div>
<p>You should see an output like:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/usr/local/etc/php/5.3/php-fpm.conf
</code></pre></div></div>
<p>Now open the php-fpm.conf file in your favorite editor and find a
configuration option that looks like:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>; Send FPM to background. Set to 'no' to keep FPM in foreground for debugging.
; Default Value: yes
daemonize = no
</code></pre></div></div>
<p>and change the value to “yes”, or comment the configuration out (since
default is “yes”).</p>
<p>That’s it!</p>
Branching in Git with Remote Tracking
2012-08-03T00:00:00-04:00
http://www.freshblurbs.com/blog/2012/08/03/branching-git-remote-tracking.html
<p><strong>Problem:</strong> we would like to set up a new branch off of an existing
branch in a remote and make sure local/remote tracking is set up
properly.</p>
<p>In this example, our remote is Github and we are trying to create a
branch named “develop” off of an existing remote branch called “master”.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>> git clone git@github.com:zaphpa/zaphpa.git develop
> cd develop/
# Branch a new "develop" branch off of master branch
> git checkout -b develop master
> git status
# Push new "develop" branch to origin
> git push origin develop
> git remote show origin
# Make local branch track the upstream branch
> git branch --set-upstream develop origin/develop
</code></pre></div></div>
<p><strong>Note</strong>: If you are using GitHub you will need to make a push from the
new branch to see it in the GitHub branches view.</p>
Async Data Loading in Knockout.js Without the 'Callback 'Hell'
2012-05-09T00:00:00-04:00
http://www.freshblurbs.com/blog/2012/05/09/async-data-loading-knockout-js-without-callback-hell.html
<p><a href="http://knockoutjs.com/">Knockout.js</a> is a beautifully implemented MVVM
Javascript framework that makes creating highly dynamic, modern,
Ajax-driven user-interfaces a breeze and almost completely removes the
need to directly mess with HTML DOM, thus drastically decreasing the
complexity of front-end code and making things typically complicated –
trivial.</p>
<p>Full introduction to Knockout.js is both way beyond this blog post, as
well as: unnecessary. Knockout is possibly the <a href="http://knockoutjs.com/documentation/introduction.html">best
documented</a>
open-source framework I have ever seen. It even comes with wonderful,
<a href="http://learn.knockoutjs.com/">interactive tutorials</a> that can get you
started in no time.</p>
<p>The use-case I want to cover in this post is: async loading of multiple
parts of the page, without causing the proverbial “javascript callback
hell”. The bonus part will cover implementing a handy “loading”
indicator. While I will cover the technique in the context of
Knockout.js, the same principal applies to any MVVM framework (or even
if you are just fiddling around with jQuery directly). That said,
understanding of Knockout is required to get the most of the
description, so head over to <a href="http://knockoutjs.com/documentation/introduction.html">the
documentation</a>,
if you are unfamiliar with Knockout. It won’t take too long to get a
grasp of. Promise.</p>
<h2 id="setup">Setup</h2>
<p>Let’s assume we are using Knockout to implement a somewhat typical “Edit
User” page. The model behind the page is a user object, which we will
load/save via Ajax. However, a user must be able to also pick: country
of residence and his/her language preference. Here’s a catch: we want
the list of country options and the list of available languages to also
load via Ajax (say, using some API call). Furthermore, we want countries
and languages to load in parallel, since the two do not depend on each
other and doing things in parallel speeds overall page load time,
obviously.</p>
<p>The somewhat complicated part is that: we do need to make sure that both
the country list, as well as languages list are loaded _before_ we
load the user object. This is necessary so that Knockout gets a chance
to populate options on corresponding drop-downs before Knockout tries to
set current user value on those drop-downs. Last, but not least, we
would like to show a user a “loading” visual indicator, while things are
loading over Ajax calls, just in case any of them take some time.</p>
<h2 id="html-part">HTML part</h2>
<p>Following are some key parts of the HTML markup we will need for this
exercise. For the sake of brevity only certain snippets are shown:</p>
<p>Github gist link: https://gist.github.com/2642420</p>
<script src="https://gist.github.com/2642420.js?file=knockoutAdvancedGist.html"></script>
<p>Please note that we are using <a href="http://knockoutjs.com/documentation/plugins-mapping.html">Knockout
Mapping</a>
plugin. Related to it, please note in the HTML (and below in Javascript)
that data properties are encapsulated on a “user” property of the
Knockout model object, not: directly on the model. I personally find
that this makes using the mapping plugin, while being able to have other
logical methods directly on the model - much easier/safer/better.</p>
<h2 id="javascript-part">Javascript part</h2>
<p>Much like with the HTML, only the most important parts of the
Javascript/Knockout side are shown, for the sake of brevity:</p>
<p>Github gist link: https://gist.github.com/2642523</p>
<script src="https://gist.github.com/2642523.js?file=AdvancedKnockout.js"></script>
<h2 id="what-did-just-happen">What Did Just Happen?</h2>
<p>Probably the most important part of the code is the following snippet:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>var parallelExecutions = [self.loadCountries, self.loadLanguages];
var delayedLoadUser = _.after(parallelExecutions.length, self.loadUser);
_.each(parallelExecutions, function(func) {
func({success: delayedLoadUser});
});
</code></pre></div></div>
<p>It uses the <a href="http://documentcloud.github.com/underscore/#after">after()</a>
method from the Underscore.js library to run loadContries() and
loadLanguages() functions asynchronously and in parallel, but waits
until both of them complete before running loadUser() function. The
delay is achieved by creating the delayedLoasUser() wrapper method.</p>
<p><strong>Note:</strong> if you have written server-side, Node.js Javascript you are
probably familiar with the wonderful
<a href="https://github.com/caolan/async">Async.js</a> and wondering why am I using
Underscore where Async’s parallel() method might work great. It would
and if I was writing server-side code, I probably would have used Async
over Underscore, in this case, but minified Async.js is 108KB vs
Underscore’s 13K, so the latter felt a more prudent choice for
client-side code.</p>
<p>Please also note that the loading indicator is an array, rather than a
scalar variable. This allows us to treat it as a stack, pushing a value
when something starts loading and popping a value when something
finishes loading, supporting parallel loading of many request in a clean
and simple way.</p>
Why Google Is Wrong To Obsess About Facebook
2012-04-29T00:00:00-04:00
http://www.freshblurbs.com/blog/2012/04/29/why-google-wrong-obsess-about-facebook.html
<p>I closed my Facebook account several months ago and have since enjoyed
time not spent on the social network, spending it much more productively
and enjoyably elsewhere. Now, for full disclosure: being in web
development I can not ignore Facebook so I still have a developer
account, to keep up with the platform, but I do not use Facebook for
anything personal.</p>
<p>I did not close my account because of Facebook’s attitude towards
privacy. I did understand privacy implications; I did have all the
“right” settings configured to minimize the impact and while slightly
annoyed with their approach (disregard?) to privacy, I was generally OK
to continue using the service. But I closed the account when it simply
stopped providing meaningful benefit to me.</p>
<p>And that is the key to most social networks: the novelty wears off quite
quickly. Initially they seem like the best thing since sliced bread, but
soon enough it’s just the same boring routine, turning into a waste of
time eventually. In order to not sound fixated on Facebook, it was even
more so the case with Quora, for me. Initial reaction to Quora was
amazing. I could ask a question to a GitHub founder and get a response
in a day. Direct response! How cool is that? But then again: how many
“Githubs” am I going to find on Quora, and how many founders of those do
I care to ask a question to? The model is not sustainable if you want
people coming back every day. And social networks can not survive
without users coming back every day, even: several times a day.</p>
<p>Of course: nobody understands this trait of social networks better than
Mark Zuckerberg. That’s why he keeps the company constantly on the edge:
always changing things, always adding features. This is why he turned
Facebook into a platform, rather than a single app: so other companies
could join into the eco-system and help innovate, help diversify. This
is why Facebook has been as successful as it has, and why nobody even
remembers MySpace, anymore.</p>
<p>However, it is also why Google should stop obsessing about Facebook. The
thing is, Google provides an essential service: search for a vast amount
of content. As far as they keep being good at it, there will never be
time when we do not need search or when we decide we are too bored with
search. Don’t get me wrong: Google still needs to keep innovating to
improve the service and adapt to changing demand, but the core business
model is sustainable in perpetuity: it’s an essential service. Facebook
is not. Much like MySpace, Facebook can go away and nobody would as much
as flinch.</p>
<p>I think it’s a safe bet to say that: in 5 years Facebook will either not
exist at all, or be so different that it will have almost nothing to do
with the Facebook we know today. I am sure that the same statement is
not true for Google Search.</p>
<p>This is why, in my opinion, Google executives should stop obsessing
about how much traffic Facebook gets today and what Facebook does TODAY,
instead they should worry about their own bread and butter: search, and
they should target where Facebook may be going tomorrow. What if next
time Zuckerberg pivots his company he decides to “reinvent” search?</p>
<p>THAT would be something to worry about, but as far as Google Plus goes,
sorry to break it: it’s a waste of Google’s time.</p>
Installing Mosh on Debian Squeeze and Mac OS-X Lion
2012-04-09T00:00:00-04:00
http://www.freshblurbs.com/blog/2012/04/09/installing-mosh-debian-squeeze-and-mac-os-x-lion.html
<p><a href="http://mosh.mit.edu">Mosh</a> is a nifty, UDP-based client-server utility
that greatly improves SSH connection’s reliability and usability,
especially on flaky connections or if you need to jump on/off VPN,
change IPs etc.</p>
<p>You need to install Mosh both on the client machine (Mac OS-X Lion in my
case) as well as server (Debian Squeeze for the sake of this blog post).</p>
<p>Installing on Mac was almost as easy as promised by the documentation:</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">></span><span class="w"> </span>brew update
<span class="gp">></span><span class="w"> </span>brew <span class="nb">link </span>pkg-config
<span class="gp">></span><span class="w"> </span>brew <span class="nb">install </span>mobile-shell
</code></pre></div></div>
<p>pretty much does it, given that you have latest XCode and HomeBrew
installed.</p>
<p>Installing on Debian Squeeze was a whole different experience. The Mosh
documentation only provides instructions for Ubuntu Lucid. You can try
adopting it for Debian, but I did not really have much success, so I
ended up installing from source, like this:</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">></span><span class="w"> </span><span class="nb">sudo </span>apt-get update
<span class="gp">></span><span class="w"> </span><span class="nb">sudo </span>apt-get <span class="nb">install </span>protobuf-compiler libprotobuf-dev
<span class="gp">></span><span class="w"> </span><span class="nb">sudo </span>apt-get <span class="nb">install </span>libboost-dev
<span class="gp">></span><span class="w"> </span><span class="nb">sudo </span>apt-get <span class="nb">install </span>libutempter-dev libncurses5-dev
<span class="gp">></span><span class="w"> </span><span class="nb">sudo </span>apt-get <span class="nb">install </span>zlib1g-dev
<span class="gp">></span><span class="w"> </span><span class="nb">sudo </span>apt-get <span class="nb">install </span>expect-dev libexpect-perl
<span class="gp">></span><span class="w"> </span><span class="nb">cd</span>
<span class="gp">></span><span class="w"> </span>wget https://github.com/downloads/keithw/mosh/mosh-1.1.3.tar.gz
<span class="gp">></span><span class="w"> </span><span class="nb">tar </span>xzvf mosh-1.1.3.tar.gz
<span class="gp">></span><span class="w"> </span><span class="nb">cd </span>mosh-1.1.3
<span class="gp">></span><span class="w"> </span>./configure
<span class="gp">></span><span class="w"> </span>make
<span class="gp">></span><span class="w"> </span><span class="nb">sudo </span>make <span class="nb">install</span>
<span class="gp">></span><span class="w"> </span>mosh-server
</code></pre></div></div>
<p>Please make sure that UDP communication is not blocked by a firewall and
connect to the server using a command like:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mosh username@example.com
</code></pre></div></div>
City-Level Geo IP Location Detection In PHP and Apache
2012-02-22T00:00:00-05:00
http://www.freshblurbs.com/blog/2012/02/22/city-level-geo-ip-location-detection-php-and-apache.html
<p>Following is a quick set of instructions to set up city-level location
detection using <a href="http://www.maxmind.com/">Maxmind’s</a> GeoIP library using
Apache/PHP.</p>
<p>There’re multiple ways to do it. Frankly the trickiest part is
figuring-out the most appropriate one. I think the most efficient
approach in cost/performance terms is to install C API and then let
mod_geoip Apache module interface with it, getting parsed values as
part of the $_SERVER variable on the PHP side. There’re some wrapper
PHP libraries on top of C library, as well as pure-PHP libraries, but
the former did not really work, while the latter is supposed to be much
slower than C lib/mod_geoip.</p>
<p>So here we go:</p>
<p>Install GeoIP C API</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">$</span><span class="w"> </span><span class="nb">mkdir</span> ~/src
<span class="gp">$</span><span class="w"> </span><span class="nb">cd </span>src
<span class="gp">$</span><span class="w"> </span>wget http://geolite.maxmind.com/download/geoip/api/c/GeoIP.tar.gz
<span class="gp">$</span><span class="w"> </span><span class="nb">tar </span>xzvf GeoIP.tar.gz
<span class="gp">$</span><span class="w"> </span><span class="nb">cd </span>GeoIP-1.4.8
<span class="gp">$</span><span class="w"> </span>./configure
<span class="gp">$</span><span class="w"> </span>make
<span class="gp">$</span><span class="w"> </span><span class="nb">sudo </span>make <span class="nb">install</span>
</code></pre></div></div>
<p>Install Apache GeoIP module</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">$</span><span class="w"> </span><span class="nb">cd</span> ..
<span class="gp">$</span><span class="w"> </span>wget http://geolite.maxmind.com/download/geoip/api/mod_geoip2/mod_geoip2_1.2.7.tar.gz
<span class="gp">$</span><span class="w"> </span><span class="nb">tar </span>xzvf mod_geoip2_1.2.7.tar.gz
<span class="gp">$</span><span class="w"> </span><span class="nb">cd </span>mod_geoip2_1.2.7
<span class="gp">$</span><span class="w"> </span><span class="nb">sudo</span> /usr/sbin/apxs <span class="nt">-i</span> <span class="nt">-a</span> <span class="nt">-L</span>/usr/local/lib <span class="nt">-I</span>/usr/local/include <span class="nt">-lGeoIP</span> <span class="nt">-c</span> mod_geoip.c
</code></pre></div></div>
<p>At the very end, you should get an output like:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">[</span>activating module <span class="sb">`</span>geoip<span class="s1">' in /etc/httpd/conf/httpd.conf]
</span></code></pre></div></div>
<p>Please note the Apache config file’s path and in that file, after the
LoadModule instruction for geoip (which installation steps above will
add automatically) add the following instruction:</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><IfModule</span> <span class="err">mod_geoip.c</span><span class="nt">></span>
GeoIPEnable On
GeoIPScanProxyHeaders On
GeoIPDBFile /usr/local/share/geoip/GeoIP.dat
GeoIPDBFile /usr/local/share/geoip/GeoLiteCity.dat
<span class="nt"></IfModule></span>
</code></pre></div></div>
<p>Now, let’s download the binary database (.dat) files indicated in the
config in those locations:</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">$</span><span class="w"> </span><span class="nb">cd</span> /usr/local/share
<span class="gp">$</span><span class="w"> </span><span class="nb">mkdir </span>geoip
<span class="gp">$</span><span class="w"> </span><span class="nb">cd </span>geoip
<span class="gp">$</span><span class="w"> </span>wget http://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz
<span class="gp">$</span><span class="w"> </span><span class="nb">gunzip </span>GeoIP.dat.gz
<span class="gp">$</span><span class="w"> </span>wget http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz
<span class="gp">$</span><span class="w"> </span><span class="nb">gunzip </span>GeoLiteCity.dat.gz
</code></pre></div></div>
<p>Once you are done setting up, restart Apache and configure a test script
to inspect the contents of the new $_SERVER variable, you should see
output like:</p>
<div class="language-php highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">Array</span>
<span class="p">(</span>
<span class="p">[</span><span class="no">GEOIP_ADDR</span><span class="p">]</span> <span class="o">=></span> <span class="c1">#CENSORED#</span>
<span class="p">[</span><span class="no">GEOIP_CONTINENT_CODE</span><span class="p">]</span> <span class="o">=></span> <span class="no">NA</span>
<span class="p">[</span><span class="no">GEOIP_COUNTRY_CODE</span><span class="p">]</span> <span class="o">=></span> <span class="no">US</span>
<span class="p">[</span><span class="no">GEOIP_COUNTRY_NAME</span><span class="p">]</span> <span class="o">=></span> <span class="nc">United</span> <span class="nc">States</span>
<span class="p">[</span><span class="no">GEOIP_REGION</span><span class="p">]</span> <span class="o">=></span> <span class="no">VA</span>
<span class="p">[</span><span class="no">GEOIP_REGION_NAME</span><span class="p">]</span> <span class="o">=></span> <span class="nc">Virginia</span>
<span class="p">[</span><span class="no">GEOIP_CITY</span><span class="p">]</span> <span class="o">=></span> <span class="c1">#CENSORED#</span>
<span class="p">[</span><span class="no">GEOIP_DMA_CODE</span><span class="p">]</span> <span class="o">=></span> <span class="c1">#CENSORED#</span>
<span class="p">[</span><span class="no">GEOIP_METRO_CODE</span><span class="p">]</span> <span class="o">=></span> <span class="c1">#CENSORED#</span>
<span class="p">[</span><span class="no">GEOIP_AREA_CODE</span><span class="p">]</span> <span class="o">=></span> <span class="c1">#CENSORED#</span>
<span class="p">[</span><span class="no">GEOIP_LATITUDE</span><span class="p">]</span> <span class="o">=></span> <span class="c1">#CENSORED#</span>
<span class="p">[</span><span class="no">GEOIP_LONGITUDE</span><span class="p">]</span> <span class="o">=></span> <span class="c1">#CENSORED#</span>
<span class="p">[</span><span class="no">GEOIP_POSTAL_CODE</span><span class="p">]</span> <span class="o">=></span> <span class="c1">#CENSORED#</span>
<span class="p">)</span>
</code></pre></div></div>
<p>I put “#CENSORED#” for some values, but obviously there should be
actual values present that you can use in your PHP app.</p>
<p>I believe that there’re instructions on the web for installing and
configuring similar setup for Nginx and Light HTTPD as well. Approach
should be very similar.</p>
<p>Enjoy.</p>
Plea For Better Responsive Web Design Support In Browsers
2012-02-04T00:00:00-05:00
http://www.freshblurbs.com/blog/2012/02/04/plea-better-responsive-web-design-support-browsers.html
<p>Responsive Web Design <a href="http://bit.ly/f6TPB7">http://bit.ly/f6TPB7</a> is an extremely important
approach/technique/movement for making web mobile-friendly. Given that
web mobile traffic is exploding and there were more smart-phones sold in
2011 than PCs <a href="http://vrge.co/wqOiED">http://vrge.co/wqOiED</a> the importance of the movement
can not be emphasized enough.</p>
<p>We have some significant obstacles on the path of fully optimized
Responsive Web Design, however. Responsive Images (smaller images for
smaller screens to optimize download times) and optimized CSS/JS (mobile
devices don’t need the same JS/CSS as desktop browsers do) are the
obvious ones.</p>
<p>The most optimal way to handle responsive images and optimize CSS/JS
would be on the server-side. However, server-side does not have enough
information about device capabilities, resulting in emergence of all
kinds of cruft-y solutions (e.g. using div’s for img tags etc.) that
should not exist.</p>
<p>However, browsers do know a lot about devices they are running on and
could pass that information to servers as part of the initial request,
making it possible for servers to get way smarter than what we have now.</p>
<p>Something as simple as if browsers passed along device’s width/height
information as part of the initial request headers would go a very very
long way, making it possible to make a lot of intelligent decisions on
the server-side (eventually allowing “media-queries-like” systems on the
server-side).</p>
<p>Since some proxy servers cut-off or disable custom headers, probably the
safest way to add this is to add width/height information in the
user-agent header.</p>
<p>The text of this plea was submitted to all major browser vendors and WhatWG group. Many thanks to <a href="http://twitter.com/paul_irish">@paul_irish</a> for suggesting the latter.</p>
<ul>
<li>WhatWG: <a href="http://lists.whatwg.org/pipermail/whatwg-whatwg.org/2012-February/thread.html#34634">http://lists.whatwg.org/pipermail…</a> – <a href="http://lists.whatwg.org/pipermail/whatwg-whatwg.org/2012-February/034634.html">Original Post</a></li>
<li>Google Chrome: <a href="http://www.google.com/support/forum/p/Chrome/thread?tid=7dc8f9c37e97a303&hl=en">http://www.google.com/support/forum/…</a></li>
<li>Firefox: <a href="https://support.mozilla.org/en-US/questions/917322">https://support.mozilla.org…</a></li>
<li>Internet Explorer: <a href="https://connect.microsoft.com/Connect/feedback/details/723367/please-report-device-capabilities-in-a-request-header">https://connect.microsoft.com…</a></li>
<li>Opera: <a href="http://my.opera.com/community/forums/topic.dml?id=1294672&t=1328384124&page=1#comment11550282">http://my.opera.com/community/forums…</a></li>
<li>Safari/WebKit <a href="https://lists.webkit.org/pipermail/webkit-dev/2012-February/019310.html">https://lists.webkit.org/pipermail/…</a></li>
</ul>
Agile Code - Design for Refactoring, Not Maintenance
2012-01-20T00:00:00-05:00
http://www.freshblurbs.com/blog/2012/01/20/agile-code-design-refactoring-not-maintenance.html
<p>Couple things happened today (Friday, of all days):</p>
<ol>
<li>My old blog hosting company sent a “we are shutting down” notice.
Out of curiosity I clicked through and quickly found myself reading
5-year old posts. One of them was ranting about code maintenance.</li>
<li>A friend
<a href="https://twitter.com/#!/crdant/status/160530812075393024">tweeted</a> a
link to a blog post by Rohan Singh: <a href="http://rohanradio.com/blog/2012/01/19/isnt-all-coding-about-being-too-clever/">Isn’t All Coding About Being
Too
Clever?</a>
where he’s also talking about maintainable code (with a different
perspective).</li>
</ol>
<p>This got me thinking…</p>
<p>In majority of software engineering literature, “maintainability” of
code is hailed as sacred. It’s easy to relate to the sentiment: no code
gets written once and then forgotten. When you ship code, you give it
birth, but the actual life of that code is only just starting. You want
to make sure your code spends its life well – goes to college, marries
the right person, and makes the “parents” proud when other people have
to deal with it (that’s the maintenance part).</p>
<p>Except, much like with kids, your plans for your code almost never work
out as initially intended. If you are smart enough you accept them just
the way they turn out to be (at least - code, if not kids) , without
trying to be a control freak. And that’s where this obsession with
“maintenance” can become a problem.</p>
<p>Unfortunately, when people think of maintainable code, instead of making
it the simplest it can be and stepping back (which is what Rohan
advocates, too) they try to predict how the code will be used. Code
quickly gets overloaded with interfaces, abstract classes and
over-engineered placeholders for conceived extension points – all
according to a long list of “design patterns” (I am looking at you,
old-school Java developers!). If you guessed that such code is the
opposite of its simplest form, then you have guessed right. What happens
next time somebody needs to deal with that code? Don’t expect any Thank
You cards in the mail.</p>
<p>TL;DR</p>
<p>Designing software for “maintenance” is dangerous. A lot of people
misinterpret this sentiment as “designing for future needs”. We can’t
know what these needs will be. A much safer approach is to create the
simplest code that get the job done and assume you will refactor that
code soon.</p>
<p>Design your code not for deceiving goal of “maintenance”, but for ease
of future refactoring: write simply, document well, use automated tests
(unit-tests rock), modularize code and couple components loosely – so
that when you modify one thing, the entire application does not fall
down on you.</p>
<p>When somebody else has to touch your code, the first thing they want is
to rewrite your “mess” anyway. Don’t fight it – make it easy and let
them only rewrite a small part of the code that they need to deal with,
without having to untangle entire monster. Design for refactoring.</p>
APC on OS-X: PHP Fatal error: Unknown: apc_fcntl_unlock failed
2011-12-27T00:00:00-05:00
http://www.freshblurbs.com/blog/2011/12/27/apc-os-x-php-fatal-error-unknown-apc-fcntl-unlock-failed.html
<p>APC 3.1.9 has a nasty bug, causing a frustrating error: “PHP Fatal
error: Unknown: apc_fcntl_unlock failed: in Unknown on line 0” to
appear when installed with PECL on Mac OS-X (and reportedly on a variety
of Linux platforms).</p>
<p>There’s an easy fix.</p>
<p>When you <a href="http://freshblurbs.com/installing-apc-mac-os-x-php">install APC through
PECL</a> it asks for a
number of settings. Do NOT go with the default value for “spin locks”
even though it warns the feature to be experimental. Experimental or
not, but it looks like it’s a hard dependency for the rest of APC so:
shame on them, be “wild” and say ‘yes’:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Enable spin locks (EXPERIMENTAL) [no] : yes
</code></pre></div></div>
<p>That’s it. Seemingly this should solve the problem. In reality: who
knows what else is broken, but, hey, it’s PHP! :)</p>
<p>No, seriously…</p>
Weird 'exec: 179: : Permission denied' Error When Installing Elastic Search
2011-11-02T00:00:00-04:00
http://www.freshblurbs.com/blog/2011/11/02/weird-exec-179-permission-denied-error-when-installing-elastic-search.html
<p><a href="http://www.elasticsearch.org/">Elastic Search</a> is a fantastic,
clustered search server built on top of Apache Lucene search engine.
It’s very easy to install and configure.</p>
<p>However, on some servers, if you follow instructions (which is
basically: download, unpack, run: bin/elasticsearch) you may get a weird
permission error:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ ./elasticsearch
exec: 179: : Permission denied
</code></pre></div></div>
<p>even though there are no apparent permission problems and even if you
run the script with sudo (which you should not have to).</p>
<p>The solution is extremely simple: if this happens, the real issue is
that you do not have JDK 6. I know, that’s not what the error complains
about, but that’s typically the root problem. Install JDK6 (e.g. with:
“sudo apt-get install openjdk-6-jdk” on Debian) and the problem will go
away.</p>
Check PHP Configuration INI Files Actually Loaded
2011-10-30T00:00:00-04:00
http://www.freshblurbs.com/blog/2011/10/30/check-php-configuration-ini-files-actually-loaded.html
<p>It’s not always easy, in PHP, to figure-out which PHP ini files are
actually parsed and loaded. CLI may use diff set than web, and if you
are using NginX with FPM, there may be yet another set.</p>
<p>Following extremely simple piece of code can greatly help to clear-up
the confusion:</p>
<div class="language-php highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp"><?php</span>
<span class="nb">print_r</span><span class="p">(</span> <span class="nb">php_ini_loaded_file</span><span class="p">()</span> <span class="p">);</span>
<span class="nb">print_r</span><span class="p">(</span><span class="s2">"Scanned: "</span><span class="p">);</span>
<span class="nb">print_r</span><span class="p">(</span> <span class="nb">php_ini_scanned_files</span><span class="p">()</span> <span class="p">);</span>
<span class="k">exit</span><span class="p">();</span>
</code></pre></div></div>
Espresso And Syntax Highlights for Custom File Formats
2011-10-23T00:00:00-04:00
http://www.freshblurbs.com/blog/2011/10/23/espresso-and-syntax-highlight-custom-file-formats.html
<p>I like <a href="http://macrabbit.com/espresso/">Espresso</a> from MacRabbit for
server-side scripting a lot. The latest version (2.0) has merged a
wonderful code editor with the best-of-the-class CSS editor, giving one
awesome, unified experience. And, of course, you can edit your files
directly over an SSH connection (the latter, alas, is not as
straightforward as it is in Panic’s <a href="http://www.panic.com/coda/">Coda</a>,
but, well, we love both of them for different reasons).</p>
<p>Nothing in this life is perfect, however. One glaring shortcoming of
Espresso is: no UI for assigning a syntax highlighter to custom file
extensions. Espresso recognizes most common file extensions, but if you
do something slightly different, e.g.: use .tpl files in Drupal (which
are PHP files) or use Handlebars templates in Javascript (which are
basically HTML), you won’t get default syntax highlighting because
Espresso does not know what type of files these are.</p>
<p>Let’s see how we can teach Espresso custom file types. I will do this
for .handlebars files, which are template files I use for my Javascript
coding.</p>
<ol>
<li>Right-click on Espresso.app in Finder and select: “show package
contents”.</li>
<li>Go to folder: Contents > SharedSupport > Sugars</li>
<li>Right-clic on “XML-and-HTML.sugar” and select: “show package
contents”.</li>
<li>Open Languages.xml for editing (with vi, Textmate or whatever your
favorite text editor is)</li>
<li>
<p>Scroll down to detectors section which should read something like:\</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> html
htm
...
</code></pre></div> </div>
</li>
<li>
<p>Add more extensions to the section, e.g. for handlebars, I added:\</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>handlebars
</code></pre></div> </div>
</li>
<li>Save languages.xml and restart Espresso</li>
</ol>
Command-Line Javascript (CLI) On Mac OS-X
2011-09-25T00:00:00-04:00
http://www.freshblurbs.com/blog/2011/09/25/command-line-javascript-cli-mac-os-x.html
<p>With the increasing popularity of server-side Javascript, you may want
to have Javascript everywhere. You can use Javascript outside of a
browser, on any platform. There are many choices: you can install
Mozilla SpiderMonkey, Google V8 or Mozilla Rhino. If you are like me and
use Mac OS-X as your development machine, however, you have hit a
jackpot: OS-X Leopard and later come with Javascript CLI pre-installed.
The CLI uses JavascriptCore by Apple, the same engine used in the Safari
browser, and many other places all over OS-X.</p>
<p>This is how you can enable JSC:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo ln -s /System/Library/Frameworks/JavaScriptCore.framework/Versions/Current/Resources/jsc /bin/jsc
</code></pre></div></div>
<p>Once you do that, you can run the jsc interactive shell or write
javascript shell executables by putting:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>#!/bin/jsc
</code></pre></div></div>
<p>at the top of a shell script. <a href="http://trac.webkit.org/wiki/JSC">JSC
Wiki</a> lists some extra commands you can
use in your CLI scripts.</p>
<h2 id="alternative-js-clis">Alternative JS CLIs</h2>
<p>If you install <a href="https://github.com/mxcl/homebrew">Homebrew, “the missing package-manager for OS
X”</a> (generally a great idea for a
developer), installing Google v8 or Mozzila Spidermonkey or Rhino
becomes trivially easy:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ brew install v8
$ brew install spidermonkey
$ brew install rhino
</code></pre></div></div>
<p>For Rhino, you need to make sure you have Java installed on your Mac. If
you do that, JS executables will correspondingly be located in:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/usr/local/Cellar/v8/HEAD/bin/v8
/usr/local/Cellar/spidermonkey/1.8.5/bin/js
/usr/local/Cellar/rhino/1.7R3/bin/rhino
</code></pre></div></div>
<p>Typically, brew will also create convenience symlinks:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/usr/local/bin/v8
/usr/local/bin/js
/usr/local/bin/rhino
</code></pre></div></div>
<p>For quick shell-script prototyping, Spidermonkey is my favorite because
you can put:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>#!/usr/local/bin/js
</code></pre></div></div>
<p>at the top of a shell script, making it executable, and Spidermonkey is
much more debuggable than JSC (which swallows error messages).</p>
<p>If you need to load an existing Javascript library, or break your script
up into multiple files, all you need to do is write something like the
following in your script:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>load("included.js");
</code></pre></div></div>
<p>where “included.js” is some javascript in the same folder as your main
script file (and does not contain “#!/usr/local/bin/js”)</p>
<p>Pretty neat stuff, overall.</p>
Elegant Way To Format SQL's Where IN For PHP 5.3
2011-09-03T00:00:00-04:00
http://www.freshblurbs.com/blog/2011/09/03/elegant-way-format-sqls-where-php-5-3.html
<p>It’s a pretty common need to format an array as a proper comma-delimited
string for use in SQL’s “WHERE … IN” clause. Following is a simple
solution that demonstrates how closures in PHP 5.3+ make writing such
code pretty elegant. A unit-test is included to demonstrate several edge
cases:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>function sql_instring($arr) {
if (empty($arr)) {
return "IS NULL";
}
return "IN (" .
implode(',',
array_map(function($arg) {
if (is_numeric($arg)) {
return $arg;
}
elseif (is_string($arg)) {
return "'$arg'";
}
else {
throw new Exception('Invalid Argument: must be string or a number.');
}
},
$arr)
) .
")";
}
class SQLInTest extends PHPUnit_Framework_TestCase {
function test_instring() {
$arr = array (1,2,3,4,5);
$expected = "IN (1,2,3,4,5)";
$this->assertEquals($expected,sql_instring($arr));
$arr = array (1);
$expected = "IN (1)";
$this->assertEquals($expected,sql_instring($arr));
$arr = array ();
$expected = "IS NULL";
$this->assertEquals($expected,sql_instring($arr));
$arr = array ('a', 'b', 'c');
$expected = "IN ('a','b','c')";
$this->assertEquals($expected,sql_instring($arr));
}
}
</code></pre></div></div>
Install CouchDB On Debian Squeeze from Source
2011-08-28T00:00:00-04:00
http://www.freshblurbs.com/blog/2011/08/28/install-couchdb-debian-squeeze-source.html
<p>Following is a step-by-step guide to installing the latest CouchDB
release on Debian Squeeze from sources.</p>
<h2 id="installing-prerequisites">Installing Prerequisites</h2>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo apt-get update
$ sudo apt-get install build-essential
$ sudo apt-get install libssl0.9.8 libssl-dev zlib1g zlib1g-dev lsb-base
$ sudo apt-get install ncurses-dev libncurses-dev
$ sudo apt-get install unixodbc unixodbc-dev xsltproc
$ sudo apt-get install libmozjs-dev libmozjs1d libicu-dev
(if you get an error on libmozjs1d, try: libmozjs2d)
$ sudo apt-get install libcurl4-dev libcurl4-openssl-dev # (if libcurl-dev is not already installed)
</code></pre></div></div>
<h2 id="installing-erlangotp">Installing Erlang/OTP</h2>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ cd /usr/local/src
$ sudo wget http://www.erlang.org/download/otp_src_R14B03.tar.gz
$ sudo tar xzvf otp_src_R14B03.tar.gz
$ cd opt_src_R14B03
$ sudo ./configure
$ sudo make && sudo make install # (this will complain about jinterface, wx, and documentation; you can ignore these)
</code></pre></div></div>
<h2 id="installing-couchdb">Installing CouchDB</h2>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ cd /usr/local/src
$ sudo wget http://mirrors.ibiblio.org/apache//couchdb/1.1.0/apache-couchdb-1.1.0.tar.gz
$ sudo tar xzvf apache-couchdb-1.1.0.tar.gz
$ cd apache-couchdb-1.1.0
$ sudo ./configure --prefix=/usr
$ sudo make && sudo make install
$ sudo /usr/sbin/adduser --system --home /usr/var/lib/couchdb --no-create-home --shell /bin/bash --group --gecos "CouchDB Administrator" couchdb
</code></pre></div></div>
<h2 id="configuring-couchdb">Configuring CouchDB</h2>
<p>By default CouchDB only attaches itself to 127.0.0.1. If you need to
connect to it from outside the server (e.g. to access embedded web-based
control panel) either:</p>
<ul>
<li>(preferred method!) Tunnel to 127.0.0.1:5984 from Apache or NginX</li>
<li>or edit /usr/etc/couchdb/default.ini and chage IP in the bind
instruction to 0.0.0.0 IP</li>
</ul>
<p>Setting proper permissions:\</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> sudo chown -R couchdb:couchdb /usr/etc/couchdb
sudo chown -R couchdb:couchdb /usr/var/lib/couchdb
sudo chown -R couchdb:couchdb /usr/var/log/couchdb
sudo chown -R couchdb:couchdb /usr/var/run/couchdb
sudo chmod 0770 /usr/etc/couchdb
sudo chmod 0770 /usr/var/lib/couchdb
sudo chmod 0770 /usr/var/log/couchdb
sudo chmod 0770 /usr/var/run/couchdb
</code></pre></div></div>
<p>Start CouchDB manually:\</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo -i -u couchdb /usr/bin/couchdb
</code></pre></div></div>
<p>Startup script:\</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo /usr/etc/init.d/couchdb start
sudo /usr/etc/init.d/couchdb stop
</code></pre></div></div>
<p>Once CouchDB successfully starts, you can access web-based interface
at:\</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ http://10.0.1.18:5984/_utils/
</code></pre></div></div>
<p>where 10.0.1.18 should be replaced by your server IP, of course.</p>
<h2 id="bonus-installing-couchrest-ruby-gem-for-couchdb">Bonus: Installing CouchREST Ruby Gem for CouchDB</h2>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo gem install couchrest
$ sudo gem install couchrest_model
</code></pre></div></div>
<p>test:\</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ irb
irb(main):001:0> require "rubygems"
=> true
irb(main):002:0> require "couchrest"
=> true
irb(main):003:0> require "couchrest_model"
=> true
irb(main):004:0> db = CouchRest.database!("http://localhost:5984/irakli")
=> http://localhost:5984/irakli
</code></pre></div></div>
<p>For more information about CouchRest Model please visit the official
website: <a href="http://www.couchrest.info/">http://www.couchrest.info/</a></p>
Install RabbitMQ on Debian Squeeze
2011-08-24T00:00:00-04:00
http://www.freshblurbs.com/blog/2011/08/24/install-rabbitmq-debian-squeeze.html
Pragmatic RESTful API Design
2011-06-19T00:00:00-04:00
http://www.freshblurbs.com/blog/2011/06/19/pragmatic-restful-api-design.html
<p>“REST vs. SOAP” has been an ongoing battle for quite a while, in the
tech industry. There is a seemingly upwards trend of the number of open
RESTful APIs emerging vs. the SOAP ones. It’s probably safe to conclude
that, at least among open APIs, REST is winning.</p>
<p>The problem, however is the ambiguity of the answer to the basic
question: what is REST?</p>
<h2 id="restful-api-design">RESTful API Design</h2>
<p>Representational State Transfer (REST) is an architectural style, for
distributed hypermedia systems. It was initially defined in 2000 by Roy
Fielding in his doctoral dissertation. REST is based on the concept of
transfer of representations of resources. A resource is any application
entity that can be uniquely addressed with a Uniform Resource Locator
(URL). A representation of a resource is a document that captures
current or intended state of a resource.</p>
<p>Since REST is an architectural style not: a well-defined specification,
it leaves a lot for interpretation. However, with the increased
proliferation of the RESTful style in popular web APIs, some common
traits have emerged which are now recognized as best-practices in
RESTful web API design. REST, in theory, is not limited to the web, but
for the purposes of this blog post we assume to be discussing REST in
the context of the world-wide web.</p>
<h2 id="basic-principles">Basic Principles</h2>
<ul>
<li>Proper RESTful APIs extensively utilize HTTP Protocol. Usage of HTTP
methods for CRUD, standard HTTP response codes, common HTTP headers
and Mime Types is a common practice.</li>
<li>
<p>URLs in RESTful APIs are semantic, resource-centric and have a
general structure which looks something like the following:\</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>http://api.example.com/{ver}/{lang}/{resource_type}/{resource_id}.{output_format}?{filters and api_key as arguments}
</code></pre></div> </div>
<p>where:</p>
<ul>
<li><strong>{ver}</strong> indicates the version of the API and allows changing
API syntax/behavior without breaking legacy clients (not
necessarily providing “new” functionality for them, however).
Usually version can be omitted, and it defaults to the latest
stable version of the API.</li>
<li><strong>{lang}</strong> in multilingual APIs, is a two-letter ISO
abbreviation for a language, e.g. “en” for English, “es” for
Spanish etc. Typically defaults to “en” for English, if ommited.</li>
<li><strong>{resource_type}</strong> is the name of the resource, e.g.: user,
story, cart, line item etc.</li>
<li><strong>{resource_id}</strong> is a unique identifier of the resource. Can
be numeric or alpha-numeric (e.g. in usernames). Often sequence
numbers of the internal database schemas are used as
identifiers, however usage of universally unique identifiers
(UUIDs) leads to better-designed APIs.</li>
<li><strong>{output_format}</strong> - commonly used to let API know which
format response is requested in: xml, html, json, bson, rss,
atom are some of the common formats implemented. Frequently
format can also be indicated using the HTTP Accept-headers.</li>
</ul>
</li>
<li>Resources in RESTful URLs are often chained. For instance, to access
an item in a user’s order the resource part of the URL may look
like: “user/2323/order/54234/line_item/73321”. Important thing to
remember about resource chaining is that it represents a hierarchy:
the line item belongs to the order and the order belongs to the
user.</li>
<li>Client-server interactions in REST are stateless: in that request
must always contain all of the information necessary to understand
the request and may not take advantage of the state stored on the
server.</li>
<li>REST encourages caching of requests that can be cached, to minimize
network bandwidth utilization. APIs should implicitly or explicitly
mark response to a request as cacheable or non-cacheable. If a
response is cacheable, then clients are encouraged to locally cache
it and reuse data for later, equivalent requests. HTTP headers are
typically used to label cacheable content and indicate the permitted
duration of cache.</li>
</ul>
<h2 id="idempotent-vs-non-idempotent-operations">Idempotent vs Non-idempotent Operations</h2>
<blockquote>
<p>Idempotence (pronounced: eye-dəm-poh-təns) is
the property of certain operations in mathematics and computer science,
that they can be applied multiple times without changing the result.</p>
<p>~ <a href="http://en.wikipedia.org/wiki/Idempotent">Wikipedia</a></p>
</blockquote>
<ul>
<li>
<p>A unary operation is idempotent if, whenever it is applied twice to
any value, it gives the same result as if it were applied once. For
example, the arithmetic absolute value function is idempotent:\</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>abs(abs (x)) = abs(x).
</code></pre></div> </div>
</li>
<li>
<p>A binary operation is idempotent if, whenever it is applied to two
values, it always gives the same value for those two as the result.
For example, the operation giving the minimum value of two values is
idempotent:\</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>min(a, b) = x
</code></pre></div> </div>
</li>
</ul>
<h2 id="api-operations-and-idempotence">API Operations and Idempotence</h2>
<p>Read/Write APIs commonly use following major HTTP Methods: GET, PUT,
DELETE and POST. Out of these HTTP methods, only GET is cacheable and
only POST is non-idempotent. Considering idempotence properties, entity
CRUD operations are matched to HTTP methods as follows:</p>
<ul>
<li>Create - is either HTTP POST or HTTP PUT:
<ul>
<li>HTTP POST is used for non-idempotent creation. This is when
entity identifier is not passed during creation but needs to be
generated by the back-end. For instance, news story creation
operations are non-idempotent. Entity identifier (primary key)
for the created entity is returned in the response, if entity
creation was successful. Since the operation is non-idempotent,
issuing it twice will create two similar entities.</li>
<li>HTTP PUT is used for idempotent creation. User creation is often
idempotent because client provides specific, unique entity
identifier (username) that the user must be created with.
Typically each entity type only supports either idempotent or
non-idempotent creation. Usually most content is non-idempotent
and is created with HTTP POST.</li>
</ul>
</li>
<li>Read - is HTTP GET. It is cacheable, and idempotent.</li>
<li>Update - is HTTP PUT. It’s idempotent, and entity identifier must be
supplied in the request.</li>
<li>Delete - is HTTP DELETE if it can be idempotent, which is the case
if content is only marked as “deleted” (delete == disable). Since
content is never really “deleted”, but just marked disabled or
inactive, you could keep “deleting” the same content and you keep
receiving HTTP 200 (idempotence in action), until the content is
actually removed from the database i.e. does not exist anymore (see
truncate operation).</li>
<li>Truncate* - is HTTP POST. It removes an item from the database /
deletes it permanently. It’s non-idempotent. If you attempt to
truncate an already truncated object, you will get HTTP 404 as a
response because the second time entity does not exist, anymore.</li>
</ul>
<h2 id="most-common-http-response-codes-used-in-restful-apis">Most Common HTTP Response Codes Used in RESTful APIs</h2>
<p>200 OK: Success!</p>
<p>201 Created: a common return code for a successful HTTP POST (or PUT in
idempotent creations)</p>
<p>202 Accepted: request was accepted, but has not fully been processed,
yet. A common code to return for asynchronous calls.</p>
<p>304 Not Modified: There was no new data to return (think: cache).</p>
<p>400 Bad Request: Invalid Request. Error message will be returned to
provide further details.</p>
<p>401 Unauthorized: Authentication credentials were missing or incorrect.</p>
<p>403 Forbidden: Valid request that was refused. Attempt to access a
resource that the client does not have permission to. Error message will
be returned to provide further details.</p>
<p>404 Not Found: The URL requested is invalid or the resource requested,
such as a story or a user, does not exists.</p>
<p>406 Not Acceptable: Returned when parameters passed are correct in
theory and individually, but when combined can not be satisfied because
the combination makes no sense (e.g. cart_id from one user is used with
a user_id from another user). If possible, an error message will be
returned to provide further details.</p>
<p>500 Internal Server Error: Something went horribly wrong and we were not
smart enough to provide more details :) Hopefully a very rare response
code.</p>
<p>503 Service Unavailable: Servers are offline for maintenance or went
down under load (oops).\</p>
<h2 id="tldr-summary">TL:DR; Summary</h2>
<p>REST is an architectural style. It is loosely defined and often
misinterpreted. While there is no official specification, a pragmatic
approach to implementing reasonably RESTful API is to follow the
fundamental principles as outlined in Fielding’s original work,
implemented in HTTP 1.1 and adopt best practices from the industry.</p>
<p>While this blog post is in no way a canonical specification for REST, it
emphasizes some of the major architectural principles behind REST:
resource-orientation, HTTP methods, statelessness, idempotent vs.
non-idempotent operations, Mime Types, versioning and standard response
codes.</p>
Recovering from: 'std::exception: old lock file, terminating' on a MongoDB server.
2011-05-31T00:00:00-04:00
http://www.freshblurbs.com/blog/2011/05/31/recovering-std-exception-old-lock-file-terminating-mongodb-server.html
<p>If a server running MongoDB crashed or MongoDB did not get to shut down
cleanly for some other reason, you may not be able to start Mongo again,
getting “exception in initAndListen std::exception: old lock file,
terminating” error in Mongo error log. Fix is actually pretty easy, you
just need to locate mongod.lock file and remove it. On a Debian server
installed from the mongodb-10gen repository it is usually located at:
/var/lib/mongodb/mongod.lock.</p>
<p>If it is not there in your installation, check the “dbpath”
configuration variable in mongodb.conf file (typically:
/etc/mongodb.conf). Lock file should be under the folder indicated by
dbpath.</p>
Install Rails 3, Ruby 1.9, NginX and MongoDB on Debian Lenny
2011-05-30T00:00:00-04:00
http://www.freshblurbs.com/blog/2011/05/30/install-rails-3-ruby-1-9-nginx-and-mongodb-debian-lenny.html
<p>Let’s start with setting up a developer account. Please note:
“:developername” should be replaced with whatever your unix user name
you want to be when developing (“irakli” in my case).</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ERROR: Loading command: install (LoadError)
no such file to load -- zlib
</code></pre></div></div>
<h3 id="install-latest-nginx-from-source">Install Latest Nginx From Source:</h3>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo apt-get install libc6 libpcre3 libpcre3-dev libpcrecpp0 libssl0.9.8 libssl-dev zlib1g zlib1g-dev lsb-base
$ cd /usr/local/src/
$ sudo wget http://nginx.org/download/nginx-1.0.5.tar.gz
$ sudo tar xzvf nginx-1.0.5.tar.gz
$ cd nginx-1.0.5
</code></pre></div></div>
<h3 id="install-passenger-for-nginx">Install Passenger for NginX:</h3>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo gem install passenger
$ sudo apt-get install libcurl4-openssl-dev
$ sudo passenger-install-nginx-module
</code></pre></div></div>
<p>Important: Please note that Nginx does not support dynamic modules.
Adding a module to Nginx means re-compiling it. passenger installer will
guide you through the steps to recompile. Please make sure you answer
the questions in a way similar to what’s shown below, otherwise your
NginX may not be re-compiled properly:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>> 2. No: I want to customize my Nginx installation. (for advanced users)
> Where is your Nginx source code located?
> Please specify the directory: /usr/local/src/nginx-1.0.5
> Where do you want to install Nginx to?
> Please specify a prefix directory [/opt/nginx]: /usr
> Extra arguments to pass to configure script: --with-http_ssl_module --without-mail_pop3_module --without-mail_imap_module --without-mail_smtp_module --with-http_stub_status_module --with-http_realip_module
</code></pre></div></div>
<h3 id="configure-nginx-with-a-sample-rails-app">Configure Nginx With A Sample Rails App</h3>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo ln -s /usr/conf/nginx.conf /etc/nginx.conf
$ sudo mkdir /var/www/rails.vm
$ sudo chgrp -R webmaster /var/www
$ sudo chmod -R 775 /var/www/
$ cd /var/www/rails.vm
$ rails new firstapp
</code></pre></div></div>
<p>Where “rails.vm” above (and below in the text) is the domain name of the
webapp you intend to build, replace it with your domain if needed. Edit
file: /etc/nginx.conf as root and insert the following lines at the end
of the “http” section (typically: before the very last closing curly
brace “}” in the file, unless Nginx changes the default config file):</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> include sites-enabled/*;
</code></pre></div></div>
<p>create “/usr/conf/sites-enabled” directory and
/usr/conf/sites-enabled/rails.vm configuration file with the following
content:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>server {
listen 80;
server_name ruby.sam.ge;
root /var/www/rails.vm/firstapp/public; # <--- be sure to add 'public' to the app path!
passenger_enabled on;
rails_env development;
gzip on;
gzip_comp_level 2;
gzip_proxied any;
gzip_min_length 1000;
gzip_disable "MSIE [1-6]\."
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
}
</code></pre></div></div>
<p>Start Nginx if it is stopped with:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo /usr/sbin/nginx
</code></pre></div></div>
<p>or if it is already running, reload configuration with:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo /usr/sbin/nginx -s reload
</code></pre></div></div>
<p>you can stop nginx at any point with:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo /usr/sbin/nginx -s stop
</code></pre></div></div>
<p>Once Nginx is running, and if you have rails.vm domain (or whatever
domain you ended up configuring in Nginx) properly pointed to the
server’s IP, if you go to that domain in your browser, you should see a
test Rails page that comes from your sample app. At this point Rails app
is properly set up and configured in Nginx.</p>
<h3 id="install-mongodb">Install MongoDB</h3>
<p>Import GPG Key:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo apt-key adv --keyserver keyserver.ubuntu.com --recv 7F0CEB10
</code></pre></div></div>
<p>add this line to your /etc/apt/sources.list</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>deb http://downloads-distro.mongodb.org/repo/debian-sysvinit dist 10gen
</code></pre></div></div>
<p>and run:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo apt-get update
$ sudo apt-get install mongodb-10gen
$ sudo gem install mongo bson bson_ext
</code></pre></div></div>
<p>For further documentation about Rails3 and Mongo you should take a look
at the following two links:</p>
<ul>
<li><a href="http://www.mongodb.org/display/DOCS/Rails+3+-+Getting+Started#Rails3-GettingStarted-Configureyourapplication">MongoDB: Rails 3 - Getting
Started</a></li>
<li><a href="https://github.com/banker/mongodb-rails3-sample">MongoDB Rail3
Skeleton</a></li>
</ul>
<h3 id="install-mysql-51-optional">Install MySQL 5.1 (Optional)</h3>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo su -
# echo "deb http://packages.dotdeb.org oldstable all" >> /etc/apt/sources.list
# echo "deb-src http://packages.dotdeb.org oldstable all" >> /etc/apt/sources.list
# echo "deb http://php53.dotdeb.org oldstable all" >> /etc/apt/sources.list
# echo "deb-src http://php53.dotdeb.org oldstable all" >> /etc/apt/sources.list
# cd /usr/local/src
# wget http://www.dotdeb.org/dotdeb.gpg
# cat dotdeb.gpg | sudo apt-key add -
# apt-get update
# exit
$ sudo apt-get install mysql-server-core-5.1 mysql-source-5.1 mysql-server-5.1 mysql-client-5.1
$ sudo apt-get install libmysqlclient15-dev libmysql-ruby
$ sudo gem install mysql
</code></pre></div></div>
<h3 id="bonus-sinatra-sample-app">Bonus: Sinatra Sample App</h3>
<p>This is a bonus section with quick example of how to use
already-installed Nginx and Phusion with Rails stack to run a Sinatra
sample app (e.g. to augment your Rails app with more light-weight REST
API component on top of Sinatra). You will need a separate nginx
configuration file that looks something like:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>server {
listen 80;
server_name sinatra.vm;
root /var/www/sinatra.vm/code/public;
passenger_enabled on;
gzip on;
}
</code></pre></div></div>
<p>Under /var/www/sinatra.vm/code you need following files:</p>
<p>Gemfile:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>source 'http://rubygems.org'
gem 'sinatra', '1.2.6'
</code></pre></div></div>
<p>config.ru:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>require 'rubygems'
require 'sinatra'
set :env, :development
disable :run
require File.expand_path('../app', __FILE__) # Name "app" corresponds to app.rb file.
run MyApi::ApplicationClass
</code></pre></div></div>
<p>app.rb:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>require 'sinatra'
module MyApi
class ApplicationClass < Sinatra::Base
get '/' do
'Default Response from API'
end
end
end
</code></pre></div></div>
<p>Once you have these files run following commands under
/var/www/sinatra.vm/code</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ mkdir public
$ bundle install
$ sudo /usr/sbin/nginx -s reload
</code></pre></div></div>
<h3 id="code-reloading">Code Reloading</h3>
<p>Phussion Passenger caches code to improve performance. This can become
counter-productive in a development environment where you are changing
code all the time since you may end-up having to issue “sudo
/usr/sbin/nginx -s reload” every time you change your code. There’re
several remedies:</p>
<p>For Rails you can just set: “RailsEnv development “ or “RakeEnv
development” in the Nginx configuration and code will be reloaded at
every request.</p>
<p>For Sinatra, you have two choices, either create “tmp/restart.txt” under
the root of your code tree and issue “touch tmp/restart.txt” every time
you need code reloaded instead of reloading entire Nginx (still pretty
annoying, imho) or create “tmp/always_restart.txt” in which case cache
will be reloaded at every http request.</p>
Building Latest Git On Debian Lenny
2011-05-23T00:00:00-04:00
http://www.freshblurbs.com/blog/2011/05/23/building-latest-git-debian-lenny.html
<p>Debian Lenny only provides Git 1.5.x out of the box, which is a pretty
old git version. Following simple steps show how to update/build git
from source:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo apt-get install tcl
$ sudo apt-get install tk
$ sudo apt-get install python-software-properties
$ sudo apt-get install zlib1g-dev
$ sudo apt-get install build-essential autoconf
$ cd /usr/local/src
$ sudo wget http://kernel.org/pub/software/scm/git/git-1.7.5.2.tar.bz2
$ # or download one from: https://github.com/github/git if kernel.org is down (has happened before)
$ sudo bunzip2 git-1.7.5.2.tar.bz2
$ sudo tar xvf git-1.7.5.2.tar
$ cd git-1.7.5.2
$ make configure
$ sudo ./configure
$ sudo make && sudo make install
</code></pre></div></div>
<p>Make sure “/usr/local/bin” is in your PATH</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ git --version
</code></pre></div></div>
Install PHP 5.3, Nginx And PHP-fpm On Debian Lenny
2011-05-15T00:00:00-04:00
http://www.freshblurbs.com/blog/2011/05/15/install-php-5-3-nginx-and-php-fpm-debian-lenny.html
<p>We start by installing <a href="http://dotdeb.org">dotdeb</a> APT repository to get
easy access to the latest .deb packages for some of our components like
NginX, PHP stack etc.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo su -
# echo "deb http://packages.dotdeb.org stable all" >> /etc/apt/sources.list
# echo "deb-src http://packages.dotdeb.org stable all" >> /etc/apt/sources.list
# echo "deb http://php53.dotdeb.org stable all" >> /etc/apt/sources.list
# echo "deb-src http://php53.dotdeb.org stable all" >> /etc/apt/sources.list
# cd /usr/local/src
# wget http://www.dotdeb.org/dotdeb.gpg
# cat dotdeb.gpg | sudo apt-key add -
# apt-get update
# apt-get upgrade
</code></pre></div></div>
<p>Now before we proceed any further, let’s make sure we have improved vi,
because we will be editing whole bunch of files and default Debian
installation only comes with classic vi, which does not understand arrow
keys in editor mode (and that personally bugs me a lot):</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo apt-get install vim
</code></pre></div></div>
<h3 id="install-nginx-and-php-53-with-php-fpm">Install Nginx and PHP 5.3 with PHP-FPM</h3>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo apt-get install nginx
$ sudo apt-get install php5-cli php5-common php5-suhosin
$ sudo apt-get install php5-fpm php5-cgi php5-apc
</code></pre></div></div>
<p>Let’s also install xdebug via pecl (we could install Xdebug through apt,
too, but it misconfigures xdebug after install and it’s a good thing to
have properly configured PECL on LAMP stack, anyway):</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo apt-get install php-pear
$ sudo apt-get install build-essential
$ sudo apt-get install php5-dev
$ sudo pecl install xdebug
</code></pre></div></div>
<p><strong>CAUTION:</strong> If you run into problems with installing php5-dev (e.g. an
error complaining about libtools version, which is expected if you run
these instructions on Debian newer than Lenny, e.g. Squeeze) you may
need to download appropriate .deb packages manually from:
<a href="http://mirrors.kernel.org/ubuntu/pool/main/p/php5/">http://mirrors.kernel.org/ubuntu/pool/main/p/php5/</a>
and install with: “dpkg -i packagename.deb”. Please make sure to pick
the correct .deb file for your CPU architecture and the version that you
need.</p>
<p>Please note an output at the end of the xdebug installation which looks
something like:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Build process completed successfully
Installing '/usr/lib/php5/20090626+lfs/xdebug.so'
</code></pre></div></div>
<p>You need the path after “installing” because we will have to create
xdebug configuration file with that path. You php configuration files
should be in “/etc/php5/conf.d/”. If that is true, please create
/etc/php5/conf.d/xdebug.ini (or create xdebug.ini under wherever your
php configuration files directory is) and insert following line there:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>; Enable xdebug
zend_extension="/usr/lib/php5/20090626+lfs/xdebug.so"
</code></pre></div></div>
<p>noting that the path provided to zend_extension instruction is the same
one we got from the xdebug pecl installation output.</p>
<h3 id="configure-nginx">Configure Nginx</h3>
<p>Following instructions assume that you are configuring a domain:
debian.vm</p>
<p>create /var/www/debian.vm/html and make it readable by Nginx user (which
is probably: “www-data”)<br />
create /var/www/debian.vm/logs and make it writable by Nginx user
(which is probably: “www-data”)</p>
<p>Edit: /etc/nginx/sites-available/debian.vm.conf as root and enter
following configuration:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>server {
listen 80;
server_name debian.vm;
root /var/www/debian.vm/html/;
access_log /var/www/debian.vm/logs/web.access.log;
error_log /var/www/debian.vm/logs/web.error.log;
# root location
location / {
index index.html index.htm index.php;
}
# static content
location ~* ^.+\.(wsf|xml|pdf|doc|jpg|jpeg|gif|css|png|js|ico|ttf|eot|otf|svg)$ {
# access_log off;
expires 15d;
}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
location ~ /\.ht {
deny all;
}
# php file handling
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param SERVER_NAME $http_host;
fastcgi_ignore_client_abort on;
}
gzip on;
gzip_comp_level 2;
gzip_proxied any;
gzip_min_length 1000;
gzip_disable "MSIE [1-6]\."
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
}
</code></pre></div></div>
<p><strong>Note:</strong> if you are setting up virtualhost for Drupal, your
configuration needs to be more involved and may look something like the
following:
<a href="https://gist.github.com/1593835">https://gist.github.com/1593835</a></p>
<p>Now let’s link this configuration from sites-enabled foder to enable it:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo ln -s /etc/nginx/sites-available/debian.vm.conf /etc/nginx/sites-enabled/debian.vm.conf
$ sudo mv /etc/nginx/sites-enabled/default /etc/nginx/sites-enabled/00_default
</code></pre></div></div>
<p>Check the resulting Nginx configuration with:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo /usr/sbin/nginx -t
</code></pre></div></div>
<h3 id="test-page">Test Page</h3>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo mkdir -p /var/www/debian.vm/html
$ sudo chown -R $USER:$GROUP /var/www/debian.vm
$ sudo chmod -R 775 /var/www/debian.vm
$ echo "<?php phpinfo(); " > /var/www/debian.vm/html/index.php
$ sudo /etc/init.d/php5-fpm restart
$ sudo /etc/init.d/nginx restart
</code></pre></div></div>
<p>After which if the domain you configured is indeed debian.vm and it i
pointing to your server (even via hosts file record), when visiting
http://debian.vm/ via your browser you should see the PHP Info page
generated by phpinfo() in your index.php. Please note that our nginx
configuration will also cache static content for 15 days, improving
performance.</p>
<h3 id="bonus-mysql">Bonus: MySQL</h3>
<p>Note: this assumes you have already set up dotdeb repositories properly
(beginning of this post).</p>
<p>If you need to install MySQL for PHP, as well:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo apt-get install mysql-common
$ sudo apt-get install mysql-client-5.1
$ sudo apt-get install mysql-server-5.1
$ sudo apt-get install php5-mysql
</code></pre></div></div>
<h3 id="bonus-changing-hostname">Bonus: Changing hostname</h3>
<p>If you want to permanently change the hostname of your server (so that
it survives reboot) you need to follow following steps:</p>
<ul>
<li>Let’s assume you are changing your server hostname to ika.ge</li>
<li>
<p>Edit /etc/hosts as a root and next to “localhost” add “ika.ge” so
corresponding line reads something like:\</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>127.0.0.1 localhost ika.ge
</code></pre></div> </div>
</li>
<li>Edit “/etc/hostname” and replace existing line there with “ika.ge”</li>
<li>
<p>run:\</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> sudo /etc/init.d/hostname.sh start
</code></pre></div> </div>
</li>
</ul>
Install Node.js and Express.js with Nginx on Debian Lenny
2011-05-07T00:00:00-04:00
http://www.freshblurbs.com/blog/2011/05/07/install-node-js-and-express-js-nginx-debian-lenny.html
<p>Following instructions were tested on a RackSpace Cloud Server. It
should work for any other reasonably configured, mostly bare-bones
Debian Lenny and latest Ubuntu (e.g. on other popular hosting options
like: SliceHost, Linode etc.). First, let’s install some essentials:</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">$</span><span class="w"> </span><span class="nb">sudo </span>apt-get update
<span class="gp">$</span><span class="w"> </span><span class="nb">sudo </span>apt-get upgrade
<span class="gp">$</span><span class="w"> </span><span class="nb">sudo </span>apt-get <span class="nb">install </span>build-essential
<span class="gp">$</span><span class="w"> </span>gcc <span class="nt">-v</span>
<span class="gp">$</span><span class="w"> </span>make <span class="nt">-v</span>
<span class="go">
</span><span class="gp">$</span><span class="w"> </span><span class="nb">sudo </span>apt-get <span class="nb">install </span>python-software-properties
<span class="gp">$</span><span class="w"> </span><span class="nb">sudo </span>apt-get <span class="nb">install </span>libssl-dev libreadline-dev
<span class="gp">$</span><span class="w"> </span><span class="nb">sudo </span>apt-get <span class="nb">install </span>git-core curl
</code></pre></div></div>
<p>Now we can proceed with Node.js installation. There are two ways to
install Node.js, directly (not recommended due to maintenance cost) or
with a version manager like <a href="https://github.com/creationix/nvm">nvm</a>
(highly recommended in most cases):</p>
<h3 id="method-1-installing-nodejs-with-nvm">Method 1: Installing Node.js with NVM</h3>
<p>Attention: this is the recommended way.</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">$</span><span class="w"> </span>git clone git://github.com/creationix/nvm.git ~/.nvm
<span class="gp">$</span><span class="w"> </span><span class="nb">.</span> ~/.nvm/nvm.sh
<span class="gp">$</span><span class="w"> </span>nvm <span class="nb">ls</span>
<span class="gp">$</span><span class="w"> </span>nvm <span class="nb">install </span>v0.8.12
<span class="gp">$</span><span class="w"> </span>nvm <span class="nb">alias </span>default v0.8.12
<span class="gp">$</span><span class="w"> </span>nvm <span class="nb">ls</span>
<span class="gp">$</span><span class="w"> </span>nvm <span class="nb">help</span>
</code></pre></div></div>
<p>Please make sure to add following line to your (and by “your” we mean
the user which node apps will be executed as) ~/.bashrc or ~/.profile:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">.</span> ~/.nvm/nvm.sh
</code></pre></div></div>
<p>You may want to log out and log back in, to test that login scripts
work.</p>
<h3 id="method-2-compiling-nodejs-from-sources-yourself">Method 2: Compiling Node.js from sources yourself</h3>
<p>Attention: this is NOT recommended. You should use NVM or Nave instead.</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">$</span><span class="w"> </span><span class="nb">cd</span> /usr/local/src/
<span class="gp">$</span><span class="w"> </span><span class="nb">sudo </span>wget http://nodejs.org/dist/node-v0.8.12.tar.gz
<span class="gp">$</span><span class="w"> </span><span class="nb">sudo tar </span>xzvf node-v0.8.12.tar.gz
<span class="gp">$</span><span class="w"> </span><span class="nb">cd </span>node-v0.8.12
<span class="gp">$</span><span class="w"> </span><span class="nb">sudo</span> ./configure
<span class="gp">$</span><span class="w"> </span><span class="nb">sudo </span>make
<span class="gp">$</span><span class="w"> </span><span class="nb">sudo </span>make <span class="nb">install</span>
<span class="gp">$</span><span class="w"> </span>whereis node
<span class="gp">$</span><span class="w"> </span>node <span class="nt">-v</span>
</code></pre></div></div>
<h4 id="installing-npm-package-manager">Installing NPM Package Manager</h4>
<p>You do not need this if you installed Node using NVM, because NVM
installs NPM as well. Let’s install Node’s package manager (make sure
your non-root user is also part of the “webmaster” group)::</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ cd
$ curl http://npmjs.org/install.sh | sh
$ which npm
</code></pre></div></div>
<p>Next, you can run “npm search” (takes a while) to see the abundance of
Node.js packages available or “npm ls” to see packages already
installed.</p>
<h4 id="another-node-version-manager-nave">Another Node Version Manager: Nave</h4>
<p><a href="https://github.com/isaacs/nave">Nave</a> is different from NVM in that it
does not require sourcing a shells script. Comparing Nave and NVM,
Nave’s author wrote: “Nvm is also really nice, but has to be sourced
rather than being run, and thus is a little bit wonky for some use
cases. But it doesn’t involve subshells, which makes it better for many
others.” I think they are both pretty great, so it’s a matter of taste,
maybe. Nave allows us to run multiple versions of node in parallel and
switch between them, similar to how rvm and virtualenv do it for Ruby
and Python respectively:</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">$</span><span class="w"> </span><span class="nb">cd</span> /usr/local/src/npm/
<span class="gp">$</span><span class="w"> </span><span class="nb">sudo </span>npm <span class="nb">install</span> <span class="nt">-g</span> nave
<span class="gp">$</span><span class="w"> </span>nave <span class="nt">-v</span>
</code></pre></div></div>
<h2 id="first-express-app">First Express App</h2>
<p>Let’s create our first Express app now</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">$</span><span class="w"> </span><span class="nb">sudo mkdir</span> /opt/apps
<span class="gp">$</span><span class="w"> </span><span class="nb">sudo chmod</span> <span class="nt">-R</span> 775 /opt/apps/
<span class="gp">$</span><span class="w"> </span><span class="nb">sudo chown</span> <span class="k">${</span><span class="nv">USER</span><span class="k">}</span>:webmaster <span class="nt">-R</span> /opt/apps/
<span class="gp">$</span><span class="w"> </span><span class="nb">mkdir</span> /opt/apps/firstapp
</code></pre></div></div>
<p>Let’s install <a href="http://expressjs.com/">Express.js</a> web framework for
Node.js under our project:</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">$</span><span class="w"> </span><span class="nb">cd</span> /opt/apps/firstapp
<span class="gp">$</span><span class="w"> </span>npm <span class="nb">install </span>express
</code></pre></div></div>
<p>create /opt/apps/firstapp/app.js with the following source code:</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/* Module dependencies. */</span>
<span class="kd">var</span> <span class="nx">express</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">express</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">app</span> <span class="o">=</span> <span class="nx">express</span><span class="p">.</span><span class="nx">createServer</span><span class="p">();</span>
<span class="nx">app</span><span class="p">.</span><span class="kd">get</span><span class="p">(</span><span class="dl">'</span><span class="s1">/</span><span class="dl">'</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">){</span>
<span class="nx">res</span><span class="p">.</span><span class="nx">send</span><span class="p">(</span><span class="dl">'</span><span class="s1">Hello World</span><span class="dl">'</span><span class="p">);</span>
<span class="p">});</span>
<span class="nx">app</span><span class="p">.</span><span class="nx">listen</span><span class="p">(</span><span class="mi">3000</span><span class="p">);</span>
</code></pre></div></div>
<p>and save. You can start your Node/Express.js app from shell with:</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">$</span><span class="w"> </span>node /opt/apps/firstapp/app.js
</code></pre></div></div>
<p>After which, if you go to http://yourdomain.com:3000/ you should see a
nice “Hello World” message. Voila! We made our first Node.js app! Of
course, in the real world you will probably want to put a web-server in
front of the node.js app. If for no other reason: to serve static
content faster and to securely attach to port 80. Since the big deal
with node.js is its non-blocking architecture, it makes sense to
front-end it with a non-blocking web-server as well. Let’s see how we
can route our node.js app through Nginx.</p>
<h3 id="installing-nginx">Installing Nginx</h3>
<p>Disclaimer: instructions adapted from a <a href="http://articles.slicehost.com/2009/7/29/debian-lenny-installing-nginx-from-source">SliceHost
Tutorial</a></p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">$</span><span class="w"> </span><span class="nb">sudo </span>apt-get <span class="nb">install </span>build-essential
<span class="gp">$</span><span class="w"> </span><span class="nb">sudo </span>apt-get <span class="nb">install </span>libc6 libpcre3 libpcre3-dev libpcrecpp0 libssl0.9.8 libssl-dev zlib1g zlib1g-dev lsb-base
<span class="gp">$</span><span class="w"> </span><span class="nb">cd</span> /usr/local/src
<span class="gp">$</span><span class="w"> </span><span class="nb">cd</span> /usr/local/src/
<span class="gp">$</span><span class="w"> </span><span class="nb">sudo </span>wget http://nginx.org/download/nginx-1.3.7.tar.gz
<span class="gp">$</span><span class="w"> </span><span class="nb">sudo tar </span>xzvf nginx-1.3.7.tar.gz
<span class="gp">$</span><span class="w"> </span><span class="nb">cd </span>nginx-1.3.7
<span class="gp">$</span><span class="w"> </span><span class="nb">sudo</span> ./configure <span class="nt">--sbin-path</span><span class="o">=</span>/usr/local/sbin <span class="nt">--with-http_ssl_module</span>
<span class="gp">$</span><span class="w"> </span><span class="nb">sudo </span>make <span class="o">&&</span> <span class="nb">sudo </span>make <span class="nb">install</span>
<span class="gp">$</span><span class="w"> </span><span class="nb">sudo ln</span> <span class="nt">-s</span> /usr/local/nginx/conf /etc/nginx
</code></pre></div></div>
<h3 id="configure-nginx">Configure Nginx</h3>
<p>Edit file: /etc/nginx/nginx.conf and insert the following line at the
end of the “http” section (typically: before the very last closing curly
brace “}” in the file, unless Nginx changes the default config file):</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>include sites-enabled/<span class="k">*</span><span class="p">;</span>
</code></pre></div></div>
<p>Create folder <code class="language-plaintext highlighter-rouge">/etc/nginx/sites-enabled/</code> and edit
<code class="language-plaintext highlighter-rouge">/etc/nginx/sites-enabled/firstapp.conf</code> file with content similar to:</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="go">server {
</span><span class="gp"> listen 80;</span><span class="w">
</span><span class="gp"> server_name yourdomain.com;</span><span class="w">
</span><span class="go">
</span><span class="gp"> #</span><span class="w"> </span>Let<span class="s1">'s put all static files like images, js and css in sub-folder: public
</span><span class="gp"> root /opt/apps/firstapp/public;</span><span class="w">
</span><span class="go">
</span><span class="gp"> #</span><span class="w"> </span>static content
<span class="gp"> location ~* ^.+.(jpg|jpeg|gif|css|png|js|ico|xml)$</span><span class="w"> </span><span class="o">{</span>
<span class="gp"> #</span><span class="w"> </span>access_log off<span class="p">;</span>
<span class="gp"> expires 15d;</span><span class="w">
</span><span class="go"> }
location / {
</span><span class="gp"> proxy_pass http://127.0.0.1:3000;</span><span class="w">
</span><span class="gp"> proxy_set_header X-Real-IP $</span>remote_addr<span class="p">;</span>
<span class="gp"> proxy_set_header X-Forwarded-For $</span>proxy_add_x_forwarded_for<span class="p">;</span>
<span class="gp"> proxy_set_header Host $</span>http_host<span class="p">;</span>
<span class="gp"> proxy_set_header X-NginX-Proxy true;</span><span class="w">
</span><span class="gp"> proxy_redirect off;</span><span class="w">
</span><span class="go"> }
</span><span class="gp"> gzip on;</span><span class="w">
</span><span class="gp"> gzip_comp_level 2;</span><span class="w">
</span><span class="gp"> gzip_proxied any;</span><span class="w">
</span><span class="gp"> gzip_min_length 1000;</span><span class="w">
</span><span class="go"> gzip_disable "MSIE [1-6]\."
</span><span class="gp"> gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;</span><span class="w">
</span><span class="go">}
</span></code></pre></div></div>
<p><strong>Attention</strong>: If you use some CSS shorthand frameworks, as <a href="/install-node-js-and-express-js-nginx-debian-lenny#comment-1369">Will
explains in his
comment</a>
you will want to remove css files from the list of static content that
you’d like NginX to handle for you. You can start nginx with:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo /usr/local/sbin/nginx
</code></pre></div></div>
<p>If you later need to edit Nginx configuration and reload it you can run:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ /usr/local/sbin/nginx -s reload
</code></pre></div></div>
<p>You can test Nginx configuration for errors with:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo /usr/local/sbin/nginx -t
</code></pre></div></div>
<p>Once Nginx is properly configured, you should be able to see the same
express.js response page with http://yourdomain.com (without the port
3000 and assuming that you are still running the node.js application).
At that point request is routed through Nginx and we have also added
instructions to serve static content (images, css, javascript etc.)
directly from Nginx (subfolder “public”), bypassing Node.js</p>
<h3 id="bundling-dependencies">Bundling Dependencies</h3>
<p>Instead of manually installing required modules, you can define
dependencies of your app declaratively and let npm manage it for you. If
you are familiar with Ruby On Rails, this is a process similar to using
Gemfiles and Bundler. First, you need to create a package.json in the
same folder where your app.js lives:</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span>
<span class="dl">"</span><span class="s2">author</span><span class="dl">"</span><span class="p">:</span> <span class="dl">"</span><span class="s2">Node Noob</span><span class="dl">"</span>
<span class="p">,</span> <span class="dl">"</span><span class="s2">dependencies</span><span class="dl">"</span><span class="p">:</span> <span class="p">{</span>
<span class="dl">"</span><span class="s2">express</span><span class="dl">"</span><span class="p">:</span> <span class="dl">"</span><span class="s2">>= 2.4</span><span class="dl">"</span>
<span class="p">,</span> <span class="dl">"</span><span class="s2">expresso</span><span class="dl">"</span><span class="p">:</span> <span class="dl">""</span>
<span class="p">,</span> <span class="dl">"</span><span class="s2">jade</span><span class="dl">"</span><span class="p">:</span> <span class="dl">"</span><span class="s2">0.15.13</span><span class="dl">"</span>
<span class="p">,</span> <span class="dl">"</span><span class="s2">should</span><span class="dl">"</span><span class="p">:</span> <span class="dl">""</span>
<span class="p">}</span>
<span class="p">,</span> <span class="dl">"</span><span class="s2">description</span><span class="dl">"</span><span class="p">:</span> <span class="dl">"</span><span class="s2">First Steps With Node.js</span><span class="dl">"</span>
<span class="p">,</span> <span class="dl">"</span><span class="s2">main</span><span class="dl">"</span><span class="p">:</span> <span class="dl">"</span><span class="s2">./app.js</span><span class="dl">"</span>
<span class="p">,</span> <span class="dl">"</span><span class="s2">name</span><span class="dl">"</span><span class="p">:</span> <span class="dl">"</span><span class="s2">app</span><span class="dl">"</span>
<span class="p">,</span> <span class="dl">"</span><span class="s2">version</span><span class="dl">"</span><span class="p">:</span> <span class="dl">"</span><span class="s2">1.0</span><span class="dl">"</span>
<span class="p">}</span>
</code></pre></div></div>
<p>after which you can run either:</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">$</span><span class="w"> </span>npm bundle
</code></pre></div></div>
<p>or in newer versions of
npm, just:</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">$</span><span class="w"> </span>npm <span class="nb">install</span>
</code></pre></div></div>
<p>to get all the required dependencies installed. see: <code class="language-plaintext highlighter-rouge">$npm help json</code> for more details about the format of
the package file.</p>
<h3 id="startup-and-management">Startup and Management</h3>
<p>One last step is to create and configure Nginx startup scripts, so that
if the server restarts, Nginx comes back up automatically. Slicehost has
a great article for the detailed steps of achieving just that, so you
should refer to it:
<a href="http://articles.slicehost.com/2009/8/3/debian-lenny-adding-an-nginx-init-script">http://articles.slicehost.com/2009/8/3/debian-lenny-adding-an-nginx-init-script</a>
For daemonizing Node process itself, you may want to review this code
snippet:
<a href="https://gist.github.com/1045395">https://gist.github.com/1045395</a>, but
you are probably much better off using Upstart (especially on Debian
Squeeze which comes pre-installed with one). For more information read
Tim Smart’s blog post:
<a href="http://howtonode.org/deploying-node-upstart-monit">http://howtonode.org/deploying-node-upstart-monit</a></p>
<h3 id="multi-process-nodejs">Multi-Process Node.js</h3>
<p>Node.js is a single-threaded system. Yes, you heard it right. There is
only one thread. Due to its event-loop-based asynchronous and
non-blocking nature it scales great even as a single thread, but if you
are running on a multi-core CPU you should want to start multiple
Node.js processes so you can leverage available cores. To utilize
multiple Node processes you should use Clustering, which is now part of
Node.js core.</p>
<h3 id="next-steps">Next Steps</h3>
<p>To understand clustering, hot reloading and take a look at a sample
Node/Express.js project, dive into the code of
<a href="http://nodebootstrap.com">NodeBootstrap</a> on Github.</p>
Developer's Ultimate Bash Prompt
2011-03-25T00:00:00-04:00
http://www.freshblurbs.com/blog/2011/03/25/developers-ultimate-bash-prompt.html
<p>Default bash prompt is limited. Good news is that it’s highly
customizable. Personally I have two requirements to bash prompt:</p>
<ul>
<li>I want two levels of folder hierarchy displayed (one is too
confusing, full path is too long)</li>
<li>I use Git for all my code (when I have it my way), so I want to see
git repo of the current folder, and whether anything is uncommitted, in
prompt.</li>
</ul>
<p>To achieve these, first you need to copy couple of scripts from Git source to
your home. Here’s how you do it:</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="go">git clone --depth 1 https://github.com/git/git
cp git/contrib/completion/git-completion.bash ~/git-completion.sh
cp git/contrib/completion/git-prompt.sh ~/git-prompt.sh
rm -rf git
</span></code></pre></div></div>
<p>after which you can paste following code in your <code class="language-plaintext highlighter-rouge">.bash_profile</code>:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">source</span> <span class="nv">$HOME</span>/git-prompt.sh
<span class="nb">export </span><span class="nv">GIT_PS1_SHOWDIRTYSTATE</span><span class="o">=</span><span class="nb">true
</span><span class="nv">txtylw</span><span class="o">=</span><span class="s1">'\033[1;33m'</span> <span class="c"># Yellow</span>
<span class="nv">txtwht</span><span class="o">=</span><span class="s1">'\e[0;37m'</span> <span class="c"># White</span>
<span class="nv">fgcolor</span><span class="o">=</span><span class="s2">"</span><span class="se">\0</span><span class="s2">33[0m"</span> <span class="c"># unsets color to term's fg color</span>
<span class="nv">twolevelprompt</span><span class="o">=</span><span class="s1">'$([ "$PWD" != "${PWD%/*/*/*}" ] && echo "/...${PWD##${PWD%/*/*}}" || echo "$PWD")'</span>
<span class="nv">gitprompt</span><span class="o">=</span><span class="s1">'$(__git_ps1 "(%s)")'</span>
<span class="nv">arrow</span><span class="o">=</span><span class="s1">$'</span><span class="se">\x</span><span class="s1">e2</span><span class="se">\x</span><span class="s1">86</span><span class="se">\x</span><span class="s1">92'</span>
<span class="nb">export </span><span class="nv">PS1</span><span class="o">=</span><span class="s2">"</span><span class="nv">$USER</span><span class="s2"> - </span><span class="se">\[</span><span class="nv">$txtwht</span><span class="se">\]</span><span class="nv">$twolevelprompt</span><span class="se">\[</span><span class="nv">$fgcolor</span><span class="se">\]</span><span class="nv">$gitprompt</span><span class="se">\[</span><span class="nv">$txtylw</span><span class="se">\]</span><span class="s2"> </span><span class="nv">$arrow</span><span class="s2"> </span><span class="se">\[</span><span class="nv">$fgcolor</span><span class="se">\]</span><span class="s2">"</span>
<span class="c"># This one isn't required for bash prompt and is a small bonus </span>
<span class="c"># which gives you git-specific auto-completion. Sometimes this can slow </span>
<span class="c"># things down. Feel free to disable it if you are experiencing latency.</span>
<span class="nb">source</span> <span class="nv">$HOME</span>/git-completion.sh
</code></pre></div></div>
<p>or, if you like having your path and prompt on separate lines, replace corresponding line
in the configuration with the following:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">txtcyn</span><span class="o">=</span><span class="s1">'\e[0;36m'</span> <span class="c"># Cyan</span>
<span class="nb">export </span><span class="nv">PS1</span><span class="o">=</span><span class="s2">"</span><span class="se">\[</span><span class="nv">$txtcyn</span><span class="se">\]</span><span class="nv">$USER</span><span class="s2">@</span><span class="nv">$HOSTNAME</span><span class="s2"> - </span><span class="nv">$twolevelprompt</span><span class="se">\[</span><span class="nv">$fgcolor</span><span class="se">\]</span><span class="nv">$gitprompt</span><span class="se">\[</span><span class="nv">$txtylw</span><span class="se">\]</span><span class="s2"> </span><span class="se">\n</span><span class="nv">$arrow</span><span class="s2"> </span><span class="se">\[</span><span class="nv">$fgcolor</span><span class="se">\]</span><span class="s2">"</span>
</code></pre></div></div>
<p>Lastly, as a bonus, I recommend setting up following colors for your terminal:</p>
<ul>
<li>Background: #4B4498 with 45% transparency</li>
<li>Foreground: #B7FEDD</li>
</ul>
Installing APC on Mac OS-X PHP
2011-03-15T00:00:00-04:00
http://www.freshblurbs.com/blog/2011/03/15/installing-apc-mac-os-x-php.html
<p>*Update*:</p>
<p>Brew packages have changes so new way of getting things done:\</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>> brew tap josegonzalez/homebrew-php
> brew install php53 --with-mysql --with-fpm
> brew install php53-apc
</code></pre></div></div>
<p>*Older instructions*:</p>
<p>I am not a fan of MAMP, XAMPP or other pre-packaged Apache/PHP
distributions, in general. Ever since OS-X started moving towards being
POSIX-compliant operating system and equally importantly HomeBrew
recipes started providing easy installation of required linux packages,
I try to stay away from MAMP & Co. Additionally, OS-X comes with
pre-install PHP/Apache (and adding MySQL is very easy with HomeBrew) so
installing a parallel Apache/MySQL/PHP stack feels dirty.</p>
<p>One big problem: there’s no APC with the pre-installed Mac PHP, which
can make large PHP projects very slow.</p>
<p>Thankfully it’s easy to fix, once you already have HomeBrew:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo pear update-channels
$ brew install pcre
$ sudo pecl install apc
</code></pre></div></div>
Installing Rails 3 with JRuby on CentOS Linux
2011-02-06T00:00:00-05:00
http://www.freshblurbs.com/blog/2011/02/06/installing-rails-3-jruby-centos-linux.html
<p>There are many benefits of using JRuby with Rails, among others: great
thread-support via JVM, easy integration with the vast amount of
functionality provided by existing Java libraries, streamlined database
access and deployment. We have blogged about <a href="http://freshblurbs.com/installing-ruby-rails-3-centos-nginx">installing latest Rails
with native
Ruby</a> and
NginX. In the following blog post we will go through the steps needed to
install and configure Rails using JRuby instead.</p>
<p>Make sure you have epel Yum repo installed, if you don’t:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo rpm -Uvh http://download.fedora.redhat.com/pub/epel/5/x86_64/epel-release-5-4.noarch.rpm
$ sudo rpm -Uvh http://download.elff.bravenet.com/5/x86_64/elff-release-5-3.noarch.rpm
</code></pre></div></div>
<p>Please note that the above instructions are for a 64-bit architecture,
on a 32-bit architecture:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo rpm -Uvh http://download.fedora.redhat.com/pub/epel/5/i386/epel-release-5-4.noarch.rpm
$ sudo rpm -Uvh http://download.elff.bravenet.com/5/i386/elff-release-5-3.noarch.rpm
</code></pre></div></div>
<p>Make sure you have working version of JDK 6 (including the compiler), if
not install it by running:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo yum install java-1.6.0-openjdk-devel
</code></pre></div></div>
<p>Check that installation was successful:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ java -version
java version "1.6.0_17"
OpenJDK Runtime Environment (IcedTea6 1.7.5) (rhel-1.16.b17.el5-x86_64)
OpenJDK 64-Bit Server VM (build 14.0-b16, mixed mode)
</code></pre></div></div>
<p>Proceed with the installation of JRuby:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ cd /opt/
$ wget http://jruby.org.s3.amazonaws.com/downloads/1.6.0.RC1/jruby-bin-1.6.0.RC1.tar.gz
$ sudo wget http://jruby.org.s3.amazonaws.com/downloads/1.6.0.RC1/jruby-bin-1.6.0.RC1.tar.gz
$ sudo tar xzvf jruby-bin-1.6.0.RC1.tar.gz
$ sudo ln -s jruby-1.6.0.RC1 jruby
$ sudo chown -R irakli jruby-1.6.0.RC1
$ sudo chmod -R 775 jruby-1.6.0.RC1
</code></pre></div></div>
<p>Please make sure to replace “irakli” with your non-root username (the
one you will be using for development) in the above sample code.</p>
<p>Next, you need to edit /etc/profile and add /opt/jruby/bin to your
$PATH with a line similar to:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>pathmunge /opt/jruby/bin
</code></pre></div></div>
<p>typically it will be around line 45, right before “export PATH …”
statement. Logout and log back in, to let Linux re-initialize with the
new PATH variable. Then proceed to installing required gems:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ jruby -S gem install bundler rake rails
</code></pre></div></div>
<p>Note: you could have just used the familiar “gem install…” if you were
sure that there are no other ruby/gem instances on the server, hence no
chance of confusing system about what “gem” stands for, but generally
it’s safer to use “jruby -S” syntax instead.</p>
<p>Let’s create a default Rails app and run it:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ jruby -S rails new yournewappname --template http://jruby.org
$ jruby -S bundle install
$ jruby -S rake db:create:all
$ jruby script/rails server
</code></pre></div></div>
<p>As you can see we ran the rails app with an embedded server. When you
are deploying your app in production, you, obviously should not do it.
Use Warbler to package your rails app as a JEE “war” archive and deploy
it into a servlet container such as Tomcat, GlassFish or Jetty:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ jruby -S gem install warbler
$ jruby -S warble
</code></pre></div></div>
SimpleTest Automated Testing and Debugging in Drupal7
2011-01-29T00:00:00-05:00
http://www.freshblurbs.com/blog/2011/01/29/simpletest-automated-testing-and-debugging-drupal7.html
<p>Drupal uses extended version of SimpleTest for automated testing. It
provides two parent classes for test cases: DrupalWebTestCase and
DrupalUnitTestCase. Documentation describes the DrupalWebTestCase as the
one appropriate for “typical Drupal tests”. However, a quick look at its
<a href="http://api.drupal.org/api/drupal/modules--simpletest--drupal_web_test_case.php/function/DrupalWebTestCase::setUp/7">setUp</a>
method is enough to notice that when this class is used a lot is done at
each test run, including a lot of pretty slow database work.</p>
<p>I am a recovering Java developer. As such, I was trained hard and long
to write tests not as an afterthought but as a design guide for the
actual working code, before the working code (some call it Test-Driven
Development). That, however, inevitably assumes running your tests very
frequently, against breaking code. <img src="http://freshblurbs.com/files/frustrated.jpg" alt="Photo copyright by Kay
Kim(ê¹ê¸°ì
)
http://www.flickr.com/photos/8906966@N02/3986997574/sizes/m/in/photostream/" />
If you write your test code as a sub-class of DrupalWebTestCase,
however, that is not really an option. With WebTestCase, each test run
takes several seconds (even on a very capable multi-core linux servers)
and those seconds really, really add up! I am easily irritable when I
write code. If something consistently wastes my time, I stop using it.</p>
<p>DrupalUnitTestCase on the other hand is much lighter and executes pretty
fast. At the first glance it’s a much better alternative to
DrupalWebTestCase. Unfortunately, it is not without some significant
shortcomings. As mentioned above, I am used to writing tests before the
working code. Which means: when I run tests, code is broken and I need
to debug it. For me, debugging a server-side application means using
some sort of logging (assume, if you wish, that I am philosophically
opposed to code tracing using inspection tools). Problem: there’s no way
to log anything from a child of DrupalUnitTestCase. Ouch.</p>
<p>Drupal’s native “watchdog” function does not work (not even with logging
to syslog, which additionally throws errors if devel module is enabled)
because Drupal is not fully bootstrapped for unit tests and, for reasons
unclear to me, PHP’s error_log() does not produce any output from test
classes, either.</p>
<p>The solution I could find is fixing error_log in your test case class’s
setUp() method with something like:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> public function setUp() {
parent::setUp('modulename');
//-- Can't use 'file_public_path' because simpletest overrides it.
$logfile = conf_path() . '/files/test.log';
ini_set('log_errors', 1);
ini_set('error_log', $logfile);
}
</code></pre></div></div>
<p>which will allow you to log messages with error_log() to
“sites/default/files/test.log” and may make using unit tests in Drupal
relatively possible.</p>
<p>The remaining problem with Drupal and unit testing is that Drupal
insists on using database for storing information about modules (and
consequently available hooks etc.). Since Drupal is not fully
bootstrapped in unit tests, a lot of this information is missing and you
have to be very careful with what functions you can call.</p>
<p>Oh well, life ain’t perfect.</p>
Installing and Configuring Clojure on CentOS 5
2011-01-29T00:00:00-05:00
http://www.freshblurbs.com/blog/2011/01/29/installing-and-configuring-clojure-centos-5.html
<p>Make sure you have epel Yum repo installed, if you don’t:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo rpm -Uvh http://download.fedora.redhat.com/pub/epel/5/x86_64/epel-release-5-4.noarch.rpm
</code></pre></div></div>
<p>Please note that the above instructions are for a 64-bit architecture,
on a 32-bit architecture:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo rpm -Uvh http://download.fedora.redhat.com/pub/epel/5/i386/epel-release-5-4.noarch.rpm
</code></pre></div></div>
<p>Make sure you have working version of JDK 6 (including the compiler), if
not install it by running:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo yum install java-1.6.0-openjdk-devel
</code></pre></div></div>
<p>Proceed with the installation of
<a href="https://github.com/technomancy/leiningen">leiningen</a> “a build tool for
Clojure designed to not set your hair on fire”:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo yum install readline rlwrap
$ cd /usr/local/bin
$ sudo wget https://github.com/technomancy/leiningen/raw/stable/bin/lein --no-check-certificate
$ sudo chmod 775 lein
$ lein
</code></pre></div></div>
<p>First run of “lein” will download all the required stuff and display
help, after which you can run interactive shell with simply:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ lein repl
</code></pre></div></div>
Installing Ruby On Rails 3 on CentOS with Nginx
2011-01-15T00:00:00-05:00
http://www.freshblurbs.com/blog/2011/01/15/installing-ruby-rails-3-centos-nginx.html
<p>This tutorial assumes that you are working with the local account on
CentOS 5.x and sudo into root as necessary.</p>
<h2 id="configuring-yum">Configuring Yum</h2>
<p>Yum is a popular package manager for CentOS and RedHat Linux
distributions. Unfortunately, standard Yum repositories carry
significantly outdated packages. Fortunately, there are third-party Yum
repositories with more updated LAMP packages which we can use. One such
repository is provided and hosted by RackSpace itself. Let’s set it up:</p>
<p>on a 64-bit CentOS 5.x, you need to run:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo rpm -Uvh http://dl.iuscommunity.org/pub/ius/stable/Redhat/5/x86_64/epel-release-1-1.ius.el5.noarch.rpm
sudo rpm -Uvh http://dl.iuscommunity.org/pub/ius/stable/Redhat/5/x86_64/ius-release-1.0-6.ius.el5.noarch.rpm
</code></pre></div></div>
<p>On 32-bit CentOS 5.x the commands would be:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo rpm http://dl.iuscommunity.org/pub/ius/stable/Redhat/5/i386/epel-release-1-1.ius.el5.noarch.rpm
sudo rpm http://dl.iuscommunity.org/pub/ius/stable/Redhat/5/i386/ius-release-1.0-6.ius.el5.noarch.rpm
</code></pre></div></div>
<p>For more information about setting up Rackspace’s IUS Community
repository, please refer to the following blog post: <a href="http://freshblurbs.com/reliable-yum-repo-easy-upgrades-latest-packages-redhat-and-centos">Reliable Yum Repo
for Easy Upgrades to the Latest Packages, on RedHat and
CentOS</a></p>
<h2 id="setting-up-packages">Setting Up Packages</h2>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo yum install openssl-devel zlib-devel gcc gcc-c++ make autoconf \
readline-devel curl-devel expat-devel gettext-devel patch
sudo yum install libjpeg libpng telnet libxslt freetype freetype-devel
sudo yum install mysql51-server mysql51-devel
</code></pre></div></div>
<p>Erase any possible existing installations:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo yum erase ruby ruby-libs ruby-mode \
ruby-rdoc ruby-irb ruby-ri ruby-docs
</code></pre></div></div>
<p>Install Ruby 1.8.7 (currently recommended version for RoR development)
from source:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cd /usr/local/src/
sudo wget http://ftp.ruby-lang.org/pub/ruby/ruby-1.8.7-p330.tar.gz
sudo tar xzvf ruby-1.8.7-p330.tar.gz
cd ruby-1.8.7-p330
sudo ./configure --enable-shared
sudo make
sudo make install
ruby -v
> ruby 1.8.7 (2010-12-23 patchlevel 330) [x86_64-linux]
</code></pre></div></div>
<p>Install Gems:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo wget http://rubyforge.org/frs/download.php/73882/rubygems-1.4.2.tgz
sudo tar xzvf rubygems-1.4.2.tgz
cd rubygems-1.4.2
sudo ruby setup.rb
gem --version
> 1.4.2
sudo gem install rubygems-update
sudo update_rubygems
</code></pre></div></div>
<p>Install Rake and Rails:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo gem install rake
sudo gem install rails
</code></pre></div></div>
<p>If you want/need to install SQLite and SQLite support for Ruby:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cd /usr/local/src/
sudo wget http://www.sqlite.org/sqlite-autoconf-3070400.tar.gz
sudo tar xzvf sqlite-autoconf-3070400.tar.gz
cd sqlite-autoconf-3070400
sudo ./configure
sudo make
sudo make install
sudo gem install sqlite3-ruby
sqlite3 -version
> 3.3.6
</code></pre></div></div>
<h2 id="install-the-latest-nginx-from-source">Install the latest Nginx from source:</h2>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo yum install pcre-devel
sudo wget http://sysoev.ru/nginx/nginx-0.8.54.tar.gz
sudo tar xzvf nginx-0.8.54.tar.gz
cd nginx-0.8.54
sudo ./configure --sbin-path=/usr/local/sbin --with-http_ssl_module \
--without-mail_pop3_module --without-mail_imap_module --without-mail_smtp_module \
--with-http_stub_status_module --with-http_realip_module
sudo make
sudo make install
sudo ln -s /usr/local/nginx/conf /etc/nginx
</code></pre></div></div>
<p>To make sure the newly installed Nginx properly restarts on server
restarts, please follow instructions in the very well-written <a href="http://articles.slicehost.com/2009/2/2/centos-adding-an-nginx-init-script">SliceHost
tutorial for installing Nginx startup
scripts</a></p>
<h2 id="install-passenger-for-nginx">Install Passenger for NginX:</h2>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo gem install passenger
</code></pre></div></div>
<p>Run step-by-step passenger for NginX installer by typing:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo passenger-install-nginx-module
</code></pre></div></div>
<p>Important: Please note that Nginx does not support dynamic modules.
Adding a module to Nginx means re-compiling it. passenger installer will
guide you through the steps of recompile. Please make sure you answer
the questions in the process similar to what’s shown below, otherwise
your NginX will not be re-compiled the way it was before passenger
“injection”:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>> 2. No: I want to customize my Nginx installation. (for advanced users)
> Where is your Nginx source code located?
> Please specify the directory: /usr/local/src/nginx-0.8.54
> Where do you want to install Nginx to?
> Please specify a prefix directory [/opt/nginx]: /usr/local/nginx
> Extra arguments to pass to configure script: --sbin-path=/usr/local/sbin \
--without-mail_pop3_module --without-mail_imap_module --without-mail_smtp_module \
--with-http_stub_status_module --with-http_realip_module
</code></pre></div></div>
<h2 id="configure-firewall">Configure Firewall</h2>
<p>Edit /etc/sysconfig/iptables-config and make sure following variables
are set to “yes�:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>IPTABLES_SAVE_ON_STOP=âyesâ
IPTABLES_SAVE_ON_RESTART=âyesâ
</code></pre></div></div>
<p>Open Web ports:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo /sbin/iptables -I INPUT -p tcp -m state --state NEW,ESTABLISHED --dport 80 -j ACCEPT
sudo /sbin/iptables -I INPUT -p tcp -m state --state NEW,ESTABLISHED --dport 443 -j ACCEPT
</code></pre></div></div>
<p>Restart iptables with:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo /sbin/service iptables stop
sudo /sbin/service iptables start
</code></pre></div></div>
<h2 id="databases">Databases</h2>
<p>Install MongoDB, following the steps from my <a href="http://freshblurbs.com/installing-mongodb-centos-or-fedora-yum">previous blog
post</a>.</p>
<p>Install MySQL and MongoDB gems:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo gem install mysql -- --with-mysql-config=/usr/bin/mysql_config
sudo gem install mongo bson bson_ext
</code></pre></div></div>
<h2 id="configure-bootup-scripts">Configure Bootup Scripts</h2>
<p>To make sure essential services come up when/if your server is
restarted, you need to run following commands:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo chkconfig --add nginx
sudo chkconfig --add mysqld
sudo chkconfig --add mongod
sudo chkconfig --level 2345 nginx on
sudo chkconfig --level 2345 mysqld on
sudo chkconfig --level 2345 mongod on
</code></pre></div></div>
<h2 id="wiring-your-first-app">Wiring your first app:</h2>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo chgrp -R webmaster /opt
mkdir /opt/reailsapps
cd /opt/railsapps
rails new firstapp
</code></pre></div></div>
<p>Edit file: /etc/nginx/nginx.conf and insert the following lines at the
end of the “http” section (typically: before the very last closing curly
brace “}” in the file, unless Nginx changes the default config file):</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> passenger_root /usr/local/lib/ruby/gems/1.8/gems/passenger-3.0.2;
passenger_ruby /usr/local/bin/ruby;
include sites/*.conf;
</code></pre></div></div>
<p>create /etc/nginx/sites/firstapp.conf with the following content:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>server {
listen 80;
server_name yourdomain.com;
root /opt/railsapps/firstapp/public; # <--- be sure to add 'public' to the app path!
passenger_enabled on;
#rails_env development;
gzip on;
}
</code></pre></div></div>
<p>Reload nginx configuration with:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo /etc/init.d/nginx reload (if you have install startup scripts) or
/usr/local/sbin/nginx -s reload
</code></pre></div></div>
<p>You should see default welcome screen of a rails app.</p>
<p>At that point you have successfully set up the environment.</p>
<h2 id="further-optimizations">Further Optimizations</h2>
<p>If you are interested in some more advanced scalability and efficiency
optimizations you may want to take a look at the: <a href="http://www.rubyenterpriseedition.com/">Ruby Enterprise
Edition</a></p>
Drupal Core CVS Checkout
2011-01-10T00:00:00-05:00
http://www.freshblurbs.com/blog/2011/01/10/drupal-core-cvs-checkout.html
<p>If you ever need to create a Drupal core patch, you may need to
check-out main branch of the appropriate version. CVS URLs for those are
not easy to find, so here they are:</p>
<p>Drupal 5:\</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cvs -d:pserver:anonymous:anonymous@cvs.drupal.org:/cvs/drupal -z6 checkout -d drupal-5 -r DRUPAL-5 drupal
</code></pre></div></div>
<p>Drupal 6:\</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cvs -d:pserver:anonymous:anonymous@cvs.drupal.org:/cvs/drupal -z6 checkout -d drupal-6 -r DRUPAL-6 drupal
</code></pre></div></div>
<p>Drupal-7 (Until there’s Drupal8):\</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cvs -d:pserver:anonymous:anonymous@cvs.drupal.org:/cvs/drupal -z6 checkout -d drupal-7 -r MAIN drupal
</code></pre></div></div>
Installing MongoDB On CentOS or Fedora with Yum
2011-01-09T00:00:00-05:00
http://www.freshblurbs.com/blog/2011/01/09/installing-mongodb-centos-or-fedora-yum.html
<p>The best way to install MongoDB on yum-enabled Linux distributions
(CentOS or Fedora) is through yum package manager. MongoDB.org provides
repositories (depending on your OS and CPU architecture) that you should
add to your list of yum repos:<br />
http://www.mongodb.org/display/DOCS/CentOS+and+Fedora+Packages</p>
<p>Once you have the repository properly installed under /etc/yum.repos.d
you can install the latest stable mongoDB release with:\</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo yum install mongo-stable-server
</code></pre></div></div>
<p><br />
which will actually install both the server and the client (since
client is set as a dependency).</p>
<p>Once installed MongoDB can be started with:\</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo /etc/init.d/mongod start
</code></pre></div></div>
<p>Further, if you need to Mongo-enable your PHP just run:\</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo pecl install mongo
</code></pre></div></div>
<p>and follow instructions.</p>
Securely Enabling Apache Server Status
2011-01-08T00:00:00-05:00
http://www.freshblurbs.com/blog/2011/01/08/securely-enabling-apache-server-status.html
<p>In httpd.conf:\</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>LoadModule status_module modules/mod_status.so
SetHandler server-status
Order deny,allow
Deny from all
Allow from 111.222.333.444
ExtendedStatus On
</code></pre></div></div>
<p>where 111.222.333.444 is the IP of your server.</p>
adduser: Only one or two names allowed.
2011-01-01T00:00:00-05:00
http://www.freshblurbs.com/blog/2011/01/01/adduser-only-one-or-two-names-allowed.html
<p>Got an error today I have never seen before (shocker) while trying to
set up something on Debian Lenny. Took a while to find the culprit, but
when I did it was so annoying, decided to share it here in case it saves
headache to somebody else.</p>
<p>So, I was just trying to run a seemingly innocent command:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo /usr/sbin/adduser —-system —-home /opt/otherhome/someuser —-no-create-home —-shell /bin/bash —-gecos “FirstName Lastname” someuser
</code></pre></div></div>
<p>Debian was freaking out with a violent: “adduser: Only one or two names
allowed.” error. Google search on the error returned a lot of hits, but
alas none of them helpful. Basically, people bailing and just creating a
regular user instead of a system one.</p>
<p>So, after some head-banging and giving up on Google, I noticed that the
answer had been right under my nose all along: command is correct but
characters are not! If you look closely you can notice that dashes and
quotes are typographical ones, not the usual geek ones you would use if
you typed the command yourself. Unfortunately, the difference is almost
impossible to tell in most terminal programs.</p>
<p>Fix: change dashed and quotes to appropriate characters or retype the
command entirely.</p>
<p>So there’s something to be said about me copy/pasting code from a Github
gist page and trusting it would just work and for people who
typographically alter code snippets :)</p>
<p>#sigh</p>
SSH Key Problems: Can Not Log In
2010-12-28T00:00:00-05:00
http://www.freshblurbs.com/blog/2010/12/28/ssh-key-problems-can-not-log.html
<p>If you generated your ssh key pair, did everything per instructions and
still can’t log-in using the keys, you may be a victim of the most
common ssh key problem: incorrect permissions. Permissions both on the
server and the client machine (if your client is Linux/Unix or Mac OS-X)
must be set properly, which is:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_rsa
chmod 644 ~/.ssh/authorized_keys2
</code></pre></div></div>
<p>Also, don’t forget that while ssh-keygen generates id_rsa.pub file,
when uploaded to the server, that file must be renamed to:
authorized_keys2</p>
Reliable Yum Repo for Easy Upgrades to the Latest Packages, on RedHat and CentOS
2010-11-24T00:00:00-05:00
http://www.freshblurbs.com/blog/2010/11/24/reliable-yum-repo-easy-upgrades-latest-packages-redhat-and-centos.html
<p>Yum is a great update manager for RedHat/CentOS Linux. Unfortunately,
default repos are typically way behind the stable releases of the
packages contained in them. If you need to install PHP, MySQL, Python or
other major package, you will find that the versions in default repos
are old to the extent of being useless. This used to force Yum users to
resort to third-party repositories and many open-source volunteers have
hosted latest versions of packages as yum repositories, helping and
assisting the community.</p>
<p>While most efforts were noble and honest contributions, it’s always
tricky to install packages from unknown sources. The dark fear of “what
if” will nag you and your security team (if you have one) will point you
to the door. Now there’s a good solution, however. One of the most
trusted names in the industry, <a href="http://rackspace.com">Rackspace</a> hosting
now has a Yum repo for popular RedHat packages.</p>
<p>The wiki documentation for how to install and use it can be found at:
<a href="http://wiki.iuscommunity.org/Doc/ClientUsageGuide">http://wiki.iuscommunity.org/Doc/ClientUsageGuide</a></p>
<p>Please note that currently the links on the wiki seem to be
outdated/broken, so to install the repo on a 64-bit CentOS 5.x, you
actually need to run:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo rpm -Uvh http://dl.iuscommunity.org/pub/ius/stable/Redhat/5/x86_64/epel-release-1-1.ius.el5.noarch.rpm
sudo rpm -Uvh http://dl.iuscommunity.org/pub/ius/stable/Redhat/5/x86_64/ius-release-1.0-6.ius.el5.noarch.rpm
</code></pre></div></div>
<p>On 32-bit CentOS 5.x the commands would be:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo rpm http://dl.iuscommunity.org/pub/ius/stable/Redhat/5/i386/epel-release-1-1.ius.el5.noarch.rpm
sudo rpm http://dl.iuscommunity.org/pub/ius/stable/Redhat/5/i386/ius-release-1.0-6.ius.el5.noarch.rpm
</code></pre></div></div>
List of All Facebook-Supported Locales
2010-11-08T00:00:00-05:00
http://www.freshblurbs.com/blog/2010/11/08/list-all-facebook-supported-locales.html
<p>This was not easy to track down in the documentation, but for anybody
that may need it, here’s the XML list of locales supported by Facebook:
http://www.facebook.com/translations/FacebookLocales.xml</p>
Installing Ruby 1.8.6 on CentOS with Yum
2010-11-06T00:00:00-04:00
http://www.freshblurbs.com/blog/2010/11/06/installing-ruby-1-8-6-centos-yum.html
<p>If you want to use the latest version of RubyGems on CentOS 5.x you need
a later version of Ruby than what you can get from usual sources
(CentOS, CentOS-Test or RPMForge Yum repos).</p>
<p>I still have not found a yum repo that allows to install 1.9.x branch of
Ruby (for installation instructions by compiling source see my blog
post: <a href="http://freshblurbs.com/install-ruby-1-9-centos">Install Rubby 1.9 on
CentOS</a>), but here’s how
to upgrade to the minimal requirement of 1.8.6:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo rpm -Uvh http://download.fedora.redhat.com/pub/epel/5/x86_64/epel-release-5-4.noarch.rpm
$ sudo rpm -Uvh http://download.elff.bravenet.com/5/x86_64/elff-release-5-3.noarch.rpm
$ sudo yum install ruby ruby-shadow ruby-ri ruby-rdoc gcc gcc-c++ ruby-devel -y
$ ruby -v
ruby 1.8.6 (2010-02-05 patchlevel 399) [x86_64-linux]
</code></pre></div></div>
<p>Please note that the above instructions are for a 64-bit architecture,
on a 32-bit architecture:\</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo rpm -Uvh http://download.fedora.redhat.com/pub/epel/5/i386/epel-release-5-4.noarch.rpm
$ sudo rpm -Uvh http://download.elff.bravenet.com/5/i386/elff-release-5-3.noarch.rpm
$ sudo yum install ruby ruby-shadow ruby-ri ruby-rdoc gcc gcc-c++ ruby-devel -y
$ ruby -v
</code></pre></div></div>
<p>To install RubyGems:\</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ wget http://rubyforge.org/frs/?group_id=126&release_id=43601
$ tar xzvf rubygems-1.3.7.tgz
$ cd cd rubygems-1.3.7
$ sudo ruby setup.rb
$ gem --version
1.3.7
</code></pre></div></div>
Install Ruby 1.9 on CentOS
2010-11-06T00:00:00-04:00
http://www.freshblurbs.com/blog/2010/11/06/install-ruby-1-9-centos.html
<p>Unfortunately, CentOS 5.5 comes with a very old version of Ruby: 1.8.5.
Even the latest rubygems require at least 1.8.6 to install. To make
things more dire, centos-test and rpmforge yum repos do not carry a more
up-to-date Ruby version.</p>
<p>If you are fine upgrading to just 1.8.6, and want to use Yum, see my
blog post: <a href="http://freshblurbs.com/installing-ruby-1-8-6-centos-yum">Installing Ruby 1.8.6 on CentOS with
Yum</a>, otherwise
following is how to install Ruby 1.9.2 from sources:</p>
<p>First uninstall any existing installations:\</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo yum erase ruby ruby-libs ruby-mode ruby-rdoc ruby-irb ruby-ri ruby-docs
</code></pre></div></div>
<p>Then proceed with installing Ruby from sources, making sure you have all
the required development tools to do so:\</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo yum install openssl-devel zlib-devel \
gcc gcc-c++ make autoconf readline-devel \
curl-devel expat-devel gettext-devel
./configure --enable-shared --enable-pthread --prefix=/usr
make
sudo make install
</code></pre></div></div>
<p>Attention: Ruby 1.9.2 now includes RubyGems so there’s no need to
install it separately. As a matter of fact, if you try doing so you will
get an error like:\</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rubygems-1.3.7/lib/rubygems/source_index.rb:68:in `installed_spec_directories': undefined method `path' for Gem:Module (NoMethodError)
</code></pre></div></div>
<p>Test that everything installed successfully:\</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ ruby -v
ruby 1.9.2p0 (2010-08-18 revision 29036) [x86_64-linux]
$ gem --version
1.3.7
</code></pre></div></div>
Sudo-Saving a File in Vi as Root
2010-11-02T00:00:00-04:00
http://www.freshblurbs.com/blog/2010/11/02/sudo-saving-file-vi-root.html
<p>How many times have you accidentally opened a protected file with vi,
edited a whole bunch of stuff in it and only at the point you wanted to
save it, have you remembered that you’d forgotten to “sudo” before
editing the file? If you do a lot of Unix work, I bet this has happened
to you more than once. It is anything but a pleasant experience.</p>
<p>However, you do not have to quit without saving (i.e. lose your changes)
and re-edit the file as root, instead you can get quick sudo from within
the vi itself by typing:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>:w !sudo tee %
</code></pre></div></div>
<p>instead of the usual “:w”</p>
First Version of LoadTest.IO Released
2010-11-02T00:00:00-04:00
http://www.freshblurbs.com/blog/2010/11/02/first-version-loadtest-io-released.html
<p>The very fresh and raw 0.1 version of http://loadtest.io is now
available for your enjoyment.</p>
<h2 id="what-is-it">What is It?</h2>
<p>LoadTest.io is multi-threaded load-tester with auto-discovery. It is
ideal for load-tests that target breadth. You give loadtest.io some
initial URLs and it will crawl the rest of your website,
auto-discovering links as it goes. It will also try to not repeat
already-tested URLs and reach maximum number of unique URLs in the
shortest time possible.</p>
<p>Due to this characteristic, LoadTest.io is a very good tool for testing
websites that employ caching. Such websites can not adequately be tested
by stress-testing tools that only hit limited number of URLs.</p>
<h2 id="why-would-you-care">Why Would You Care?</h2>
<p>The majority of tools currently available do not have auto-discovery
feature. Which means they can only test a fixed set of URLs. But any
reasonably built web-system has some kind of caching, so after the first
hit, any consequent hit to the same URL only tests your cache not - the
web system (application layer, database etc). Such test can be
unrealistically optimistic and misleading. Real traffic from real users
will not just hit 20 hand-picked URLs from your web-site.</p>
Reverting a File To Previous Revision in CVS
2010-10-06T00:00:00-04:00
http://www.freshblurbs.com/blog/2010/10/06/reverting-file-previous-revision-cvs.html
<p>For the [hopefully very infrequent] times when you still need to deal
with CVS, in 2010, and [god forbid] fix something you messed up there,
here’s how you can revert an accidental commit back to the previous
version.</p>
<p>First find the revision you need to revert back to by running:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cvs log screwed_up.code
</code></pre></div></div>
<p>Once you have the revision number you want to switch to (say, 2.1.2.1),
run:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cvs -Q update -p -r 2.1.2.1 screwed_up.code > screwed_up.code
</code></pre></div></div>
My Thoughts About the Google Street View and Privacy
2010-07-09T00:00:00-04:00
http://www.freshblurbs.com/blog/2010/07/09/my-thoughts-about-google-street-view-and-privacy.html
<p>As I sit here on a hot, humid Friday night with my scotch and my laptop
(21st century #fail), in a thoroughly air-conditioned room, I try to
make myself useful. In this unbearable heat, only a desperate socialite
would even think about going out. I, myself, much prefer pointlessly
scrolling through the day’s worth of tweets, catching up on the
discussions about Google Street View and privacy. Not even sure how old
this stuff is, I start to slowly type my thoughts on the subject.</p>
<p>To make my thoughts look more respectable, I organize them in a bulleted
list. I will attach a pie-chart later.</p>
<ul>
<li>In case you did not know: between Facebook, professional spammers
and the government (not just yours, too), you have no privacy to
begin with. The only thing anybody does not know about you is what
they don’t care to know about you. So, please come down the high
horse and wake up.</li>
<li>Google Street View is the most amazing technology we have in 2010
(except maybe for Twitter). If you don’t believe me, check this out:
I am sitting on my couch in North America and am browsing streets in
Australia. Beat that.</li>
<li>Google Street View does not go into anybody’s home. It only captures
public places, so just be a decent human being when you are outdoors
and you should be fine.</li>
<li>Did I mention Street View is a piece of art and a global treasure?
Yeap, it is.</li>
</ul>
<p>With the final score of 4:0, I am all for Google Street View and I
think, in this case, Google is the victim: offering a wonderful service
for free, getting little gratitude for it.</p>
<p>Peace.</p>
LAMP Settings for a High-Performance Small Server.
2010-06-30T00:00:00-04:00
http://www.freshblurbs.com/blog/2010/06/30/lamp-settings-high-performance-small-server.html
<p>With the VPS expansion you can now get a (very) small virtual private
server (VPS) for a very affordable price. However, when you get a server
with something like 256MB or 512MB RAM and a portion of CPU power, using
default MySQL/PHP/Apache settings is a pretty bad idea.</p>
<p>Performance and scalability tuning of a server is more of an art than
science, in the sense that there’re no ready-to-use formulas. Optimal
server settings depend on many unique factors: web-app code, traffic to
the site, site’s information architecture among other things. It’s
virtually impossible to really optimize server settings without thorough
understanding of the web application and a lot of testing.</p>
<p>That said, you are not going to run newsweek.com or huffingtonpost.com
on a 256MB slice. Also, the default settings are typically so off that
it is possible to give you a much better starting point. I’d like to
share with you some settings that have worked well for me. I am assuming
you are running a small site or a blog, with the traffic of several
thousand page-views/day, using Wordpress, Drupal or something of that
kind. I highly recommend getting at least a 512MB VPS, but these
settings are better than the default for a 256MB server, as well.</p>
<p>Following are some variables for various settings files that have been
modified from their default values.</p>
<p>/etc/my.cnf:\</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>thread_cache_size=4
# Skip bdb if your install has it.
# skip-bdb
skip-locking
query_cache_type=1
query_cache_size=64M
query_cache_limit=8M
# Reduce max_connections to 16 for a 256M server
max_connections=32
key_buffer_size=4M
# Reduce the following two settings to 32M for a 256M server
tmp_table_size=48M
max_heap_table_size=48M
join_buffer_size=4M
max_allowed_packet=8M
innodb_additional_mem_pool_size=8M
innodb_buffer_pool_size=16M
innodb_flush_log_at_trx_commit = 1
# Server/Storage Engine Settings
default-storage-engine=INNODB
# for MySQL 5.0:
default-character-set= utf8
# for MySQL 5.1, use the following instead:
# skip-character-set-client-handshake
# collation_server = utf8_unicode_ci
# character_set_server = utf8
</code></pre></div></div>
<p>/etc/php.ini:\</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>; Drupal is memory-hungry, you will need at least 64M or 92M for Drupal,
; but 40M should be fine for barebones Wordpress
memory_limit = 48M
realpath_cache_ttl=300
realpath_cache_size=1M
</code></pre></div></div>
<p>/etc/php.d/apc.ini\</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>extension=apc.so
apc.enabled=1
apc.shm_segments=1
; Reduce shm_size to 32 for 256M server
apc.shm_size=48
apc.ttl=7200
apc.user_ttl=7200
apc.num_files_hint=1024
apc.mmap_file_mask=/tmp/apc.XXXXXX
apc.enable_cli=1
</code></pre></div></div>
<p>/etc/httpd/conf/httpd.conf\</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>KeepAlive On
MaxKeepAliveRequests 100
KeepAliveTimeout 3
# Replace /var/www with whatever directory you keep your virtualhost folders under.
AllowOverride all
Options all
Order allow,deny
Allow from all
Deny from none
# Insert filter
SetOutputFilter DEFLATE
# Netscape 4.x has some problems...
BrowserMatch ^Mozilla/4 gzip-only-text/html
# Netscape 4.06-4.08 have some more problems
BrowserMatch ^Mozilla/4\.0[678] no-gzip
# MSIE masquerades as Netscape, but it is fine
# BrowserMatch \bMSIE !no-gzip !gzip-only-text/html
# NOTE: Due to a bug in mod_setenvif up to Apache 2.0.48
# the above regex won't work. You can use the following
# workaround to get the desired effect:
BrowserMatch \bMSI[E] !no-gzip !gzip-only-text/html
# Don't compress images, videos and audio
SetEnvIfNoCase Request_URI \
\.(?:gif|jpe?g|png|flv|mp4|m4v|mp3|zip|gz)$ no-gzip dont-vary
# Make sure proxies don't deliver the wrong content
Header append Vary User-Agent env=!dont-vary
</code></pre></div></div>
<h3 id="disabling-swap">Disabling Swap</h3>
<p>Another thing that can adversely affect performance is if a server
decides to start using swap partition for memory. On Linux, swap space
is there to prevent running out of memory. However, Linux is somewhat
frivolous in swapping, in that it may use swap even in the cases when it
would not have ran out of memory. When linux uses swap for MySQL or
Apache/PHP performance degrades significantly.</p>
<p>If you want to be absolutely sure that swapping never happens you can
disable swap. This is dangerous because if you don’t properly project
your maximum memory allocation you may run out of space and server will
crash. But sometimes the risk is worth the benefit of running the server
at top speed. To disable swap: edit the /etc/fstab file and find a
record that looks like:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/dev/sda2 swap swap defaults 0 0
</code></pre></div></div>
<p>The first column shows the partition used for swap: /dev/sda2. It may be
different in your case. To disable swap put a comment character (“#”
pound character) in front of that line and run the following command as
root:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>swapoff /dev/sda2
</code></pre></div></div>
<p>where the argument of “swapoff” should be the partition which swap was
mounted on.</p>
<h3 id="static-cache">Static Cache</h3>
<p>Another thing that could be a great idea for a blog on a small server is
to put it behind a static-HTTP-cache like
<a href="http://varnish-cache.org">Varnish</a>. That can really boost your
scalability. Configuring Varnish is a complex and large topic that
requires its own blog post, however.</p>
Installing GoogleCL On a Mac
2010-06-19T00:00:00-04:00
http://www.freshblurbs.com/blog/2010/06/19/installing-googlecl-mac.html
<p><a href="http://code.google.com/p/googlecl/">GoogleCL</a> is a command-line client
to Google services that was released recently. It should appeal to Web
geeks, many of whom, in my non-scientific observation, are Mac users.</p>
<p>GoogleCL documentation suggest you use MacPorts to install it on Mac.</p>
<p>Now, I have to admit - it really pisses me off when people talk about
installing simple Unix utilities on Mac using MacPorts (or Fink or that
new kid on the block called HomeBrew). People, Mac OS-X 10.5 and up is a
POSIX Unix system! If you have Dev Tools installed, and Terminal does
not scare you, you should not need a crappy thing like MacPorts to
install a simple unix utility like Git, SVN or GoogleCL. If you can not
install them as you would install on most Unix systems, MacPorts will
probably fail you too, so no need to pile garbage on your shiny Mac.</p>
<p>If you don’t have DevTools installed on your Mac, stop calling yourself
a Mac geek until you go to http://developer.apple.com/, download and
install Dev Tools.</p>
<p>The pre-requisites to GoogleCL are Python 2.5+ and Gdata Python Client
Library. OS-X versions 10.5 and 10.6 have proper Python version
pre-installed. Installaltion of the rest is as easy as:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mkdir ~/src
cd ~/src
curl -O http://gdata-python-client.googlecode.com/files/gdata-2.0.10.tar.gz
tar xzvf gdata-2.0.10.tar.gz
cd gdata-2.0.10
sudo python setup.py install
curl -O http://googlecl.googlecode.com/files/googlecl-0.9.5.tar.gz
tar xzvf googlecl-0.9.5.tar.gz
cd googlecl-0.9.5
sudo python setup.py install
</code></pre></div></div>
<p>(The versions of GData and GoogleCL in the example are the latest
current versions, if you find this blog post months from the date it was
written on, make sure you download the latest and not outdated versions.
The steps should still be the same).</p>
<p>After which you can run google shell with the command:\</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>google
</code></pre></div></div>
<p>To make sure you are properly set up run:\</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>youtube list
</code></pre></div></div>
<p>GoogleCL will give you instructions for logging into your account and if
you have ever uploaded any videos to YouTube (has not everybody?) it
will list those for you.</p>
<p>Enjoy.</p>
Fix: Yum Error: ValueError: need more than 1 value to unpack
2010-05-14T00:00:00-04:00
http://www.freshblurbs.com/blog/2010/05/14/fix-yum-error-valueerror-need-more-1-value-unpack.html
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>yum clean all
yum clean metadata
yum clean dbcache
</code></pre></div></div>
<p>and then:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>yum makecache
</code></pre></div></div>
Changes Since Last Push in Git
2010-03-15T00:00:00-04:00
http://www.freshblurbs.com/blog/2010/03/15/changes-last-push-git.html
<p>The “git status” command only shows uncommitted changes locally. But
what if we need to see “what <strong>files</strong> would get pushed if we did a push
now?”. The answer is not trivial (and no, “git push –dry-run” is not
useful since it does not show changed files).</p>
<p>I’ve been looking for an answer, and since I am no git expert, it took
me a while to find one, until <a href="http://twitter.com/iosebi">@iosebi</a> came
to rescue. Apparently, what you need is this line of code:\</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git log origin/master.. --stat
</code></pre></div></div>
<p>Thank you, <a href="http://twitter.com/iosebi">@iosebi</a>! I probably hate git a
little less, now :)</p>
Adding Drupal, Django and JQuery Support to Espresso
2010-03-06T00:00:00-05:00
http://www.freshblurbs.com/blog/2010/03/06/adding-drupal-django-and-jquery-support-espresso.html
<p>MacRabbit’s Espresso (http://macrabbit.com/espresso/) has been my
favorite editor for server-side scripting for a while now. I was an avid
Coda user before that, and Coda is a fine editor, but I like several
features of Espresso better (e.g. large file browser in the center and
ability to simultaneously open files from any number of servers).</p>
<p>Espresso is much “younger” than Coda and it was a little behind on
language support (and availability of plugins in general), initially. We
even had to post <a href="http://www.freshblurbs.com/teaching-espresso-drupal-php-file-extensions-e-g-module">a hacking
instruction</a>
for how to “teach” Espresso Drupal files. (<strong>UPDATE</strong>: new instructions
at:
http://freshblurbs.com/espresso-and-syntax-highlight-custom-file-formats)</p>
<p>The situation is much different now. There’s a wonderful abundance of
quality plugins now at http://fileability.net/coffee/ that work like a
charm. We are using Combined Python&Jango, JQuery, YAML and Drupal-PHP
sugars and they are simply awesome. To install, all you need is download
appropriate tar.gz, unarchive. rename resulting folder so it has
extension .sugar and move that to ~/Library/Appplication
Support/Espresso/Sugars</p>
Best jQuery Book Ever
2010-01-21T00:00:00-05:00
http://www.freshblurbs.com/blog/2010/01/21/best-jquery-book-ever.html
<p>An absolutely awesome jQuery book: http://jqueryenlightenment.com/</p>
<p>It’s this simple: if you are a Web developer, you need this. And you
will support the project. And PDF version is dirt-cheap.</p>
Prevent Terminal from timing-out SSH on Mac.
2010-01-11T00:00:00-05:00
http://www.freshblurbs.com/blog/2010/01/11/prevent-terminal-timing-out-ssh-mac.html
<p>If you use Terminal application on Mac OS-X to connect over SSH, you
have most probably been annoyed by closed connections. Following is a
quick recipe to prevent timeouts:</p>
<p>Open Terminal</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>> sudo vi /etc/ssh_config
</code></pre></div></div>
<p>Edit the file to make lines 20-21 look like:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Host *
ServerAliveInterval 5
</code></pre></div></div>
<p>Save file and restart Terminal. Your connections won’t time-out nearly
as frequently.</p>
Password-Protecting Apache Folders
2010-01-07T00:00:00-05:00
http://www.freshblurbs.com/blog/2010/01/07/password-protecting-apache-folders.html
<p>Prerequisite: Make sure .htaccess overrides are allowed for the folder
you are protecting!</p>
<p>In the folder being protected create two files:</p>
<p>.htaccess:\</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>AuthUserFile /path/to/file/.htpasswd
AuthType Basic
AuthName "Secured Access"
Require valid-user
</code></pre></div></div>
<p>or if you need to protect just specific file, change the last part of
.htaccess to read like:\</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> Require valid-user
</code></pre></div></div>
<p>For the creation of .htpasswd, in the corresponding folder run:\</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>htpasswd .htpasswd Johnnie
</code></pre></div></div>
<p>To change password in an existing .htpasswd for user Jannie:\</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>htpasswd .htpasswd Jannie
</code></pre></div></div>
Font Sizes
2009-12-01T00:00:00-05:00
http://www.freshblurbs.com/blog/2009/12/01/fontsizes.html
<p>Following is a handy matrix for those among us who like to indicate HTML
(font) sizes in “em”s. All modern browsers use a 16px default font size.
Specifying the font-size and line-height in ems (relative to the 16px
default font) allows the user to resize the font in the browser and
produces the most consistent results across different browsers.</p>
<p>For more about using em’s, read:
http://www.alistapart.com/articles/howtosizetextincss</p>
<p>Now, the matrix:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> font-size: .625em; = 10px
font-size: .6875em; = 11px
font-size: .75em; = 12px
font-size: .8125em; = 13px
font-size: .875em; = 14px
font-size: .9375em; = 15px
font-size: 1.0625em; = 17px
font-size: 1.125em; = 18px
font-size: 1.188em; = 19px
font-size: 1.25em; = 20px
font-size: 1.313em; = 21px
font-size: 1.375em; = 22px
font-size: 1.438em; = 23px
font-size: 1.5em; = 24px
font-size: 1.563em; = 25px
font-size: 1.625em; = 26px
font-size: 1.688em; = 27px
font-size: 1.75em; = 28px
font-size: 1.813em; = 29px
font-size: 1.875em; = 30px
</code></pre></div></div>
Installing Django 1.1 on CentOS 5.4
2009-11-27T00:00:00-05:00
http://www.freshblurbs.com/blog/2009/11/27/tutorial-installing-django-1-1-centos-5-4.html
<p>This step-by-step tutorial walks you through the installation of Django
1.1 with Apache and MySQL. on CentOS 5. The example VPS used during the
walk-through is the popular <a href="http://slicehost.com">SliceHost</a> from
RackSpace ™ The steps involved should be quite similar for any properly
installed CentOS 5.x (or RedHat EL 5.x).</p>
<p>We use the latest stable version of Python: 2.6 and mod_wsgi (far
superior alternative to mod_python), in this tutorial. Django is not,
yet, compatible with Python 3.x branch (few things are).</p>
<p>Note: this tutorial is partially based on: <a href="http://blog.perplexedlabs.com/2008/11/10/setup-python-25-mod_wsgi-and-django-10-on-centos-5-cpanel/">a blog post by Matt
Reiferson</a></p>
<h3 id="set-up-user">Set up user</h3>
<p>We will first log-in as root and set up environment for a user with the
username “irakli” (you can use your own username).</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[root@django ~]# groupadd webmaster
[root@django ~]# useradd -c "Irakli" -g webmaster -m -s /bin/bash irakli
[root@django ~]# passwd irakli
Changing password for user irakli.
New UNIX password:
Retype new UNIX password:
passwd: all authentication tokens updated successfully.
[root@django ~]# visudo
</code></pre></div></div>
<p>Add a line like “irakli ALL=(ALL) ALL” under similar “root ALL=(ALL)
ALL” line (by default line #77) to grant your new user sudo access and
avoid the necessity of using root account.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[root@django ~]# sudo su - irakli
[irakli@django ~]$ sudo hostname yourhostname.com
</code></pre></div></div>
<ul>
<li>Add entry into /etc/hosts to point public ip address to
yourhosntame.com</li>
<li>Edit /etc/sysconfig/network to set hostname</li>
<li>
<p>sudo-edit /etc/bashrc and add following code after the original
umask logic (around line 14):\</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>if [ $UID -gt 99 ] && [ "`id -gn`" = "webmaster" ]; then
umask 002
fi
</code></pre></div> </div>
</li>
</ul>
<h3 id="install-apache-mysql-and-miscellaneous-tools">Install Apache, MySQL and miscellaneous tools</h3>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[irakli@django ~]$ sudo yum install httpd-devel mysql mysql-server mysql-client mysql-devel apr-devel
[irakli@django ~]$ sudo yum install openssl mod_ssl crypto-utils
[irakli@django ~]$ sudo yum install libjpeg libpng gcc make autoconf telnet libxslt gettext
[irakli@django ~]$ sudo yum install bind bind-utils bind-devel
[irakli@django ~]$ sudo yum install zlib-devel
[irakli@django ~]$ sudo yum install postfix # I like postfix over sendmail
</code></pre></div></div>
<ul>
<li>
<p>Make sure your /etc/httpd/conf/httpd.conf includes a line like:\</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Include conf.d/*.conf
</code></pre></div> </div>
</li>
<li>sudo mkdir /var/www/default</li>
<li>
<p>sudo vi /etc/httpd/conf.d/00_default.virtualhost.conf in there
enter:\</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>NameVirtualHost *:80
<VirtualHost *:80>
DocumentRoot /var/www/default
ServerName _default_
ErrorLog logs/default-error_log
CustomLog logs/default-access_log common
</VirtualHost>
</code></pre></div> </div>
</li>
<li>
<p>sudo vi /var/www/default/index.html<br />
in there enter your default message for misconfigured hosts:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Default blank page
</code></pre></div> </div>
</li>
</ul>
<h3 id="upgrading-python">Upgrading Python</h3>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[irakli@django ~]$ python -V
Python 2.4.3
[irakli@django ~]$ cd ~/
[irakli@django ~]$ mkdir src
[irakli@django ~]$ cd src
[irakli@django src]$ wget http://www.python.org/ftp/python/2.6.4/Python-2.6.4.tgz
[irakli@django src]$ tar xzvf Python-2.6.4.tgz
[irakli@django src]$ cd Python-2.6.4
[irakli@django Python-2.6.4]$ ./configure --prefix=/opt/python2.6 --with-threads --enable-shared --with-zlib=/usr/include
[irakli@django Python-2.6.4]$ make
[irakli@django Python-2.6.4]$ sudo make install
[irakli@django Python-2.6.4]$ sudo ln -s /opt/python2.6/lib/libpython2.6.so /usr/lib
[irakli@django Python-2.6.4]$ sudo ln -s /opt/python2.6/lib/libpython2.6.so.1.0 /usr/lib
[irakli@django Python-2.6.4]$ sudo /sbin/ldconfig -v
[irakli@django Python-2.6.4]$ sudo ln -s /opt/python2.6/bin/python /usr/local/python
[irakli@django Python-2.6.4]$ python -V
Python 2.6.4
Troubleshooting: if you still see old version of Python, you need to edit /etc/profile (as root), add the following line:
pathmunge /opt/python2.6/bin/
</code></pre></div></div>
<p>towards the end of the file, before the line that reads something like:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>export PATH USER LOGNAME MAIL HOSTNAME HISTSIZE INPUTRC
</code></pre></div></div>
<p>and re-login to the system, so that new path location is picked up by
the system. Then try running “python -V” again.</p>
<p>[irakli@django ~]$ sudo yum search php # make sure we did not
accidentally mess up “yum”, which is the biggest threat when upgrading
Python version. If you see no errors, you should be fine</p>
<h3 id="installing-python-extensions">Installing Python Extensions</h3>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[irakli@django Python-2.6.4]$ cd ..
[irakli@django src]$ wget http://bit.ly/6E0DNN
[irakli@django src]$ sudo su -
[root@django ~]# cd /home/irakli/src/
[root@django src]# chmod u+x setuptools-0.6c11-py2.6.egg
[root@django src]# ./setuptools-0.6c11-py2.6.egg --prefix=/opt/python2.6
[root@django src]# exit
logout
# (For some reason installing MySQL-python .egg binary, we downloaded, did not work. Let's show how to install it from source, if you run into a similar problem):
[irakli@django src]$ wget http://bit.ly/6j4uID
[irakli@django src]$ tar xzf MySQL-python-1.2.3c1.tar.gz
[irakli@django src]$ cd MySQL-python-1.2.3c1
[irakli@django MySQL-python-1.2.3c1]$ python setup.py build
[irakli@django MySQL-python-1.2.3c1]$ sudo python setup.py install
[irakli@django MySQL-python-1.2.3c1]$ cd ..
[irakli@django src]$ python
Python 2.6.4 (r264:75706, Nov 29 2009, 19:51:34)
[GCC 4.1.2 20080704 (Red Hat 4.1.2-46)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import MySQLdb
(you should not see any errors, type Ctrl-D to exit)
</code></pre></div></div>
<h3 id="install-django">Install Django</h3>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[irakli@django src]$ wget http://www.djangoproject.com/download/1.1.1/tarball/
[irakli@django src]$ tar xzf Django-1.1.1.tar.gz
[irakli@django src]$ cd Django-1.1.1
[irakli@django Django-1.1.1]$ python setup.py build
[irakli@django Django-1.1.1]$ sudo python setup.py install
[irakli@django Django-1.1.1]$ cd ..
[irakli@django src]$ python
Python 2.6.4 (r264:75706, Nov 29 2009, 19:51:34)
[GCC 4.1.2 20080704 (Red Hat 4.1.2-46)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import django
>>> django.VERSION
(1, 1, 1, 'final', 0)
>>> import MySQLdb
</code></pre></div></div>
<h3 id="starting-a-django-project">Starting a Django Project</h3>
<p>Note: for former PHP developers, it’s important to understand that
Django project not only does not have to, but also should not be in a
web-accessible folder. An installatio that has Django project under a
DocumentRoot is inherently insecure.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[irakli@django src]$ sudo mkdir -p /opt/web/django
[irakli@django src]$ sudo chown irakli:webmaster -R /opt/web
[irakli@django src]$ sudo chmod -R 775 /opt/web
[irakli@django web]$ cd /opt/web/django
[irakli@django django]$ /opt/python2.6/bin/django-admin.py startproject iproj
[irakli@django django]$ cd iproj
</code></pre></div></div>
<h3 id="configure-apache-with-mod_wsgi">Configure Apache with mod_wsgi</h3>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[irakli@django django]$ cd ~/src
[irakli@django src]$ sudo ln -s /opt/python2.6/lib/python2.6.so /opt/python2.6/lib/python2.6/config/
[irakli@django src]$ wget http://modwsgi.googlecode.com/files/mod_wsgi-2.8.tar.gz
[irakli@django src]$ cd mod_wsgi-2.8
[irakli@django mod_wsgi-2.8]$ ./configure --with-python=/usr/local/bin/python
[irakli@django mod_wsgi-2.8]$ make
[irakli@django mod_wsgi-2.8]$ sudo make install
[irakli@django mod_wsgi-2.8]$ cd ~/src
[irakli@django src]$ vi /opt/web/django/iproj.wsgi
import os
import sys
sys.path.append('/opt/web/django')
os.environ['DJANGO_SETTINGS_MODULE'] = 'iproj.settings'
os.environ['PYTHON_EGG_CACHE'] = '/opt/web/django/iproj/.python-eggs'
import django.core.handlers.wsgi
application = django.core.handlers.wsgi.WSGIHandler()
[irakli@django src]$ mkdir /opt/web/django/iproj/.python-eggs
[irakli@django src]$ sudo chmod -R 777 /opt/web/django/iproj/.python-eggs
[irakli@django src]$ mkdir /opt/web/django/iproj/logs
[irakli@django src]$ sudo chown apache:staff -R /opt/web/django/iproj/logs
[irakli@django src]$ sudo chmod -R 775 /opt/web/django/iproj/logs
[irakli@django src]$ sudo vi /etc/httpd/conf.d/yourdomain.com.conf
<VirtualHost *:80>
ServerName yourdomain.com
ErrorLog /opt/web/django/iproj/logs/error_log
CustomLog /opt/web/django/iproj/logs/access_log combined
UseCanonicalName Off
Alias /admin_media /opt/python2.6/lib/python2.6/site-packages/django/contrib/admin/media
Alias /static /opt/web/django/iproj/static
WSGIScriptAlias / /opt/web/django/iproj.wsgi
WSGIDaemonProcess iproj processes=7 threads=1 display-name=%{GROUP}
</VirtualHost>
[irakli@django conf.d]$ sudo /etc/init.d/httpd configtest
Syntax OK
</code></pre></div></div>
<h3 id="configure-firewall">Configure Firewall</h3>
<ul>
<li>
<p>sudo vi /etc/sysconfig/iptables-config and make sure following
variables are set to “yes”:<br />
IPTABLES_SAVE_ON_STOP=”yes”<br />
IPTABLES_SAVE_ON_RESTART=”yes”</p>
<p>Open Web ports:</p>
</li>
<li>sudo /sbin/iptables -I INPUT -p tcp -m state –state NEW,ESTABLISHED
–dport 80 -j ACCEPT</li>
<li>sudo /sbin/iptables -I INPUT -p tcp -m state –state NEW,ESTABLISHED
–dport 443 -j ACCEPT</li>
<li>Restart iptables with: ‘sudo /sbin/service iptables stop’ and: ‘sudo
/sbin/service iptables start’ and make sure rules are still in. Try
restarting server, too, to make sure setting picked up.</li>
</ul>
<!-- -->
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[irakli@django conf.d]$ sudo /etc/init.d/httpd restart
</code></pre></div></div>
<p>Open http://yourdomain.com you should see a Django welcome screen.</p>
<h3 id="add-startup-scripts">Add Startup Scripts</h3>
<p>These will ensure, your servers will come back up after a server reboot.</p>
<ul>
<li>sudo /sbin/chkconfig –add httpd</li>
<li>sudo /sbin/chkconfig –level 2345 httpd on</li>
<li>
<p>sudo /sbin/chkconfig –list httpd</p>
<p> </p>
</li>
<li>sudo /sbin/chkconfig –add mysqld</li>
<li>sudo /sbin/chkconfig –level 2345 mysqld on</li>
<li>
<p>sudo /sbin/chkconfig –list mysqld</p>
<p> </p>
</li>
<li>sudo /sbin/chkconfig –add postfix</li>
<li>sudo /sbin/chkconfig –level 2345 postfix on</li>
<li>sudo /sbin/chkconfig –list postfix</li>
</ul>
<p>Have fun writing Django programs!</p>
Searching Drupal Files with Ack
2009-10-08T00:00:00-04:00
http://www.freshblurbs.com/blog/2009/10/08/searching-drupal-files-ack.html
<p>Ack is a recursive grep-replacement Perl script that you can download
from: http://betterthangrep.com It is somewhat similar to “egrep”, but
is much smarter and has ten times nicer output format. It also
automatically ignores annoying .svn files and you can teach it different
file types.</p>
<p>If you are a Drupal developer you need to put the following line in your
/etc/profile:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>export ACK_OPTIONS=--type-set=php=.php,.module,.inc,.install
</code></pre></div></div>
<p>After which you can enjoy yourself some:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ack --php "check_plain"
</code></pre></div></div>
Install PHP XDebug via Pecl
2009-10-05T00:00:00-04:00
http://www.freshblurbs.com/blog/2009/10/05/install-php-xdebug-pecl.html
<p>Even though you may find xdebug in a yum repository, due to version
incompatibilities you may need to compile/install it using Pecl.
Following are several easy steps to achieve exactly that:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>> pecl install xdebug
</code></pre></div></div>
<p>check the output of the command above, if everything went well, you
should see something like :\</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Installing '/usr/lib64/php/modules/xdebug.so'
install ok: channel://pecl.php.net/xdebug-2.0.5
</code></pre></div></div>
<p>at the end of the output. Note the location of the .so file and using it
create /etc/php.d/xdebug.ini file that rads something like:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>; Enable xdebug
zend_extension="/usr/lib64/php/modules/xdebug.so"
</code></pre></div></div>
<p>If you want to use xdebug for profiling you can also add configuration
like:\</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>; profiler settings
xdebug.profiler_append=1
xdebug.profiler_enable=0
xdebug.profiler_enable_trigger=1
xdebug.profiler_output_name = cachegrind.out.%s
xdebug.profiler_output_dir=/xdebug/
</code></pre></div></div>
<p>Whenever you want to run profiler, you can change
xdebug.profiler_enable to one, but be careful not to forget it on, when
you are not profiling since it will cause each page load to produce
megabytes worth of debug output file.</p>
<p>Please also note that for profiler to run properly /xdebug/ folder must
exist and be writable by Apache process.</p>
<p>Once you are done with the installation, restart Apache and check the
PHP module list with: “php -m”, you should see “xdebug” appear in the
list.</p>
OpenPublish and Tattler (app) Webinar, Hosted by Acquia
2009-09-22T00:00:00-04:00
http://www.freshblurbs.com/blog/2009/09/22/openpublish-and-tattler-app-webinar-hosted-acquia.html
<p><a href="http://acquia.com">Acquia</a> and <a href="http://phase2technology.com">Phase2
Technology</a> will be hosting <a href="http://tattlerapp.com">Tattler
(app)</a> and
<a href="http://openpublishapp.com">OpenPublish</a>™ Webinar tomorrow Wednesday,
September 23, 2009 1:00 PM - 2:00 PM EDT.</p>
<p>To sign up visit: http://bit.ly/2nypWj</p>
While You Were Sleeping - Looking Back at Last Couple Years on the Internet
2009-09-15T00:00:00-04:00
http://www.freshblurbs.com/blog/2009/09/15/while-you-were-sleeping-looking-back-last-couple-years-internet.html
<p>=== Originally published at: <a href="http://www.agileapproach.com/blog-entry/while-you-were-sleeping">The Agile
Approach</a>
===</p>
<p>In the ’90s romantic comedy that we borrowed the title from, a chain
of dramatic events take place, while the main character (played by Peter
Gallagher) is in a post-accident coma.</p>
<p>Comatose sleep is a little too dramatic for this, but just in case you
spent the last couple of years on a beautiful island, away from the
daily strains of the everyday life in the 21st century, let us list some
of the major, latest technical advancements for you. For the
less-fortunate rest of us, who did not get to lounge on an island, this
is a chance to look back and identify new technologies that have changed
the way we live and operate, but were not around just couple of years
ago.</p>
<h3 id="twitter">Twitter</h3>
<p>Twitter took off during 2007 SXSW festival. This 140-character-limit
social messaging service revolutionized the Internet landscape by
inventing, and at the same time monopolizing, a completely new
phenomena: Micro-Blogging. The invention was so successful that it went
far beyond the initial idea and became the most effective way to share
ideas on the Web.</p>
<h3 id="linked-data">Linked Data</h3>
<p>Linked data is too technical and behind-the-scenes to receive wide
recognition, but since the invention of the World-Wide Web it is
probably the biggest change Internet has gone through. Linked data
allows presentation of data in machine-readable, “linkable� way and
linking data silos into aggregated, enriched content much like
World-Wide Web allowed linking web-pages at the dawn of the Internet.
Under different names, the idea of Linked Data (sometimes also referred
as Semantic Web) has been around for a long while, but only recently
have we seen real, practical applications of Linked Data that actually
benefit consumers. And we are just touching the tip of an iceberg, so
far.</p>
<h3 id="intelligent-apis">Intelligent APIs</h3>
<p>In the last couple years an increasing number of free web-services
emerged that provide the kind of machine intelligence that traditionally
was only available to an exclusive set of companies and only for very
large amounts of money. One of the most prominent examples of such
service is the free Open Calais API from Thomson-Reuters. Open Calais
allows machine-analysis of a free-text document and identifies named
entities in a linked data cloud. In more simple terms: it allows to
identify entities like: people, organizations, companies, as well as
events (e.g. mergers and acquisitions) and links those entities to other
sources of information which can provide more detailed information about
them (e.g. Company profile). Another important service that is clearly
emerging is Sentiment Analysis. Unfortunately, there’s no equivalent
provider that offers free, large-scale service like the one from
Thomson-Reuters, but it’s probably just a matter of time.</p>
<h3 id="url-shorteners">URL Shorteners</h3>
<p>Another old technology, re-invented and grown into maturity thanks to
different social networks, Twitter most importantly, where posting long
URLs is a problem. While most people consider short URLs just a matter
of convenience it’s much more than that. Accumulating huge databases
of cross-linked data and link usage statistics (like the one bit.ly has)
allows unprecedented ability to derive value-added statistics and
behavioral analysis. If I was going to invest money, this is where I
would invest my money, right now.</p>
<h3 id="cloud-computing">Cloud Computing.</h3>
<p>Modern Web applications process many orders of magnitude larger data
than they used to mere 2-4 years ago. Startups emerge and scale to
mind-bobbling levels in no time. All of these is possible thanks to
cloud computing and cloud computing only. While we are still learning
how to use the power of a cloud to the best, one thing is clear: future
of computing is in a “cloud� and there’s no going back.</p>
<h3 id="open-source-in-government">Open Source in Government.</h3>
<p>The administration change in White House, launch of http://recovery.gov
on Drupal and clear support of open, innovative technologies from the
new US government opens unprecedented opportunities for community
collaboration and innovation the benefits of which we, probably, can not
even fully imagine at this point.</p>
<h3 id="iphone">iPhone</h3>
<p>And last, but not least is the iPhone. Originally released on June 29,
2007, this little gadget completely changed the way we think of mobile
devices. It took the market by storm, climbing to leading position in a
highly-competitive arena and becoming a true technological phenomena,
way beyond just a gadget. It also ignited very healthy competition,
forcing stagnating mobile manufacturers to bring new devices to the
market, devices that are geared more towards real-time mobile
applications.</p>
<h2 id="whatâs-next">What’s Next?</h2>
<p>Having listed some of the major achievements of the technology in just
past couple of years, we can look forward and speculate on what’s to
come. Speculate, because with the speed things change – nobody really
knows. However, one trend is quite obvious – Web and technology at
large is becoming increasingly real-time. It’s safe to assume that
that’s where most of the new innovation will be concentrated – being
more mobile and more real-time. It will also make life more hyper and
intense, of course, which makes us wish it was us departing to a quiet
island for two years and coming back in two years to read somebody
else’s While You Were Sleeping blog post.</p>
Unix Shell Programming and Broken Symlinks
2009-09-11T00:00:00-04:00
http://www.freshblurbs.com/blog/2009/09/11/unix-shell-programming-and-broken-symlinks.html
<p>The well-known approach for checking whether path exists, in Unix, is:
“if [ -e $path ]” condition. However, contrary to popular belief, “-e”
does not always work. The “-e” check works for folders, files etc with
one exception: if there’s a broken symlink on the path, it won’t
recognize that. Which makes sense: broken symlink is not a valid path.
However, if you are writing some kind of cleanup code, you do want to be
able to check on broken links, as well. To achieve that, you need to add
extra condition:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>if [[ -e $filepath || -L $filepath ]]; then
echo "There's something at: $filepath"
fi
</code></pre></div></div>
Drupal Can Be Very Pretty
2009-08-28T00:00:00-04:00
http://www.freshblurbs.com/blog/2009/08/28/drupal-can-be-very-pretty.html
<p>There has been increasing amount of complain about how Drupal is ugly or
not designer friendly yadda, yadda, yadda. Well, sure - it’s not
WordPress, because it is much more complex and used for building much
more complex websites. Neither do I, personally, think should it try to
copy WordPress. Whilst there’s always room for improvement, Drupal and
WordPress have very distinct niche areas that each should strive in and
not try to compete with each other.</p>
<p>But, for the skeptics that think Drupal is just Garland, check out the
new, shiny, semantically powered The New Republic
[<a href="http://tnr.com">http://www.tnr.com/</a>] website built using the
<a href="http://openpublishapp.com">OpenPublish</a> distribution of
<a href="http://drupal.org">Drupal</a>. And it was built in a matter of couple
months with a small team and without any crazy work hours.</p>
<p>Drupal is awesome and Drupal can be pretty.</p>
Preview an SVN Update
2009-08-25T00:00:00-04:00
http://www.freshblurbs.com/blog/2009/08/25/preview-svn-update.html
<p>Since “svn update” is a subset of “svn merge” you can use something
like:\</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>svn merge --dry-run -r BASE:HEAD .
</code></pre></div></div>
<p>(Source: http://translocator.ws/2005/10/12/svn-update-dry-run)</p>
<p>The only downside is that ‘svn merge’ does not quite work like ‘svn
update’ in the sense that you can not run ‘svn merge’ from outside the
workspace. E.g. if I have several workspaces under /tmp/irakli:
/tmp/irakli/one and /tmp/irakli/two, I can run:\</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cd /tmp/
svn update irakli/one
</code></pre></div></div>
<p>whereas /tmp is not a workspace. We can not do the same with svn merge.</p>
Your First jQuery Plugin
2009-07-13T00:00:00-04:00
http://www.freshblurbs.com/blog/2009/07/13/your-first-jquery-plugin.html
<p>We all have come to love and admire <a href="http://jquery.com">jQuery</a> for the
amazing Javascript library it is. But we also have fallen in love with
numerous extensions to jQuery; plugins, modules - whatever you call ‘em.
Most of us, however, just use these goodies and bless the hearts of all
wonderful people who make the gems available. Some of us are even a
little bit intimidated when we look at all the complicated
Javascript-ing going on in the source files… Especially when/if we
accidentally look into a minified version ;)</p>
<p>Jokes aside, starting a new jQuery plugin is quite simple. Here is just
how easy one could be:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(function($) {
// jQuery plugin initialization
$.fn.irakli = function(conf) {
alert("okaaaay");
};
})(jQuery);
</code></pre></div></div>
<p>This goofy plugin will allow you to invoke irakli() function on a jQuery
object. For instance, $(‘div.something’).irakli() will have an alert
box pop up.</p>
iChat 4 Does Not Display Text Messages Problem
2009-07-04T00:00:00-04:00
http://www.freshblurbs.com/blog/2009/07/04/ichat-4-does-not-display-text-messages-problem.html
<p>Turn on:<br />
Preferences -> Messages -> Collect chats into a single window</p>
<p>and restart iChat.</p>
<p>The problem should go away.</p>
'More' Link's URL for a Block Display in Drupal6 Views2
2009-06-25T00:00:00-04:00
http://www.freshblurbs.com/blog/2009/06/25/more-links-url-block-display-drupal6-views2.html
<p>It is only available in the top-level theme as a variable, but in case
you need to derive the same value from the View object, per se, here it
is:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$view->display[$view->current_display]->handler->get_path();
</code></pre></div></div>
Replace a Function Name in Drupal Source Files
2009-06-05T00:00:00-04:00
http://www.freshblurbs.com/blog/2009/06/05/replace-function-name-drupal-source-files.html
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>> perl -i -pe 's/oldname_/newname_/g' `find | grep "\.module$"`
</code></pre></div></div>
<p>Or if you want to first check the results:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>> perl -pi.bak -e 's/oldname_/newname_/g' `find | grep "\.module$"`
</code></pre></div></div>
<p>which will create backup of original files. Those you can delete later
with:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>> find . -name "*.bak" -exec rm -rf {} \;
</code></pre></div></div>
<p>You can replace “.module” with “.inc” or “tpl\.php” if you also need
those processed</p>
SVN: Restore Deleted Folder from a Revision
2009-06-01T00:00:00-04:00
http://www.freshblurbs.com/blog/2009/06/01/svn-restore-deleted-folder-revision.html
<p>Imagine a situation: you accidentally “svn removed” an entire directory
tree from SVN. If the tree contained uncommitted code you can restore it
from the backup, but you also need to restore things that were in the
SVN. You can approach it multiple ways, but arguably the cleanest way is
to simply revert to the revision before the deletion.</p>
<p>How do you do that in Subversion? The answer to this is quite short, but
not necessarily obvious, so following is the list of example commands:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>svn co -N SVN_PARENT_URL .
svn copy SVN_URL@REV FOLDERNAME
(Add-in or modify here any files that were not committed, before deletion)
svn commit -m "restoring" FOLDERNAME
</code></pre></div></div>
<p>example:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>svn co -N https://svn.ex.com/repo/project/parentfolder@7537 .
svn copy https://svn.ex.com/repo/project/parentfolder/deletedfoldername@7537 deletedfoldername
(Add-in or modify here any files that were not committed, before deletion)
svn commit -m "restoring" deletedfoldername
</code></pre></div></div>
Bing it on, Google! Microsoft is Back!
2009-06-01T00:00:00-04:00
http://www.freshblurbs.com/blog/2009/06/01/bing-it-google-microsoft-back.html
<p>People who know me know that I am the last person on earth to be a
Microsoft fan. I have my reasons to be a tough critic of the Redmond
company, but something that I did not expect to happen, has happened
recently and giving well-deserved credit to them is due. The name is
<a href="Bing">Bing</a> and it launched today. It’s absolutely AWESOME! I won’t
bore you with a description of what Bing is. You most probably already
know it, but what you are about to find (on Bing, not on this blog :) )
is a truly new way to experience Web. It’s not about just a search
engine, anymore, it’s the entire decision-making experience that
matters.</p>
<p>Microsoft folks are right-on in their marketing: Bing is NOT a search
engine, it’s a “decision engine”. Brilliant! Absolutely brilliant!</p>
<p>Stan Schroeder of <a href="http://Mashable.com">Mashable</a>
<a href="http://mashable.com/2009/06/01/bing-opens-up-live/">wrote</a> this
morning: “Bing Opens Up. It’s Live.com, Wrapped In a Prettier Box.”
Sorry Stan, I don’t know why you would say such thing, but I have to
respectively disagree and say: “Bing could not be further from live.com
or anything that existed before it, for that matter”. It is NOT just a
wrap around an old engine. The engine is new and fantastic!</p>
<p>Quick test: try searching for “usb flash 64GB” in google.com (just the
straight search box, not any subsite) and then on bing.com (same here:
main search box, not the shopping section) and just compare the results.
Bing understands what I want to see and gives me very nice tools to
quickly narrow-down results. Google is as naivly narrow-minded as it was
10 years ago, it’s just that world is not the same as it was 10 years
ago. Hello there, in Mountan View, is anybody home? We are in 2009, wake
up!</p>
<p>Bing is big. No Bing is huge and all of this is extremely exciting
because finally we are going to see some real competition in the area of
global IT that matters probably the most: access to information. Quick.
Intelligent. Efficient.</p>
<p>I hope Google will get its act together and respond with something
equally impressive. Until then - I got a big supply of popcorn and soda,
am sitting back, watching and having fun. Show is on!</p>
<p>P.S. Since the two were announced together and are kindof kept being
compared to each other all the time, we can’t help mentioning Google
Wave.</p>
<p>So, about Wave: it’s a wonderful piece of engineering and a great
example of out-of-the-box thinking. However, for an average consumer it
has no value, yet. And as much as we’d like to think so, majority of
earth population is not constituted by geeks :) It is also very
community-based (vs. search engines which are personal tools). In social
tools, it’s never just about the technology and a complex overly
“intelligent” technology can sometimes be a drawback rather than
benefit. Social tools are about communities. If the communities see no
value - even the most brilliant technology will just go unnoticed.
Google has been very unsuccessful in raising communities. Poor adoption
of Knol and Orcut are good examples, to name a few.</p>
<p>So Wave? Maybe. But Bing - oh yeah!</p>
Sane Backtrace in PHP
2009-05-27T00:00:00-04:00
http://www.freshblurbs.com/blog/2009/05/27/sane-backtrace-php.html
<p>PHP error messages are quite helpful, most of the time. Sometimes they
do fall short of telling us what went wrong, however. It’s especially
common when and if you use a development framework (e.g. Drupal).
Frameworks often do output buffering and/or code eval()-ing, making
debugger output incomprehensible.</p>
<p>In such cases PHP’s <a href="http://php.net/debug_backtrace">debug_backtrace()</a>
function is a real savior. debug_backtrace() is also very helpful if
you want to look at the execution stack in a complicated code, to better
understand the code. This function shows the execution stack that lead
to the current function and does it pretty well… “too well” sometimes
:) Out-of-the-box version of the function shows the list of invoked
functions, source files they belong to, line numbers in the source file
and the argument values being passed. The latter can be a huge problem,
if code is passing around large variables. Output on the screen may get
so garbled (esp. if HTML is used in variables) that the entire exercise
may lose its meaning.</p>
<p>Short snippet below sanitizes debug_backtrace() output to make it
slimmer and more comprehensible:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$trace = debug_backtrace();
foreach ($trace as &$t) {
unset($t['args']);
}
echo "<pre>".print_r ( $trace,true)."</pre>";
exit();
</code></pre></div></div>
How to Enable Local SMTP (Postfix) on OS-X Leopard
2009-05-10T00:00:00-04:00
http://www.freshblurbs.com/blog/2009/05/10/how-enable-local-smtp-postfix-os-x-leopard.html
<p>OS-X Leopard comes pre-installed with a Postfix version. No need to
install it via darwin ports or other such mess (actually uninstall it if
you have previously manually installed it via ports or something
similar). Postfix just needs to be enabled and following sequence of
several easy steps explains how to do it:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> sudo vi /System/Library/LaunchDaemons/org.postfix.master.plist
</code></pre></div></div>
<p>add following line before the closing </dict> tag:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><key>RunAtLoad</key> <true/> <key>KeepAlive</key> <true/>
</code></pre></div></div>
<p>Start service with</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo launchctl
launchd% start org.postfix.master
</code></pre></div></div>
<p>You can also start simply with “sudo postfix start” but the above
command will start via launch sequence and test the configuration you
edited in the previous step.</p>
<p>Check that SMPT is running:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>telnet localhost 25
</code></pre></div></div>
<p>For more information, see: <a href="http://developer.apple.com/documentation/Darwin/Reference/ManPages/man5/launchd.plist.5.html">Mac OS X Manual Page For
launchd.plist</a></p>
Drupal: Fatal error: Unsupported operand types in
2009-04-28T00:00:00-04:00
http://www.freshblurbs.com/blog/2009/04/28/drupal-fatal-error-unsupported-operand-types.html
<p>If you have misfortune of having to upgrade Drupal5 website to Drupal6,
there’s a very good chance that at some point you will run into a fatal
error:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Fatal error: Unsupported operand types in...
</code></pre></div></div>
<p>Fatal errors are never fun, but this one is particularly annoying and
hard to hunt down. It helps to understand the cause of the problem,
thought. Basically, the main problem is that Drupal url() and l()
functions have changed their signatures in a major way. Function
operands that used to be literals are supposed to be an array now.</p>
<h4 id="solution">Solution</h4>
<p>You need to hunt-down all url() and l() functions and change their
signature to Drupal6-compliant format. The functions can be used (and
causing problem from) multiple locations: a tpl.php file, a module file
or a code in a block in the database! This last one is particularly
troublesome to hunt down and can cause the most problem. We suggest
disabling all blocks for the time of upgrade by running:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>UPDATE blocks set status=0
</code></pre></div></div>
<p>Also, to find which function causes the problem. open
includes/common.inc and at the begining of url() and l() function
definitions paste following code:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>if (!is_array($options)) {
echo "<pre>";
$backtrace = debug_backtrace();
var_export($backtrace);
exit();
}
</code></pre></div></div>
<p>Typically first function call in the backtrace is the offender function.</p>
Teaching Espresso Drupal PHP file Extensions (e.g. .module)
2009-04-23T00:00:00-04:00
http://www.freshblurbs.com/blog/2009/04/23/teaching-espresso-drupal-php-file-extensions-e-g-module.html
<p><strong>UPDATE:</strong> instructions for Espresso 2.0 at:
http://freshblurbs.com/espresso-and-syntax-highlight-custom-file-formats</p>
<p><a href="http://macrabbit.com/espresso/">Espresso</a> From MacRabbit (you may
remember them for their splendid CSSEdit eidtor) is a new Web editor,
for Macs, worth paying attention to. It handles the usual suspects: PHP,
CSS, HTML, servers over SFTP, Amazon S3 etc with style out of the box
and has numerous extensions for other things like Python, LUA, SQL,
Regular Expressions etc. And it’s only 1.x version, so you bet you can
expect much more in coming versions.</p>
<p>One little shortcoming it had, for Drupal developers is that, there’s no
easy way to configure custom-for-Drupal PHP extensions: .module and
.install to make Espresso recognize these as PHP files.</p>
<p>Joe Shindelar of <a href="http://dreamformula.com">Dreamformula</a> has posted a
nice <a href="http://bmu.li/sMh">blog post</a> detailing the configuration of
custom PHP extensions in Espresso.</p>
<p>Thank you, Joe!</p>
Announcing: World Bank Open API 2.0
2009-04-10T00:00:00-04:00
http://www.freshblurbs.com/blog/2009/04/10/announcing-world-bank-open-api-2-0.html
<p>Blog post about the new <a href="http://developer.worldbank.org">World Bank API</a>, how we designed it, why we are
excited about it and why you could be, too:
<a href="http://www.agileapproach.com/blog-entry/world-bank-api-20-launch">http://www.agileapproach.com/blog-entry/world-bank-api-20-launch</a></p>
Solving Doxygen Troubles With Drupal.
2009-04-08T00:00:00-04:00
http://www.freshblurbs.com/blog/2009/04/08/solving-doxygen-troubles-drupal.html
<p>Drupal requires its source documentation to be <a href="http://drupal.org/node/1354">compatible with
DoxyGen</a>. If you are working on a large
project, you want to install DoxyGen and run it on cron to have nice,
up-to-date API docs.</p>
<p>Unfortunatley, if you install Doxygen via yum (or any other
auto-updater, I assume) it installs a fairly old 1.4.x branch that is
incompatible with Drupal. Specifically, it completely ignores the
.module and .install files and has poor support for .inc, from what I
can tell. That’s because Doxygen does not realize these are PHP source
files.</p>
<p>What you want to do is to install the latest Doxygen release (1.5.8 at
the time of this writing). In the new version, the author of Doxygen has
generously added a configuration tag that allows mapping of arbitrary
file extensions with language types. The setting you need in your
doxygen configuration file is:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>EXTENSION_MAPPING = module=PHP install=PHP inc=PHP
</code></pre></div></div>
Drupal Selector FAPI Element
2009-04-06T00:00:00-04:00
http://www.freshblurbs.com/blog/2009/04/06/drupal-selector-fapi-element.html
<p>A really nice extension to Drupal Forms API has been released over the
weekend: <a href="http://drupal.org/project/selector_element">Selector Element</a>
module introduces the hip awesomeness of jQueryUI Sortable widget to
Drupal’s Forms API in a very easy way.</p>
<p>If you are using Drupal and wanted to quickly implement one of those
drag-n-drop-n-sort selectors - you found a perfect module for yourself.</p>
<p>I have no doubt I will be using this new element a lot, myself.</p>
Installing Webmin Securely with SSL on CentOS 5.2
2009-03-22T00:00:00-04:00
http://www.freshblurbs.com/blog/2009/03/22/installing-webmin-securely-ssl-centos-5-2.html
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># yum install openssl
# yum install openssl-devel
# yum install perl
# yum install perl-Net-SSLeay perl-Crypt-SSLeay
# rpm --import http://www.webmin.com/jcameron-key.asc
</code></pre></div></div>
<p>Create the /etc/yum.repos.d/webmin.repo file containing :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[webmin]
name=Webmin Distribution Neutral
baseurl=http://download.webmin.com/download/yum
enabled=0
</code></pre></div></div>
<p>Then run:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># yum --enablerepo=webmin install webmin
</code></pre></div></div>
<p>Check installation success with:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/etc/init.d/webmin status
</code></pre></div></div>
<p>If everything is good and webmin is running access it via:<br />
https://yourdomain.com:10000/</p>
TED: MIT Media Lab Unveils the Future of Mobility
2009-03-16T00:00:00-04:00
http://www.freshblurbs.com/blog/2009/03/16/ted-mit-media-lab-unveils-future-mobility.html
<p>Pattie Maes & Pranav Mistry: Unveiling the “Sixth Sense,” game-changing
wearable tech</p>
Drupal: 'Views2 Returns Zero Results but SQL Is Fine' Problem
2009-03-03T00:00:00-05:00
http://www.freshblurbs.com/blog/2009/03/03/drupal-views2-returns-zero-results-sql-fine-problem.html
<p>This has happened couple times, already, so I may as well blog about it.
If you use Views in Drupal, you already know that it shows you the final
SQL generated. Very useful feature, but there’s a rare edge condition
when the SQL returns results (if you run it from an SQL client), but
Views shows zero elements. Extremely frustrating and confusing.</p>
<p>How can this happen?</p>
<p>The thing is, Views omits limit condition when displaying the SQL, so
when you copy/paste your SQL in a client you are not running exactly the
thing that Views displays.</p>
<p>Solution: check the pagination setting in the View settings. Most of the
time the problem is an offset value indicated that is higher than number
of elements in the result-set.</p>
Control Your OS-X Keynote Presentation from iPhone
2009-02-24T00:00:00-05:00
http://www.freshblurbs.com/blog/2009/02/24/control-your-os-x-keynote-presentation-iphone.html
<p>If you are on a Wifi and both your mac and iPhone can access it, you can
get free ride with controlling Keynote from your iPhone by using:
<a href="http://manas.tungare.name/software/keymote/">Keymote</a>, which in part
uses <a href="http://code.google.com/p/telekinesis/downloads/list">Telekinesis
iPhoneRemote</a>.</p>
<p>Telekinesis actually uses iPhone Safari and Ajax so you need to point
iPhone Safari to a specific address (https://192.168.74.104:5010/ by
default). You can bookmark it as iPhone shortcut on iPhone desktop
though, for easy launching.</p>
Tagipedia - a Wikipedia for Tags?
2009-02-19T00:00:00-05:00
http://www.freshblurbs.com/blog/2009/02/19/tagipedia-wikipedia-tags.html
<p>Thinking about Semantic Web, crowdsourcing and mostly after reading a
recent blog post from
<a href="http://www.agileapproach.com/blog-entry/tagging-why-we-use-it-and-where-its-going">Andy</a>
I came to believe that we need a ‘Tagipedia’ (Wikipedia for tags): a
place where anybody can tag any uniquely identified web resource (URL)
and thus gradually, collaboratively describe the entire Web in more
semantically sensible way.</p>
<p>Ironically, large social-bookmarking services (e.g. del.icio.us) have
enough data to start something like that, but they have not exposed it
in a meaningful way, yet. What we really need is an API call that would
return top 10 (or 20) most common tags, across all users for a specific
URL. Given that all kinds of widgets can be built, including
browser-extensions.</p>
<p>Del.icio.us, where art thou? Can you hear us?</p>
Professional (Software) Certifications Are Lame
2009-02-19T00:00:00-05:00
http://www.freshblurbs.com/blog/2009/02/19/professional-software-certifications-are-lame.html
<p>I’ve been saying this off the record for a long time and finally I am
frustrated enough to go on the record and say it out loud and without a
shred of fear: professional certification, in software, is lame, means
nothing at all and is a waste of everybody’s time except companies that
make money off of it.</p>
<p>Why? Because I personally know a number of Oracle-certified DBAs that
can not even install Oracle on Linux. Which may be saying something
about Oracle DB, too, but says a lot about the value of a certificate,
as well. I’ve known equally large number of Sun-certified engineers that
should not be let anywhere near writing code, in any language, Java
included. And last, but not least because anybody can pass most software
certifications, by wasting time on memorizing meaningless answers to
meaningless questions from a textbook and it means absolutely nothing.
What it means to me, actually, is that somebody lacked interest in
coding enough to waste time on memorizing, rather than developing his
actual programming skills. And that is not good.</p>
<p>Software engineering is tough. Correction: it is really tough. It’s a
field where things change overnight, new frameworks emerge, the breadth
of the knowledge required is immense and being out of the loop for even
6 months (hell, 3 month) can make even a subject-field expert’s
knowledge obsolete.</p>
<p>How can anybody put up with such pressure? The only answer is - passion.
You can not be a programmer worth a dime if you do not have absolute
passion for what you are doing. If you do not get craving for writing
code, if you have never broken nights working on a challenging code,
just because you could not stop, and not because there was a deadline or
a project manager standing behind your back - you do not have a
programmer’s soul and you are wasting everybody’s time.</p>
<p>When I interview for an engineering position, aside from basic
knowledge, I look for two immensely important things: passion (drive,
motivation, initiative - whatever you call it) and attention to detail.
If you have basics right, senior developers and colleagues can teach you
the craft, or at least help you polish it, but if you do not have the
drive and passion, if you are not attentive to details - you will never
make a decent developer. Just like in, probably, many other professions,
there’re certain character traits that are just necessary for the
profession of a software engineer.</p>
<p>Can a bullet-pointed listing of 100 questions tell me if a person is
motivated and curious? Can it tell me if he or she is methodical and
detail-oriented? No. It can not. Therefore, when I see a list of
certifications on a resume, I simply ignore it. If I would have to take
it into account, I would probably consider it as something negative,
since somebody clearly wasted their time, but that is not fair, as well</p>
<ul>
<li>realistically given the pressure form the industry, I can see why a
young professional could make such mistake. But do not expect any points
from me for a “certification”.</li>
</ul>
<p>I am equally critical of the companies that do pay attention to
certification or even require them. The only way to really see how
somebody thinks is to observe the process and see past work. To that
extent, anybody who can show me code that they have written gets a +1
point from me (which can be dropped if the code is horrible :) ). If you
blog - show me your blog and I can see how your thinking has been
evolving over time. Hopefully the blog will have some original thinking
and not just copy/pasted things from all over the Internet. And finally,
maybe even most importantly - I like to give a short challenge problem
and see how a person solves it in real time. I would give them 15-20
minutes to think about it, prying over them is unfair, but watching how
they present the solution and explain the thinking process is priceless.
Especially valuable are problems where there is not a “right” or “wrong”
answer, but you can observe problem-solving in action.</p>
<p>In any case, different people have different techniques and that’s why
the best companies always interview candidates with several employees,
to get different perspectives, but one thing remains rock-solid:
certifications are lame and all they do is try to commoditize
creativity, which is a real shame, in my humble opinion.</p>
Upgrading Subversion to 1.5 on CentOS 5.2 Using Yum
2009-02-18T00:00:00-05:00
http://www.freshblurbs.com/blog/2009/02/18/upgrading-subversion-1-5-centos-5-2-using-yum.html
<p>Default CentOS 5.2 yum repositories are still on Sybversion 1.4.x
branch, so if you need the latest Subversion client, you are out of
luck… or not, if you read this blog post :) This quick tutorial will
show you how to upgrade in less than 5 minutes.</p>
<p>We will use RPMForge repos for the upgrade.</p>
<p>Download and install proper RPMForge repo RPM for your server
architecture (64bit or 32bit) from <a href="http://wiki.centos.org/AdditionalResources/Repositories/RPMForge?action=show&redirect=Repositories%2FRPMForge#head-20e1f65f19ccf2f5fbf5adb30dbaf5ea963a64ae">RPMForge
website</a>.</p>
<p>Edit /etc/yum.repos.d/rpmforge.repo and change</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>enabled=1
</code></pre></div></div>
<p>to “0”. We do not want this repo to be enabled by default, because an
accidental “svn update” will update all your packages to bleeding-edge,
test-quality versions. RPMForge has many experimental rpms.</p>
<p>Run:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>yum --enablerepo=rpmforge check-update subversion
</code></pre></div></div>
<p>and make sure the version of subversion you are looking for is
available. It should show you something like:\</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rpmforge 100% |=========================| 1.1 kB 00:00
subversion.x86_64 1.5.5-0.1.el5.rf rpmforge
</code></pre></div></div>
<p>Check for existing subversion clients:\</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># rpm -qa | grep -i subversion
subversion-1.4.2-2.el5
subversion-1.4.2-2.el5
</code></pre></div></div>
<p>Apparently there’re two rpms installed (happens sometimes) so we need to
add special flag to rpm -evf to safely remove it:\</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rpm -evf --allmatches subversion-1.4.2-2.el5
</code></pre></div></div>
<p>Obviously, in your case there may not be previous installation or the
version may be different.</p>
<p>Run install:\</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>yum --enablerepo=rpmforge --disablerepo=base install subversion
</code></pre></div></div>
<p>Please note that we are enabling rpmforge repo and disabling “base” repo
that has 1.4.x version of Subversion, since yum would try to install it,
as well. If yum finds other repos with 1.4.x, you may need to disable
them as well.</p>
<p>cheers</p>
Peer1 - Website Redesign
2009-02-09T00:00:00-05:00
http://www.freshblurbs.com/blog/2009/02/09/peer1-website-redesign.html
<p><a href="http://www.peer1.com">Pee1</a>’s new website design is a great example of
modern, user-centric, ergonomic design. Professional, yet fun, easy to
navigate, stunningly beautiful and appealing, it inspires the emotions
of trust, reliability, feeling of cutting-edge. Combine that with the
promise of 100% network SLA and 24/7/365 support, plus different
marketing messages cleverly spread-out across different pages and you
get a website that immediately grabs user’s attention.</p>
<p>I just wish they provided more modern services like virtual servers,
server clouds and distributed CDN. Service packages from last century do
not go well with the design of the future. Hopefully, in time, they will
re-think and update business strategy, as well.</p>
CVS Status Like the One in SVN - Bash Script
2009-02-08T00:00:00-05:00
http://www.freshblurbs.com/blog/2009/02/08/cvs-status-one-svn-bash-script.html
<p>Yeah, I know - CVS is an archaic mess and there’s not a single reason in
the entire world to be using it in 2009… except if you are a Drupal
contributor and need to maintain a module (or contribute to one) on
drupal.org. For reasons that are complicated and don’t matter to this
blog post, Drupal uses CVS and there’s no word that it will switch to
something decent like SVN (git users - stay quiet), any time soon.</p>
<p>Fine, but when you actively use a version control, you need to be able
to quickly see modified files. Files that need to be added or committed
to version control. If you use a GUI CVS client - fine, but I don’t. I
do most of my development on remote Linux servers and command-line is my
only cvs tool. Now that can get tricky in many ways. One of the ways is
‘cvs status’ command.</p>
<p>For reasons that I will never understand, CVS authors decided to show
status of all files when you run this command over a directory. Plus
they show 5 lines of information for each file. In the end - you can’t
see anything, if you are just looking for the names of modified files.
Classic case of “less is more” (by the way - fixed in SVN, the improved
CVS).</p>
<p>To emulate the behaviour of “svn status” that just shows a list of
modified and new files, I wrote a quick bash script that hopefully
somebody else, unlucky enough to be stuck with CVS, may find useful, as
well:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>#!/bin/sh
patterns=(
'?'
'Locally Added'
'Locally Modified'
)
for i in "${patterns[@]}"
do
cvs -Q status -R . | grep -i "$i"
done
</code></pre></div></div>
Twitter Unleashed - How Its Message is Misleading And Why You'd Love It
2009-02-06T00:00:00-05:00
http://www.freshblurbs.com/blog/2009/02/06/twitter-unleashed-how-its-message-misleading-and-why-youd-love-it.html
<p><a href="http://twitter.com">Twitter</a> is one of the tech wonders that really
took off last year. According to <a href="http://compete.com">Compete.com</a>
number of unique visitors to Twitter has <a href="http://siteanalytics.compete.com/twitter.com/?metric=uv">increased almost 10
times</a> from Dec
‘07 to Dec ‘08. If we also account for the fact that most Twitter users
use it from desktop applications that are not easy to track, the actual
usage numbers are probably even more impressive. No doubt, that’s a
mind-bobbling success for any Web-based business.</p>
<p>But what is Twitter? The Twitter website describes itself as follows:</p>
<p>Twitter is a service for friends, family, and co–workers to
communicate and stay connected through the exchange of quick, frequent
answers to one simple question: <strong>What are you doing?</strong></p>
<p>Now, that <strong>does not sound too interesting</strong>. Let’s be honest: most
people don’t do anything worth announcing across the world. Unless you
are some kind of serious travel-addict or a wild celebrity of sorts,
which most of us, are not. Who wants to read meaningless messages like:
“Went out to get some food from McDonalds. Recession, indeed” from
dozens of people?</p>
<h3 id="then-why-do-millions-of-people-use-twitter">Then why do millions of people use Twitter?</h3>
<p>Because Twitter simply is not what it says it is. We’ve
<a href="http://www.freshblurbs.com/web-business-all-about-users">blogged</a> about
how social networks have an interesting characteristics of evolving
themselves way beyond the initial idea. Once you have sufficient number
(the “critical mass”) of users, the social network becomes a living,
breathing creature that can decide its fate on its own. That is exactly
the case of Twitter.</p>
<p>Twitter is interesting, because people who are interesting on Twitter do
not answer the question of “What are you doing”? They answer a much more
important question of <strong>“What are you thinking about [right now]?”</strong>
Now, that can be incomparably more interesting. Whilst what we
physically do is limited, and we don’t usually do anything too exciting,
what we can think about is limitless and full of creativity (well,
sometimes).</p>
<p>Twitter is successful, because its users found out that instead of
treating it as a tool for satisfying selfish (some would say:
adolescent) need of announcing meaningless, personal activities, it
could be used for something that later became known as Microblogging.</p>
<p>Microblogging is a combination of quickly dumping short (limited to 140
characters) thoughts and observations, plus sharing links to interesting
web-pages you stumble upon, with like-minded people all over the Web.
The “like-minded people” is the key in successfully using Twitter to its
potential. You want to “follow” people who are interested and
researching the same kinds of things you are, not necessarily - your
friends. In this Twitter can be very different from Facebook.</p>
<p>Choose very carefully who you are following on Twitter and start
building a meaningful list of followers - you will quickly come to love
it.</p>
ACL or Rules-Based Security for Drupal?
2009-02-06T00:00:00-05:00
http://www.freshblurbs.com/blog/2009/02/06/acl-or-rules-based-security-drupal.html
<p>Joomla has announced availability of new ACL: http://is.gd/iA5B and they
seem pretty excited about it. Is that something for Drupal community to
be jealous of?</p>
<p>If you come from a Java/J2EE background the clear answer is: NO (yes, in
capital letters). You have to actually suffer from a structured, strict
ACL to really appreciate the simplicity of a security system like that
of Drupal.</p>
<p>Now, you may argue that Drupal security is slightly over-simplistic and
too code-oriented (makes us, the developers happy) for “business” use.</p>
<p>OK, but it does not have to be a “hierarchical ACL” or strings-based
security. A flexible, rules-based security system may be the answer?</p>
<p>Zed Shaw, of the RoR world, has some very interesting things to say on
the subject:<br />
http://vimeo.com/2723800</p>
Web Business Is All About Users
2009-01-27T00:00:00-05:00
http://www.freshblurbs.com/blog/2009/01/27/web-business-all-about-users.html
<h3 id="king-is-dead-long-live-the-king">King is dead, long live the King!</h3>
<p>The trademark of the Web: “Content is king” is dying away. In the end,
Web is business and business needs to make money. With the emergence of
so many, high-quality, free-content resources, few people want to pay
for content on the Net; even if they do - it’s for niche and limited
content. By large, the money on the Net is in advertising, exclusively.
To get any advertising money you obviously need users and the size of
the audience you can reach directly resonates with the ad revenue.</p>
<p>It is not about content, anymore!</p>
<p>The mind-bobbling success of online services with limited original
content such as micro-blogging (Twitter) and social rating (Digg) prove
that it’s not about content. Content is not #1 even on Facebook - it’s
the interaction that brings people to Facebook, not some magic content
they are looking for. Let’s face it: most of the content on Facebook is
pretty goofy.</p>
<p>Speaking in grossly generalized terms, successful sites on the Web
become popular for two main reasons: either they are very useful and
fill some need, or there’re way too many people on the site to avoid it.
Large user base creates a social power: just because there are so many
people on the website, and somebody can contact them (either textually
or through applications as in case of Facebook) - it instantly becomes a
marketplace.</p>
<p>One, less explored characteristic of the Social Web is that - once you
have a large user-base, it becomes less important what brought these
users together. You need to open proper channels between them and the
crowd can mold itself into many interesting things, some of which may
have little to do with the original idea.</p>
<p>If you have read this blog post this far and are thinking “So? What’s
new”. Well, nothing is, but next time you work on a website, make sure
you pay as much attention to pure user experience as you usually pay to
content and its presentation (which is not the same as user experience).</p>
WFP.ORG Launches on Drupal
2009-01-23T00:00:00-05:00
http://www.freshblurbs.com/blog/2009/01/23/wfp-org-launches-drupal.html
<p>The official website of the United Nation’s World Food Programme has
launched its new, redesigned and re-engineered website, today, in beta
mode: http://beta.wfp.org. The website is now driven by Drupal (woohoo!)
and looks pretty cool - a word rarely used in regards with the websites
of large, non-profit, international organizations.</p>
<p>We’d like to congratulate everybody who worked hard to make this
possible. The team at <a href="http://phase2technology.com">Phase2 Technology</a>
who worked around the clock to make it a reality in Drupal and made sure
the website performs well under high traffic loads. The awesome team at
<a href="http://developmentseed.org">The Development Seed</a> who made the website
look so stylish, engaging and easy to browse. And of course
<a href="http://wfp.org">wfp.org</a> staff, itself, who were the masterminds and
have managed the process brilliantly. A special gratitude goes to
<a href="http://personomies.com">Pierre Guillaume Wielezynski</a> for evangelizing
open-source and Drupal in the highest levels of the international
non-profit world.</p>
<p>From me personally: I have to admit that there was something especially
gratifying to work on this site, realizing just how much impact World
Food Programme has and how crucial and courageous is what they do.</p>
Drupal: Expose a Custom Field to Views2
2009-01-23T00:00:00-05:00
http://www.freshblurbs.com/blog/2009/01/23/drupal-expose-custom-field-views2.html
<p><strong>Disclaimer:</strong> Views2 Advanced Help contains a more detailed and
comprehensive documentation on the same subject. However, that also
means that you have to actually comprehend more :) This is just a quick
sample code of one usage of the hook_views_data() to expose custom
fields from a custom table to Views2. If you need more advanced
functionality, do refer to Views2 documentation.</p>
<p>Let’s say we are building a small job posting board and, for whatever
reason, decided to store all resume-related extra fields in a table
called “resume”, instead of using CCK. Now we need to expose those
fields to Views, to use all the beauty and flexibility of the automated
query generation provided by Views.</p>
<p>Let’s write a custom module called resume (or add it to an existing
module).</p>
<p>The very first thing you need to do when you implement Views hooks is to
tell Views that you are doing so and (optionally) - where your inc file
will rely that holds all views hook implementation routines. We do that
using hook_views_api(). Assuming your module is called “resume” and
that you want to put views hook implementation file in the “views”
subfolder:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>function resume_views_api() {
return array(
'api' => 2,
'path' =>
drupal_get_path('module', 'resume') . '/views',
);
}
</code></pre></div></div>
<p>If you omit the “path” argument, you will have to create the
modulename.views.inc file in the root folder of your module (or
“includes” subfolder). If you do indicate path - you create it on that
path.</p>
<p>Let’s create resume.views.inc file (under the “views” fubfolder of the
resume module’s folder, in our case) and enter following code in it:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><?php
function resume_views_data() {
$data['resume'] = array(
'table' => array(
'group' => 'Resume',
'title' => 'skills',
'join' => array(
'node' => array(
'left_field' => 'nid',
'field' => 'nid',
),
),
),
'skills' => array(
'title' => t('Skills'),
'help' => t('Applicant Skills.'), // The help that appears on the UI,
// Information for displaying the nid
'field' => array(
'handler' => 'views_handler_field_node',
'click sortable' => TRUE,
),
),
);
return $data;
}
</code></pre></div></div>
<p>this will expose a property called “skills” from the “resume table” as a
proper Views2 field that can be used in the Views queries.</p>
<p>That’s it. You just created your first custom Views2 field!</p>
<p>Again, Views2 has more flexibility in the hook_views_data() hook, then
shown here. Do refer to the documentation (Advanced Help) if you need
more.</p>
XAMPP Runs As User Nobody on Mac
2009-01-08T00:00:00-05:00
http://www.freshblurbs.com/blog/2009/01/08/xampp-runs-user-nobody-mac.html
<p>During my recent macbook pro upgrade, I had a sweet time automatically
migrating my entire old macbook to the new one using Migration
Assistant. The experience could not have been smoother - all my data and
applications were moved without a hitch. Couple apps asked to re-enter
serial numbers, but that’s all.</p>
<p>However when I tried to start my XAMPP-packaged MySQL today (I usually
develop on a Linux box, so do not use local MySQL that often) - it would
not start. After some digging around I noticed that permissions on the
MySQL data folder in /Applications/xampp/xamppfiles/var were wrong - it
was owned by “admin” and MySQL could not write in it. I quickly changed
ownership to the mysql user (that was present on my computer), but to my
surprise - that did not help. After some more digging, I found that,
apparently, XAMPP runs MySQL as “nobody”, just like it does Apache.
Somewhat uncommon, but oh well.</p>
<p>Following three commands fixed my after-migration problem:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cd /Applications/xampp/xamppfiles/var
sudo chown -R nobody:admin mysql
sudo chmod -R 775 mysql
</code></pre></div></div>
Apple Support - Does It Exist?
2009-01-07T00:00:00-05:00
http://www.freshblurbs.com/blog/2009/01/07/apple-support-does-it-exist.html
<p>If you are on the latest version of OS-X Leopard (10.5.6) and Safari
(3.2.1) you most probably have encountered the infamous <a href="http://discussions.apple.com/thread.jspa?threadID=1828211&tstart=0">Safari Can Not
Keep
Cookies</a>
problem. You can see from the discussions on Apple.com threads that a
lot of people are affected by it, it has been going on for weeks now and
there is still no resolution or even acknowledgment from Apple.</p>
<p>This is wrong on many levels. First off - managing cookies properly is a
basic feature of a web browser and it’s embarrassing to not get it
right. Granted everybody makes mistakes, but after so many people are
affected, it’s reported to Apple Software Support line, it’s extensively
discussed on apple.com threads - how come nothing is done? How can it go
on for so long? After all, Apple does have one of the best software
engineering teams in the entire industry. Why is nobody taking any
action?</p>
<p>Last, but not least - are Apple employees even using their own software?
:) I mean, we are not talking about some weird combination of versions
and setups - latest OS and latest browser update do not work! Even if
they care little about the end-users, how come this does not affect
them? What’s Steve Jobs using? A Windows? :-)</p>
<p>Something’s rotten in the state of Cupertino!</p>
Proxying to Tomcat from Apache
2009-01-06T00:00:00-05:00
http://www.freshblurbs.com/blog/2009/01/06/proxying-tomcat-apache.html
<p>J2EE servers (Tomcat, JBoss, you name it) usually run on a port that is
higher than 1000. Otherwise they would have to be run as root, which
would be a serious security hole. Apache, on the other hand is a
time-proven web-server that runs on port 80. Following are quick
instructions for how to proxy your J2EE application server from Apache
so that your J2EE applications show up on nice URLs without a port
number in them.</p>
<p>Make sure mod_proxy is available and enabled in Apache. Create a
VirtualHost, in Apache, as you normally would, but instead of indicating
a DocumentRoot put following lines:\</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ProxyRequests Off
ProxyPreserveHost On
ProxyPass /yourpath http://localhost:8080/appctxt
ProxyPassReverse /yourpath http://localhost:8080/appctxt
</code></pre></div></div>
<p>That’s it.</p>
<p>You can also channel Apache to a Java app server using AJP connectors
and Apache’s mod_jk module. It give you more powerful options like:
load-balancing, but also involves more configuration both on Apache and
Tomcat/JBoss side.</p>
<p>Of course, using mod_proxy you can tunnel not just J2EE servers, but
any other server even the one you might have written in C++ for fun.</p>
<p>Enjoy</p>
Using Node References on a Multilingual Website
2009-01-04T00:00:00-05:00
http://www.freshblurbs.com/blog/2009/01/04/using-node-references-multilingual-website.html
<p>CCK Node Reference is an excellent module that allows creation of
complex relationships between content types in Drupal. Combine that with
Views2 feature called Relationships and you have one of the most
sophisticated information architecture design tools any CMS has ever
seen. At least - if you stick to one language. When you are working on a
multilingual website, though, things get complicated. In this blog post
we will discuss how to properly configure node references on a
multilingual Drupal website.</p>
<p>When your website is multilingual the referenced nodes are also in
multiple languages. On an English-only website, you set up your Node
Reference field by indicating the node type. Try that on a multilingual
site and your drop-downs, on node edit pages, will have choices in all
languages! That’s just amateur. Any self-respecting client will frown if
you deliver a solution like that.</p>
<p>The first step at fixing the problem is to indicate a view in the Node
Reference configuration, instead of a node type. That does not get us
all the way to the destination, however, since View only has an option
of indicating “current user language” as a filter. That is not what we
need. We need to filter view by the language of the node being edited.
You can only do that in a View if you use Views Arguments.
Unfortunately, whilst Node Reference does allow passing arguments, it
only allows passing hardcoded arguments and does not allow passing a
dynamic property of the current node (e.g. language).</p>
<p>While we believe this is a serious shortcoming of the Node Reference
module, and hope that they will add such feature in the future, right
now we have to forget about arguements and praise the authors of Views2
for leaving all kinds of hooks to change the default behavior of the
Views programmatically.</p>
<p>The solution is to write a Query Alter hook implementation for views,
that will filter view for use on node edit pages by the language of the
edited node, if present, or the current user language if node does not
have a language specified.</p>
<p>An example code, that takes care of Node Reference node types (and
corresponding views) called “company” and “location” would look
something like the listing below and would be placed in a module called
“modulename”.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>function modulename_views_query_alter(&$view, &$query) {
global $language;
if ( arg(0) == 'node' &&
( (is_numeric(arg(1)) && arg(2) == 'edit') ||
(arg(1) == 'add') )
&& ( $view->name == 'company' || $view->name == 'location') ) {
$node = node_load(arg(1));
if (!empty($node->language)) {
$lang = $node->language;
} else if (arg(1)=='add' && !empty($_GET['language'])) {
$lang = $_GET['language'];
} else {
$lang = $language->language; //default user lang
}
$query->where[0]['clauses'][] = 'node.language = \'%s\'';
$query->where[0]['args'][] = $lang;
}
}
</code></pre></div></div>
<p>P.S. This implementation has one last, minor flaw: if you are changing
the language of a node, you will have to first save the change, before
dropdowns of the Node Reference fields will update, but hey - nothing is
perfect in this world :)</p>
Fascination with Portlets Gone Wrong - Orange.com
2009-01-04T00:00:00-05:00
http://www.freshblurbs.com/blog/2009/01/04/fascination-portlets-gone-wrong-orange-com.html
<p>I must admit, I’ve always been skeptical about
<a href="http://en.wikipedia.org/wiki/Portlet">portlets</a> (or whatever else you
happen to be calling the same notion in your technology). I’ve rarely
seen a website where I found them a necessity. I do not use, or ever
intend to use, iGoogle, because I never go to their homepage - my
browser allows me to search from the toolbar. As a matter of fact, the
only two cases where widgets make any sense, that I know of, are OS-X
Dashboard and Facebook. I have not bothered to customize even those,
much, to be honest, though.</p>
<p>To my great delight, most website owners quickly figured that the
“usability” myth of morphing their websites into a pile of “widgets” was
nothing more than a mirage. They quickly kicked the
know-it-all-can-sell-any-bullshit “consultants” that suggested it out of
the door - where they belong.</p>
<p>Unfortunately, it seems like <a href="http://orange.com/en_EN/">Orange</a> of
France Telecom “did not get the memo”. Somebody over there managed to
“portletize” the homepage (!) of the corporate website. Now, it’s one
thing to let users customize their own profile pages, but to turn
corporate homepage into a Lego™ toy is just a whole new level of a case
of an arrested development.</p>
<p>:big sigh:</p>
How to Delete All Tables in a MySQL Database
2009-01-02T00:00:00-05:00
http://www.freshblurbs.com/blog/2009/01/02/how-delete-all-tables-mysql-database.html
<p>If you are working on a system with somewhat large number of tables, you
probably have wanted to delete a number of tables matching a pattern
(dropping all tables is a specific case of this one). You can do that,
by creating a very simple stored procedure:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mysql> delimiter $$
create procedure drop_tables_like(pattern varchar(255))
begin
SELECT
@drop_sql:=concat('DROP TABLE IF EXISTS ', group_concat(table_name))
drop_statement
FROM information_schema.tables
WHERE table_schema=database() and table_name like pattern;
IF (@drop_sql IS NOT NULL) THEN
PREPARE stmt from @drop_sql;
EXECUTE stmt;
DROP PREPARE stmt;
END IF;
end$$
delimiter ;
</code></pre></div></div>
<p>then you can use this procedure to mass-delete tables like:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mysql> call drop_tables_like ('ika%');
</code></pre></div></div>
Solr, in Drupal, Suddenly Stopped Working!
2008-12-23T00:00:00-05:00
http://www.freshblurbs.com/blog/2008/12/23/solr-drupal-suddenly-stopped-working.html
<p>Ok, so you can swear Solr was working just fine on your Drupal website
and suddenly it does not! You made sure nobody messed with your install
and you do not believe in goblins. What to do?</p>
<p>Keep your cool. Help is on its way and let us explain what happened.</p>
<p>Apache Solr module uses Drupal’s drupal_http_request() function. This
is a very useful function that has numerous benefits over PHP curl
library for the retrieval of information via HTTP. Simplicity,
reliability and speed are just a few to name.</p>
<p>However, it has one serious shortcoming. Somebody thought it was a good
idea to check if the Drupal installation can make HTTP calls at all, by
fetching self-generated page. If that request fails (because you had
.htaccess on for a brief moment there, the request just timed out
randomly or evil in-laws casted Voodoo spell on you) - <a href="http://drupal.org/node/245990">Drupal blocks
the function</a> by setting a variable
‘drupal_http_request_fails’ in the database and then it’s all
downwards from there.</p>
<p>So, if your Solr installation suddenly stops working for no good reason,
or your FeedAPI is not bringing feed items, anymore, try clearing the
flag by either issuing: variable_set(drupal_http_request_fails,
false); in Drupal, or running the following command in mysql:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mysql> update variable set value='b:0;' where name='drupal_http_request_fails';
</code></pre></div></div>
CSS Background Transparency
2008-11-23T00:00:00-05:00
http://www.freshblurbs.com/blog/2008/11/23/css-background-transparency.html
<p>The Right Way is obviously CSS 3.0: rgba(R,G,B,ALPHA), but since only
Safari supports CSS 3.0 currently (to the best of my knowledge, but you
bet IE does not) the “right way” is out of question.</p>
<p>Moving on.</p>
<p>You can, also, try using the combined CSS properties:\</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>filter:alpha(opacity=50);-moz-opacity:.5;opacity:.5;
</code></pre></div></div>
<p><br />
and think to yourself: “OK, I used three properties for one thing, so
the cross-browser demons should be happy, right? What can possibly go
wrong?”</p>
<p>Well, demons are demons because they are evil and more goes wrong than
possibly could. Namely, all child elements of the div, the background of
which you just made transparent, will also become transparent. Even if
you have no children divs: all your text, within the div, will be
transparent and I can bet that was not something you wanted!</p>
<p>What to do? What to do? You rush to Google and find all kinds of
MMFW-CSS (make-me-feel-worse, CSS) tricks that do not help. Like the one
suggesting the inside elements should not really be children of the
initial div, but be overlapped using, nothing less than, an absolute
positioning. Yeah, like that really helps: adding the pain of absolute
positioning to the already existing list of pains with your page’s CSS!</p>
<p>But do not despair! There’s a way to the light!</p>
<p>With no further delay, here is the workin’-kickin’ solution, tested in
most browsers:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>div.transp[class] {
background-image:url(70percent.png);
}
</code></pre></div></div>
<p>The 70percent.png is a PNG image with 70% percent alpha transparency.
The “filter:” CSS style fixes IE’s shortcoming of having no clue about
PNG Alpha channels. The [class] attribute of the .transp class hides
that style from IE6. Otherwise you’d get a solid-color background.</p>
<p>You have to hide filter: attribute from IE version > 6 since they do
understand the [class] thingie and do handle aplha channels correctly,
so they will both apply the filter and the transparent PNG, giving you a
comletely different color than what you expected.</p>
<p>Also, for some weird reason, “filter” does not understand relative
pathes. You have to use absolute path or it won’t work. You can thank
Microsoft, once again.</p>
The Best VPS Hosting - SliceHost
2008-11-15T00:00:00-05:00
http://www.freshblurbs.com/blog/2008/11/15/best-vps-hosting-slicehost.html
<p>OK, it’s official: I am in love with a hosting company. I never thought
I would ever say something like this. I have tried many hosting
companies over the years, some horrible, some overpriced, some barely
decent. Never have I ever felt so strong (at least positively) about any
of them.</p>
<p><a href="http://slicehost.com">SliceHost</a> is an absolute perfection of a hosting
company for personal, small and mid-size businesses. I can not think
about a single thing that I would not love about them: from incredibly
affordable plans, to stability, performance, reliability, quality,
instant activation, Drupal-based control panel, even the <a href="https://slicehost.campfirenow.com/guest/lobby">Campfire-based
support</a> line, where you
can get answers to your questions 24/7 and right away from highly
knowledgeable experts and share experience with other customers.</p>
<p>If I was to build a perfect affordable hosting company myself, and I
could implement it exactly the way I wanted, I still would not be able
to do it better… frankly, I probably would not even be able to do it
as well.</p>
<p>Wonderful job, guys! Seriously!</p>
<p>Keep up the good work!</p>
<p>P.S. So far I have been helping some friends with their SliceHost
servers and enjoying their accounts. I will be moving my blog to
SliceHost as soon as I find some time to migrate all the stuff I have
accumulated on the current server.</p>
Web 2.0 in the Army
2008-11-08T00:00:00-05:00
http://www.freshblurbs.com/blog/2008/11/08/web-2-0-army.html
<p>I found it very interesting to listen to this Web 2.0 Summit
presentation by Jeffrey A. Sorenson and see how Web 2.0 is perceived by
Army. It’s a common stereotype that government is always behind as far
as new and cool goes, but apparently Army is well aware of Web 2.0, is
fully embracing it and that, my friends, is very exciting to hear,
indeed!</p>
<p>Enjoy:</p>
Install PHP 5.2 on CentOS 5.2 Using Yum
2008-11-08T00:00:00-05:00
http://www.freshblurbs.com/blog/2008/11/08/install-php-5-2-centos-5-2-using-yum.html
<p>Yum is a standard installation utility for CentOS 5.2. One of the
reasons I favor CentOS over other Linux distros is actually because it
comes with yum. It is that good!</p>
<p>Unfortunately, CentOS 5.2 does not generally include the latest versions
of libraries, because it follows conservative path of the RedHat
Enterprise. Which is not that bad of an idea, for a server OS… until
you need that latest version of something and you are stuck… or: not
necessarily.</p>
<p>If you a are a Drupal developer, there’s a very good reason why you need
the latest version of PHP: 5.2. The reason is called <a href="http://drupal.org/project/filefield">FileField
module</a>. This module is required by
another absolutely essential module
<a href="http://drupal.org/project/imagefield">ImageField</a> making it a matter of
life-or-death (just kidding) to have PHP 5.2 on your server. But the
latest CentOS release (ironically also 5.2) only comes with PHP 5.1.6.</p>
<p>What to do?</p>
<p>Some people on the Net suggest installing Fedora RPMs. Not such a good
idea, since PHP also has a bunch of its own extensions that RPM will not
like the versions of and going down that path will quickly prove being
extremely painful. Also, if you install custom RPMs, you lose the
benefits of Yum and that’s not good at all. Compiling from source, is
even worse of an idea, for all the same reasons, of course.</p>
<p>Like I already mentioned, yum is awesome and one of the awesome things
it allows is to attach to third-party repositories. So you can still
install newer versions of certain RPMs if you need to.</p>
<p>A third-party Yum repo simply means that somebody else went through the
pain for you (thank you, Somebody!) and now you can use the benefits of
their work, plus continue using yum to manage versions. Nice!</p>
<p>You can find some other Yum repo containing PHP 5.2 but I suggest using
one from Jason Litka. He has nice, detailed explanation on his blog how
to install his Yum repo: http://www.jasonlitka.com/yum-repository/ Yum
recommends that you install
<a href="http://wiki.centos.org/PackageManagement/Yum/Priorities">Yum-Plugin-Priorities</a>
when you install any third-party repo.</p>
<p>So you start with the standard Yum installation of PHP 5.1.6 on CentOS
5.2. Then, once you have installed Jason’s repo, you can update PHP. If
you are using APC with PHP (always a good idea) you need to first
disable it and re-install after update:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># pecl uninstall apc
# mv /etc/php.d/apc.ini /tmp/apc.ini
# yum update php
# pecl -d memory_limit=16M install apc
# mv /tmp/apc.ini /etc/php.d/apc.ini
</code></pre></div></div>
<p>The uninstall/re-install procedure for APC is actually relevant for any
other extension you might have installed using PECL for PHP 5.1.6.</p>
<p>If you run into any problems uninstalling PECL just remove the .so file
and the configuration that tries to load it. If you run into any
problems re-installing APC with PECL, read a great <a href="http://www.agileapproach.com/blog-entry/howto-install-pecl-apc-cache-centos-without-xampp">blog post from
Frank</a>
that explains everything in detail.</p>
OpenID on Google and MSN Live!
2008-11-01T00:00:00-04:00
http://www.freshblurbs.com/blog/2008/11/01/openid-google-and-msn-live.html
<p>Fantastic news for OpenID:</p>
<p>“This is a historic week for OpenID. Google and Microsoft announced the
release of code to support OpenID 2.0 across their most important
properties. On Monday, Microsoft, announced OpenID 2.0 support for their
460 million users on the LiveID platform. On Wednesday Google said it
will be supporting OpenID 2.0 for any user that has a Google account.
Both of these deployments are great news for the OpenID community and
the Internet at large. It can be safely said that within the coming
months, every single user on the Internet will have an OpenID”</p>
<p>via:
<a href="http://openid.net/2008/10/30/microsoft-and-google-announce-openid-support/">openid.net</a></p>
Please Join A Good Cause
2008-10-27T00:00:00-04:00
http://www.freshblurbs.com/blog/2008/10/27/please-join-good-cause.html
<p>If you care about the future of the Internet we kindly ask you to <a href="http://www.facebook.com/group.php?gid=54552678792">join
a good cause</a>.</p>
Easily Edit Blocks in Drupal
2008-10-22T00:00:00-04:00
http://www.freshblurbs.com/blog/2008/10/22/easily-edit-blocks-drupal.html
<p>I finally got around developing a little, nifty Drupal module I’ve been
craving for, for a really long while now. The “<a href="http://drupal.org/project/block_edit">Edit
Block</a>” module adds inline block
editing capability to any theme. It’s entirely jQuery-based, hence - no
<del>dirty</del> intrusive theming hacks are necessary and is compatible with
most properly built Drupal themes.</p>
<p>Some nice themes do provide similar capabilities, but most - do not and
adding it is no fun, so now there’s a module that does it all for you.</p>
<p>Enjoy</p>
Business Analytics in Drupal
2008-10-21T00:00:00-04:00
http://www.freshblurbs.com/blog/2008/10/21/business-analytics-drupal.html
<p>Designing professional reports in Drupal is not trivial. At the same
time, Drupal has one of the most advanced query builder tools (Views)
that any CMS (open-source or not) has ever dreamed of. There’s clearly a
gap.</p>
<p>I’ve been cooking some stuff up for a while now and will be putting a
presentation together for DC Drupalcon. Drupalcon topics are chosen by
popular vote, so if you want to learn how to easily create awesome
charts, graphs and reports in Drupal, please give a vote:
<a href="http://dc2009.drupalcon.org/session/business-analytics-drupal-views">http://dc2009.drupalcon.org/session/business-analytics-drupal-views</a></p>
High Quality Youtube Content: URL Trick
2008-10-19T00:00:00-04:00
http://www.freshblurbs.com/blog/2008/10/19/high-quality-youtube-content-url-trick.html
<p>Nice trick: add “&fmt=18” to a YouTube URL and you can enjoy stereo
audio and better-quality picture (requires more bandwidth, of course).</p>
<p>Have fun</p>
DrupalCon DC Announced!
2008-10-15T00:00:00-04:00
http://www.freshblurbs.com/blog/2008/10/15/drupalcon-dc-announced.html
<p>DrupalCon DC was <a href="http://drupal.org/node/321768">announced</a> today on
Drupal.org. We’ve known it for a while, to be honest, but now it’s
official! DrupalCon DC will be held March 4-7, 2009 and registration
will be opening next week.</p>
<p>The importance of DrupalCon DC is hard to overestimate. Washington, DC
is home to many non-profits and PR Agencies, the most active users of
Drupal, to date. It’s also right next to Virginia’s tech hub - the
largest tech “settlement” on the East coast. And, being on the east
coast, it’s also a shorter flight for European Drupallers.</p>
<p>Local firms like <a href="http://agileapproach.com">Phase2 Technology</a> and
<a href="http://developmentseed.org">DevelopmentSeed</a> have put a lot of effort
into making Drupalcon DC a reality, but winning the bid and the
announcement is just a start. There will be a lot more tasks to do to
make DrupalCon DC the largest and the best DrupalCon. We hope that you
will join our efforts.</p>
<script type="text/javascript" language="JavaScript">
var atSign = "@";
var enc_eml = "tsha"+"ck"+"el"+"ford";
enc_eml += atSign;
enc_eml += "phase2"+"techno"+"logy.com";
</script>
<p>Sponsorship slots are still available and there are numerous other ways
to get involved, as well. Please stay tuned while the official
conference site is being born or e-mail</p>
<script type="text/javascript" language="Javascript"> document.write ( "<a href=\"mailto:"+enc_eml+"\">"+enc_eml+"</a>" ); </script>
<p>with any questions you may have.</p>
Why Large Organizations Lose on the Web
2008-10-02T00:00:00-04:00
http://www.freshblurbs.com/blog/2008/10/02/why-large-organizations-lose-web.html
<p>A popular joke of the 21st century has been that the Web is “ruled” by
teenagers. That saying may be a joke, but the truth is: we live in an
era in which a self-organized group of college students, without any
funding <a href="http://www.youtube.com/watch?v=J80PE1h9OuA">can take on global organizations like
HSBC</a>.</p>
<p>How come?</p>
<p>Because large organizations are too SLOW! Web is extremely fast-paced
and the large bureaucratic beasts are often just way too late to the
party.</p>
<p>To give couple examples:</p>
<p>1) In most organizations people who can quickly react to an emerging
topic, on the Web, concerning the organization, are not allowed to. The
messages “have to go through proper channels” and channels take time.</p>
<p>Solution: either remove the channels or make sure they do not take so
much time. Can you achieve 10-minute turnaround? If not - relax the
preemptive oversight. Educate your employes on what’s acceptable and
what is not. Let them take initiatives of engaging in the conversations
on the Web, let them make mistakes (they will make some), make sure they
learn from those.</p>
<p>2) Use agile technologies. Forget about “enterprise” this and that.
Forget about “big company consultants”. Use what is already available:
Facebook, Linkedin, Youtube, GoogleMaps etc. For the part you need to
build, use Drupal, WordPress, DJango, RubyOnRails. Use technologies that
can give you results QUICKLY.</p>
<p>I’ve been a Java architect long enough and I know enterprise Java
technologies well-enough to allow myself say this: most organizations
that build websites in Java (or any other heavy-weight technology like
that) are just wasting their time. Java is great and there are many
incredible things you can build with it if you are an Internet backbone
company like Verisign, but Java is not for your blogging needs or even
for your website of average complexity.</p>
<p>Be responsive, be quick, be agile. Worn-out phrase or not, I will repeat
this: please, please, do <strong>not</strong> be afraid to make mistakes.</p>
Re-Think Medium Independence
2008-10-01T00:00:00-04:00
http://www.freshblurbs.com/blog/2008/10/01/re-think-medium-independence.html
<p>Software engineering has introduced the paradigm of the separation of
the View (visual representation) from the Model (business logic) long
time ago. In the realm of the Web, this principle was re-emphasized. In
the late ’90s and early 2000s the separation was used to accommodate for
differences between physical mediums that a web-page could be viewed on:
from the lame WAP browsers to incompatible HTML ones of all kinds. Or at
least, this is how it was commonly explained. I, for one, have rarely
seen any actual web-application that would cleanly and transparently
render to WAP and HTML from the same engine. Also, the WAP mess
disappeared long before most developers would start to feel its pains.
But that’s a different story.</p>
<p>These days tiny gadgets (think: iPhone or Blackberry if you are
“uncool”) have better, more compliant browsers than some desktop systems
(would that be Windows?). Is the need for MVC - the separation of Model
and View gone?</p>
<p>On the contrary. The peak of the so-called Web 2.0 is characterized by
the flood of widgets of all kinds. Widgets for iGoogle, “applications”
for Facebook and even - web-enabled widgets for Desktop systems like
OS-X Dashboard. Large companies of the kind of New York Times produce
widgets for all of these mediums. Obviously, something like that can be
a huge expenditure if you are writing each widget from scratch each time
and do not re-use anything but the database.</p>
<p>Therefore, the Web Question of 2009 becomes: can your website’s source
code output a widget instead of a full-fledged website with very little
code change?</p>
<p>Think about it.</p>
Next Big Thing on the Web - Free SMS Gateway
2008-09-29T00:00:00-04:00
http://www.freshblurbs.com/blog/2008/09/29/next-big-thing-web-free-sms-gateway.html
<p>I woke up feeling a little prophet-ish this morning. I would bet you
money, but it is illegal, so I am just going to say: I know what the
next big <del>service</del> thing from Google <del>should</del> will be! Ready? It’s a
free SMS gateway that allows sending SMS messages through an open API.</p>
<p>Now think about it. Text-messaging (“SMSing”) has been hot for a while
now. Marketing companies and individuals are already using it big time.
Text-messaging is expensive, though. Many little startups, with little,
but interesting pilot sites just can not afford it. How is the industry
going to innovate, if the innovators can not afford the tools?</p>
<p>There’s a lot of data transmitted over text-messages and it could be
even more interesting than the data you find in emails. Text-messages
typically have less spam. If Google is willing to provide huge mailboxes
for free, just for a chance to index e-mail text - they should be dying
to get their hands on text-messages. If anything, Google is late to do
it.</p>
<p>You say “privacy”? I say - yeah, like Google cares.</p>
<p>So, here it is - you should see something like it in the next 6 months.
I give it a year tops.</p>
Joomla and the World Bank Logo
2008-09-17T00:00:00-04:00
http://www.freshblurbs.com/blog/2008/09/17/joomla-and-world-bank-logo.html
<p>Interesting choice of graphics from <a href="http://joomla.com">Joomla:</a></p>
<p>Check this:<br />
<img src="http://www.freshblurbs.com/files/joomla-image.jpg" alt="" /></p>
<p>And then look at the striking similarity of the World Bank logo:</p>
<p><img src="http://www.freshblurbs.com/files/logo.gif" alt="" /></p>
<p>Could have come up with something more original.</p>
How To Uninstall Cooliris from Safari on a Mac
2008-09-12T00:00:00-04:00
http://www.freshblurbs.com/blog/2008/09/12/how-uninstall-cooliris-safari-mac.html
<p><img src="http://www.freshblurbs.com/files/cooliris.png" alt="" /><a href="http://www.cooliris.com/">Cooliris</a>
is one of these new gadgets that sound cool in somebody’s blog review,
but do not live up to an expectation when actually used. Let alone that
it is not nearly as useful as it claims to be, Cooliris has been
reported to significantly slow down Safari on Macs. Specifically - when
viewing FLASH videos like on YouTube. These fellas must have done
something terribly wrong.</p>
<p>In any case, the real sad part is - they don’t have any human way of
uninstalling it. So here is a quick tutorial of how to remove this weed
from your computer and let your Safari breath again:</p>
<ul>
<li>Close Safari</li>
<li>Trash the Cooliris Previews folder found in
$LIBRARY/InputManagers/)</li>
<li>Trash the cooliris’ .plugin file found in $LIBRARY/Internet Plugins</li>
</ul>
<p>Depending on whether you installed Cooliris for just your user or
system-wide, substitute $LIBRARY with /Users//Library or
/System/Library.</p>
<p>Hope this works for you, too.</p>
Blackhole Noise - Kill the Office Noise!
2008-07-31T00:00:00-04:00
http://www.freshblurbs.com/blog/2008/07/31/blackhole-noise-kill-office-noise.html
<p><img src="http://www.blackholemedia.com/images/noiseicon.png" alt="" /> If you work in a
noisy office (or home) environment and can’t concentrate, this is a
must-have Mac app: http://www.blackholemedia.com/noise/</p>
Menu Items Disappeared in Drupal 5
2008-07-16T00:00:00-04:00
http://www.freshblurbs.com/blog/2008/07/16/menu-items-disappeared-drupal-5.html
<p><strong>Quick Note:</strong> the <a href="http://drupal.org/project/admin_menu">Administration
Menu</a> module in Drupal seems to
have some weird bug in ver. 5.2.5 which causes menu items listing to
disappear on admin/build/menu configuration page.</p>
<p><strong>Solution:</strong> disable and remove Administration Menu module, download
5.2.6 or later version, install that one. If the problem persists run
“menu_rebuild();” from hook_init() of any module or even from
page.tpl.php. Problem should be gone.</p>
<p>Enjoy.</p>
Google Protocol Buffers - the Good, the Bad and the Ugly
2008-07-10T00:00:00-04:00
http://www.freshblurbs.com/blog/2008/07/10/google-protocol-buffers-good-bad-and-ugly.html
<p>Google released to open-source its “language-neutral, platform-neutral,
extensible way of serializing structured data for use in communications
protocols, data storage, and more”: <a href="http://code.google.com/apis/protocolbuffers/docs/overview.html">Protocol
Buffers</a>.</p>
<p>Google claims it’s like XML, but better mostly because: “[Protocol
Buffers] are 3 to 10 times smaller, and 20 to 100 times faster”.</p>
<p>My feelings about this news are mixed. Like I was just telling
<a href="http://wemmick.blogspot.com">Doug</a> you can’t argue with Google when it
comes to matters of performance and speed, BUT you can feel concerned at
the fact that a giant, like Google, uses its muscle to diminish and harm
the crucial standard like XML. XML took so long to get adopted, made so
much possible and is still so fragile, that you can’t take this matter
lightly.</p>
<p>OK, maybe the PB thing is faster and smaller and blah, blah, blah and
maybe it’s not as cumbersome as CORBA was, so it’s not total evil, BUT
(I repeat - BUT) let’s be honest here - not everybody is Google and I
can bet 90% of systems just do not care about the same things Google
does. So, XML is fine for most applications.</p>
<p>However, now that Google is pushing one more of its bloated technologies
(want another example? Think GWT) - a lot of people will adopt it just
because it’s a Google thing. And it may harm XML, and it may harm
industry.</p>
<p>So, you see - as much as we all love open-source, sometimes when
open-source gets intermixed with big, corporate politics - things can go
south.</p>
<p>And last but not least, if you want more object-oriented, smaller,
faster exchange format, there is JSON! JSON is well adopted and
supported, so why, oh why do mere mortals like ourselves need Protocol
Buffers?</p>
<p>We don’t. Please, don’t force us.</p>
How To Recognize Drupal-Built Websites
2008-07-06T00:00:00-04:00
http://www.freshblurbs.com/blog/2008/07/06/how-recognize-drupal-built-websites.html
<p>Geeks among us often wonder what a website is built with. Is it a
Java/J2EE home-cooked mess? Is it a .Net nightmare? Or is it a common
CMS installation styled to the extent of not being recognizable (i.e.
not being ugly, anymore :) )?</p>
<p>Most 5-minute drupal installations will respond to requests like
http://example.com/user/ and http://example.com/admin/ and you will see
familiar Drupal interface: either the ugly tabs, or the Garland itself.</p>
<p>More paranoid (or careful?) admins may have the default URIs disguised
for public eyes. If we are doing analysis using an automated tool
(somebody?) it’s better to have an alternative method since other CMS’s
may respond to the same URIs and automated tools don’t have eyes to see
the ugly tabs.</p>
<p>What may help in a complex analysis of a site is looking at its HTML
source. If in the header you see URIs like “/misc/drupal.js” you know
this site is running Drupal! If the website admin had enabled javascript
aggregation, though, you won’t see anything like that and will have to
hunt for “/sites/default/files/js” pattern.</p>
<p>Also, please note that Drupal does not load drupal.js if no other
javascript is requested from code, so you may not see any of those on
the home page. It’s the best to look at the “Add Comment” pages, since
those usually have some Javascript.</p>
<p>Happy hunting! :)</p>
Firefox 3.0 Has Arrived. Download!
2008-06-17T00:00:00-04:00
http://www.freshblurbs.com/blog/2008/06/17/firefox-3-0-has-arrived-download.html
<p><img src="http://www.freshblurbs.com/files/firefox_3.png%20" alt="" /><br />
<a href="http://firefox.com">Firefox 3.0</a> web-browser has been released! The
new browser has much slicker (imho) user-interface, feels faster/lighter
and is just plain awesome!</p>
<p>For <a href="http://getfirebug.com/releases/">FireBug</a> users (i.e. any
web-developer and designer?) out there: you need to manually download a
new major release version, 1.2.0b4. Automated update of 1.05 won’t work.</p>
<p>Don’t know about Windows machines, but on Macs you can rename the
existing Firefox to Firefox2 under Applications, before installing
Firefox3 and that way you can keep running both in parallel (though not
at the same time). Once you upgrade the plug-ins, you can not use them
in the Firefox 2, anymore and you will start getting warnings. It’s
still useful for testing rendering of websites and making sure your
HTML/CSS works in Firefox 2, though.</p>
Oxymoron of the Month - Agile Websphere (Project Zero)
2008-06-12T00:00:00-04:00
http://www.freshblurbs.com/blog/2008/06/12/oxymoron-month-agile-websphere-project-zero.html
<p>The intro/description from IBM’s new <a href="http://www.projectzero.org/">Project
Zero</a> caught my eye right away: “We’re
building an agile development environment leveraging scripting runtimes
such as Groovy and PHP, and optimized for producing REST-style services,
integration, mash-ups, and rich Web interfaces. This is the community
development site for IBM WebSphere sMash, offering users a chance to
interact with the development team as we build this new product”.</p>
<p>Generally, I don’t believe in software frameworks that do not emerge off
of a successful real-life project and are built “in-theory”, around a
vague idea. This attitude of mine is backed by facts: Spring came out of
a real project, so did Hibernate, Erlang was heavily used at Siemens…
even Drupal was initially built for a college website Dries was putting
together. Nothing ever came out of just wanting to create a software
framework and thinking you have enough experience (“more than others” is
usually the feeling). At least, I know no real good examples.</p>
<p>But besides that, WebSphere and “agile”? :) If you ever <strong>had</strong> to work
with WebSphere, you will understand and will have to forgive my natural
sarcasm.</p>
<p>P.S. Nice domain, though. I wonder how much they got <em>that</em> for.</p>
Chrooted FTP Access
2008-06-11T00:00:00-04:00
http://www.freshblurbs.com/blog/2008/06/11/chrooted-ftp-access.html
<p>FTP is an insecure, outdated and overall horrible protocol that you
should never use yourself. Yet, sometimes you want to allow some people
to upload files to your server, but you don’t want them poking around
your server or users demand FTP because they are used to it and have no
idea what SSH/SFTP is.</p>
<p>Either way, following is how you “chroot” ftp users to their home
folder, so they can’t do any harm:</p>
<ul>
<li>Download latest <a href="http://www.proftpd.org/">proftpd</a> source to
/usr/local/sources and change to that folder.</li>
<li>./configure –sysconfdir=/etc –localstatedir=/var</li>
<li>make</li>
<li>make install</li>
<li>Edit vi /etc/proftpd.conf:
<ul>
<li>Change “Umask 022” to “Umask 002” #So, files they upload are
group-writable</li>
<li>Uncomment “DefaultRoot ~” # this does actual chrooting</li>
</ul>
</li>
<li>Make sure “/bin/false” is listed among the shells in “/etc/shells”</li>
<li>Create new unix user with “-s /bin/false”</li>
<li>Start proftpd daemon</li>
</ul>
Drupal in Healthcare - Social Networks Beyond MySpace
2008-06-10T00:00:00-04:00
http://www.freshblurbs.com/blog/2008/06/10/drupal-healthcare-social-networks-beyond-myspace.html
<p><img src="http://www.freshblurbs.com/files/Picture%2013.png" alt="" /> David E.
Williams, from the <a href="http://www.healthbusinessblog.com">Health Business
Blog</a> recorded an interesting
<a href="http://www.healthbusinessblog.com/?p=1804">podcast</a> with Dr. Jason
Bhan, co-founder of <a href="http://ozmosis.com">Ozmosis</a>.</p>
<p>Ozmosis is a social network for practicing physicians to share knowledge
and communicate. Revolutionary in its nature, Ozmosis uses the rich
experience of existing social networks, plus a proprietary “trust”
technology, to create a breakthrough environment where physicians can
quickly get answers and improve their knowledge.</p>
<p>Ozmosis was made possible by Drupal. Examples of Drupal usage that
benefit public are numerous, but if I am not mistaken, this is the first
major case of Drupal being used in Healthcare. It’s great to see Drupal
helping revolutionize the way things are done, especially in such an
important area.</p>
<p>Listen to the podcast: [ http://www.healthbusinessblog.com/?p=1804 ]</p>
Martin Fowler And Jim Webber About SOA and Enterprise Integration
2008-06-07T00:00:00-04:00
http://www.freshblurbs.com/blog/2008/06/07/martin-fowler-and-jim-webber-about-soa-and-enterprise-integration.html
<p><img src="http://www.infoq.com/resource/presentations/soa-without-esb/en/smallimage/both.jpg" alt="" />
A very insightful and fun presentation that is not boring, from people
who really get it:<br />
http://www.infoq.com/presentations/soa-without-esb</p>
<p>Awesome job! We admire these guys for a reason, indeed.</p>
Measure Distances on Screen in Mac OS-X
2008-05-30T00:00:00-04:00
http://www.freshblurbs.com/blog/2008/05/30/measure-distances-screen-mac-os-x.html
<p>Really nice and useful tool:<br />
http://www.pixelatedsoftware.com/products/pixelstick/</p>
<p>Tools like this one are plenty, but this particular one has a great
user-interface. Better than any other free one, I have seen.</p>
Web 3.0 Has Arrived
2008-05-21T00:00:00-04:00
http://www.freshblurbs.com/blog/2008/05/21/web-3-0-has-arrived.html
<p>Web 1.0: Global reach to content publishing.<br />
Web 2.0: Web becomes a two-way publishing avenue: readers contribute
content and play central role.<br />
Web 3.0: Let’s try make sense of the enormous content published. Smart
aggregation becomes key.</p>
<p>It looks like the reality in which content aggregation plays equally
important role, compared to publishing, is arriving quietly but
steadily:</p>
<p><img src="http://www.freshblurbs.com/files/aws_bandwidth.gif" alt="" /></p>
<p>Image courtesy of <a href="http://aws.typepad.com/aws/2008/05/lots-of-bits.html">Amazon Web Services
Blog</a></p>
<p>P.S. Thanks to <a href="http://wemmick.blogspot.com/">Doug</a> for pointing to the
blog post.</p>
Can Microsoft Be Cool?
2008-05-16T00:00:00-04:00
http://www.freshblurbs.com/blog/2008/05/16/can-microsoft-be-cool.html
<p>Microsoft has recently awarded a $300M account to a star ad-agency
Crispin Porter + Bogusky. Bogusky is <del>like</del> a new icon of the Ad
industry, having under the belt such successful projects as Mini Cooper
campaign, the revival of Burger King brand image and many others.</p>
<p>Of course, the hypocrisy of the story is that Crispin became successful
using all-Mac technologies… And now they are trying to help Microsoft
battle Apple. But let’s not go into that. Let’s just think for a second</p>
<ul>
<li>can even the most edgy, “cool” ad agency help Microsoft’s image of the
out-of-touch, obnoxious, nerds-run company?</li>
</ul>
<p>No. And here is one clear example of why. Watch this commercial from
2007 (which was not made by Crispin):</p>
<p>What’s wrong with it? Nothing! It’s actually really good - moderately
self-promoting, supposedly facts-based and re-ensuring… Except it’s a
lie. A complete lie at that. Yes, the image in the commercial is how
Microsoft sees itself, or wants to see itself - long-time innovator and
industry enabler, but there are solid facts, experiences of people that
prove: the truth is different. When your software sucks, hangs every
five seconds and gets on anybody’s nerves that has ever used it - well,
commercials can’t help it.</p>
<p>Microsoft execs, write it down: <strong>outright lies do not sell!</strong></p>
<p>Advertising is powerful, but it is not almighty. Microsoft’s problems
are far serious and deeper than a question of what Ad agency to choose.
When are they going to realize it? Ever?</p>
CCK Import During Install
2008-05-15T00:00:00-04:00
http://www.freshblurbs.com/blog/2008/05/15/cck-import-during-install.html
<p>We’ve blogged about <a href="http://www.freshblurbs.com/extreme-form-handling-drupal">hardcore Drupal Form
Manipulations</a>
using CCK Node Types and hooks. If it is part of your module (as it
should) you need to install CCK type during module setup. In the
.install file of that module you can import CCK definition with a code
like:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>function ourmodule_CCK_install() {
$modulepath = drupal_get_path ('module', 'ourmodule');
$cck_definition_file = $modulepath."/custom.cck";
$values['type_name'] = '<create>';
$values['macro'] = file_get_contents($cck_definition_file);
include_once( drupal_get_path('module', 'node') .'/content_types.inc');
include_once( drupal_get_path('module', 'content') .'/content_admin.inc');
drupal_execute("content_copy_import_form", $values);
}
</code></pre></div></div>
<p>where custom.cck under your module folder is the file that you can
export from CCK if you have cck_content_copy module installed.</p>
Agile Hosting Packages: Ruby On Rails, Django, You Name It
2008-05-15T00:00:00-04:00
http://www.freshblurbs.com/blog/2008/05/15/agile-hosting-packages-ruby-rails-django-you-name-it.html
<p>Some extremely exciting news in the world of Agile and Dynamic
languages:</p>
<ul>
<li><a href="http://www.modrails.com/">Passenger (mod_rails)</a> released and the
popular, mass-hosting provider DreamHost <a href="http://blog.dreamhost.com/2008/05/13/passenger-for-ruby-on-rails/">is now
offering</a>
mod_rails hosting.</li>
<li>A legendary, rock-solid MediaTemple hosting is now offering <a href="http://www.mediatemple.net/labs/grid/gc-django-beta.htm">Django
GridContainers</a>
for scalable deployments.</li>
</ul>
<p>The way I am cut-out, I get in physical pain if I don’t have a root
access to a server. Considering this, I would much rather get a VPS or
(for massive, scalable solution) a combination of Amazon EC2 and
RightScale management console, but for industry at large, the
availability of mainstream RoR and Django hosting solutions is a big
deal… huge deal. And we welcome it wholeheartedly.</p>
<p>These are very exciting times to be in the software business, indeed.</p>
Extreme Form Handling in Drupal
2008-05-13T00:00:00-04:00
http://www.freshblurbs.com/blog/2008/05/13/extreme-form-handling-drupal.html
<p>Via: <a href="http://agileapproach.com/blog-entry/extreme-form-handling-drupal">AgileApproach
Blog</a></p>
<p>Drupal Form-Handling support goes far beyond just the documented part of
so-called Forms API. You can do pretty much <em>anything</em> with forms in
Drupal and you can use/display the forms anywhere.</p>
<p>Here is an example. Let’s assume we want to construct a custom node type
with custom fields, using CCK. Then we want to display this form into
some non-standard page. To further complicate things, let’s assume we
also want custom verification and processing routines.</p>
<p>And last but not least - we want to use full power of Drupal and write a
minimal amount of code. Following is a snippet demonstrating key points
to achieving this task (thorough understanding of Drupal is required):</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>define ('OUR_NODE_TYPE', 'flight_schedule');
define ('OUR_NODE_FORM_ID', 'flight_schedule_node_form');
</code></pre></div></div>
<p>where $form_id is the Drupal form_id of the form and $form_values
is an indexed array of submitted values. In the validation function you
can set alert points using form_set_error() function like this:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>form_set_error('field_flight_schedule', t('Flight Schedule ID must be unique.'));
</code></pre></div></div>
<p>where field_flight_schedule is a form element ID coming from a CCK
field.</p>
<p>Also, for node forms you can call the original submit function from your
submit function, so that you don’t have to duplicate things that it
already does. You do it with something like:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> $original_return = node_form_submit($form_id, $form_values);
</code></pre></div></div>
<p>and you can and your _submit function with “return $original_return”
so form submit redirects to where it would normally do.</p>
<p>The rest of the code should be self-explanatory, given a reader is
proficient in Drupal. Also, you can leave comments here, if you have
further questions.</p>
Python, Django and LAMPP
2008-05-10T00:00:00-04:00
http://www.freshblurbs.com/blog/2008/05/10/python-django-and-lampp.html
<p><strong>Disclaimer:</strong> <em>the problem and the solution are not unique to LAMPP.
If you have a MYSQL installation with uncommon paths, you will get a
similar problem and you can solve it in a similar way. Just make sure
you insert correct paths in the newly created .conf file for the LD (see
below).</em></p>
<p>If, for whatever reason, you are running MySQL from your
<a href="http://apachefriends.org">LAMPP</a> installation and try to use Python’s
MySQLdb API to connect to MySQL server you will get the following nasty
error into your face:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ImportError: libmysqlclient_r.so.15: cannot open shared object file
</code></pre></div></div>
<p>The problem is that lampp, in its attemt to not disturb the rest of the
OS space, does not expose some crucial shared libraries (like: mysql
client, ssl etc.) to Linux at large and Python is unable to find them
even though they are installed under LAMPP.</p>
<p>The solution is quite easy</p>
<p>(NO! Do NOT use LD_LIBRARY_PATH, that’s evil). We need to tell LD to
look for additional libraries.</p>
<p>For that, we need to create a lampp.conf file under /etc/ld.so.conf.d/
and insert following two lines in it:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/opt/lampp/lib/mysql
/opt/lampp/lib
</code></pre></div></div>
<p>When that’s done, we tell LD to reload config by issuing:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo /sbin/ldconfig
</code></pre></div></div>
<p>Voila!</p>
Twitter Spitting on Ruby On Rails Performance
2008-05-02T00:00:00-04:00
http://www.freshblurbs.com/blog/2008/05/02/twitter-spitting-ruby-rails-performance.html
<p>Very interesting: Twitter is abandoning Ruby on Rails due to claimed
scalability problems:\</p>
<p>http://www.techcrunch.com/2008/05/01/twitter-said-to-be-abandoning-ruby-on-rails/</p>
MacBook Air SSD - Don't Waste Your Money
2008-04-29T00:00:00-04:00
http://www.freshblurbs.com/blog/2008/04/29/macbook-air-ssd-dont-waste-your-money.html
<p><img src="http://www.freshblurbs.com/files/macbook-air.jpg" alt="MacBook Air" /> MacBook
Air is undoubtedly one of the most revolutionary gadgets released
lately. Could even be the most revolutionary one, if not iPhone. Hold!
Before you attack my statement about “undoubtedly”, keep in mind - I
don’t mean it’s something you should jump on buying. All we mean is that
it’s a revolutionary design (with outstanding implementation) that makes
a breakthrough in a consumer product class and forces the entire
industry segment to make a big leap forward. Now you do have to agree
MacBook Air is a revolutionary product.</p>
<p>Anyhoo… That is not what I wanted to write today about. The subjects
of the today’s post are the two versions of MacBook Air: the affordable
$1,799 one and the insanely expensive $3,098 one. Aside from some
other minor differences, the biggest difference between the two,
affecting the price is the Solid-State Drive featured in the expensive
version. Basically, the cheap one has good, old hard disk, expensive
enjoys a disk produced with the technology similar to the one used in
Flash drives (found in USB dongles and iPod nanos).</p>
<p>Big question - is it worth it? Honest answer - HELL NO!</p>
<p>There has been a huge propaganda about how SSD is faster, more energy
efficient blah-blah. Beware - all of that is a lie! We’ve seen real-life
<a href="http://gizmodo.com/353324/the-macbook-air-ssd-performance-boost-pretty-much-non+existent">benchmark test
results</a>
that prove that SSD is not faster. Quite honestly it came as a surprise
to us, too, but facts are all out there.
<a href="http://storagemojo.com/2008/04/27/notebook-flash-ssd-market-fantasy-or-mirage/">StorageMojo</a>
published an excellent article, recently giving more details about the
situation and their verdict is also - No, no, no!</p>
<p>Don’t waste your money. If you are to buy a MacBook Air - go with the
less expensive model. It’s just as good for surfing and other
lightweight usages. Go MacBook Pro, if you are planning anything
hardcore.</p>
<p>Cheers.</p>
The Seven Habits of Highly Effective Internet Users
2008-04-25T00:00:00-04:00
http://www.freshblurbs.com/blog/2008/04/25/seven-habits-highly-effective-internet-users.html
<p>Nice and funny “analysis” of the Internet community on
<a href="http://blog.createdebate.com/2008/04/24/the-7-habits-of-highly-effective-internet-users/">CreateDebate</a></p>
<p><img src="http://qc.createdebate.com/img/blog_article_images/7-Habits-Internet.gif" alt="" /></p>
Must Read for Drupal
2008-04-22T00:00:00-04:00
http://www.freshblurbs.com/blog/2008/04/22/must-read-drupal.html
<p>Some of the blogs I often find to have useful Drupal information (in
alphabetical order):</p>
Calais Module for Drupal Released
2008-04-20T00:00:00-04:00
http://www.freshblurbs.com/blog/2008/04/20/calais-module-drupal-released.html
<p><img src="http://www.freshblurbs.com/files/calais_logo.png" alt="" /> One of the hottest
subjects in Web technologies, these days, is finding effective ways to
exploit <a href="http://en.wikipedia.org/wiki/Collective_intelligence">Collective
Intelligence</a> of
masses. Most everybody has heard of the so-called Web 2.0 and hundreds
of different definitions of what it is or is not. In simple terms, Web
2.0 is a phenomena characterized by vastly increased direct
participation of the user community in content authoring, mostly through
blogs and discussions around blogs. Web 2.0 has brought us to a state
where more and better content is freely available online than ever
before.</p>
<p>There is a major problem with collective intelligence, though:
information pieces are often disbursed. The more we move from the early
days of the Internet as static data publishing platform towards the
Internet, an aggregator of <em>Intelligence</em>, more do modern search engines
fall short of providing adequate results. Current technologies are often
unable to put information in context and help us connect the dots. It is
for that reason that there is an increased demand for tools that can
extract context off of content and can aggregate different data sources
in a meaningful way.</p>
<p>One of such tools that has caught some spotlight lately, has been
<a href="http://opencalais.com/">Calais Web Service</a>, released by the news
giant: Reuters.</p>
<blockquote>
<p>“The Calais web service allows you to automatically annotate your
content with rich semantic metadata, including Entities like People
and Companies and Events & Facts like Acquisitions and Management
Changes.” – <a href="http://opencalais.com">opencalais.com</a></p>
</blockquote>
<p>What is exceptional and interesting about the Calais web-service,
putting it beyond and above other free terms-extractor services (like
the one from
<a href="http://developer.yahoo.com/search/content/V1/termExtraction.html">Yahoo!</a>)
is that Calais provides context to extracted terms. For instance, when
Calais web service analyzes a piece of content and finds “George Bush”,
not only will it extract and return it as a term (keyword) relevant to
the text, but it will also tell you that George Bush is a Person.
Likewise, it will tell you that United States is a country. This may
seem trivial and simple, but if you put the added information (entity
type) to a good use, you can build systems much more intelligent than
you could with other, flat terms extraction tools.</p>
<p>Calais is a free Web Service. You can plug it into your applications
and/or content management systems and use it, without any charge .
<a href="http://agileapproach.com/user/frank">Frank</a> and I, spent a lot of our
time last month integrating it into <a href="http://drupal.org">Drupal CMS</a> and
are glad to announce that it is now available for both Drupal 5 and
Drupal 6. It is also the first integration of Calais API with a major
content-management system.</p>
<p>You can download Calais integration module from:<br />
http://drupal.org/project/opencalais<br />
You can also watch a short screencast Frank recorded to demo main
features of the module:
http://calais.phase2technology.com/content/calais-demo-screencast</p>
<p>The screencast was recorded before the code was finalized, so the module
can actually do more than you see in the screencast. You are encouraged
to download and test-drive it.</p>
<p>And last, but not least, we would like to express our gratitude to our
friends at the Calais team, for their invaluable help and support.</p>
Ballmer About iPhone - The Reign of Blind Stupidity
2008-04-17T00:00:00-04:00
http://www.freshblurbs.com/blog/2008/04/17/ballmer-about-iphone-reign-blind-stupidity.html
<p><a href="http://www.youtube.com/watch?v=wvsboPUjrGc&feature=related"><img src="http://www.freshblurbs.com/files/ballmer.jpeg" alt="Steve
Ballmer" /></a>
I do usually try to not bash any particular company, in my blog posts.
Every so often I may critique somebody and I like to think my criticism
is factual and constructive. This time around, though, I will allow
myself to go into a full-on ranting and smirking, because the person we
are talking about is <a href="http://www.youtube.com/watch?v=wvsboPUjrGc&feature=related">Mr. Steve
Ballmer</a>,
the infamous CEO of Microsoft, and the subject is - his ridiculous
“predictions” about iPhone.</p>
<p>I mean, we all understand why a Microsoft CEO would not love iPhone.
It’s also clear why he would try do diminish the importance of this
revolutionary device. Still, the job of a CEO, especially a giant like
Microsoft, is to be at least close to reality and not blurt random
stupidities publicly.</p>
<p>Let’s see what Ballmer was saying just a year ago:</p>
<blockquote>
<p>“<strong>There’s no chance that the iPhone is going to get any significant
market share</strong>. No chance,” said Ballmer. “It’s a $500 subsidized
item. They may make a lot of money. But if you actually take a look at
the 1.3 billion phones that get sold, I’d prefer to have our software
in 60% or 70% or 80% of them, than I would to have <strong>2% or 3%, which
is what Apple might get.</strong>”<br />
— <a href="http://arstechnica.com/journals/microsoft.ars/2007/04/30/ballmer-says-iphone-has-no-chance-to-gain-significant-market-share">Source: ArsTechnica, April
2007.</a></p>
</blockquote>
<p>And a year later, according to the report from Net Applications (Feb
2008), Safari on iPhone has 71% market share among mobile web-browsers
in the US, leaving only 12% to the next runner-up, the child-product of
Microsoft: Pocket IE.</p>
<p>Similarily, Canalys reports that as far as overall US “smart phone”
market goes, iPhone, in just over a year, has gained 28% market share,
only second to RIM (producer of Blackberry) that has 41%. If you take
into account how long have the competitors been on the market (and those
are wildly well-known brands like Palm, Nokia and others) and the fact
that RIM has been selling its Blackberries to corporate clients in large
bulks, for a while now and has tremendous head-start, the results are
just amazing.</p>
<p>Back to Ballmer’s “2-3% forecast” . Well, what can we say? Except state
the obvious and say that we can’t help feeling sorry for Microsoft when
Bill Gates fully retires and the software giant is left to the mercy of
Ballmer.</p>
<p>*smirk* (sorry, could not help it).</p>
Windows Is Too Monolithic
2008-04-15T00:00:00-04:00
http://www.freshblurbs.com/blog/2008/04/15/windows-too-monolithic.html
<p><img src="http://www.freshblurbs.com/files/windows.jpeg" alt="" /> It must be an unhappy
day in Redmond, today. A heavy-weight like Gartner bashing your main
product is no joke for any software development company, not even for
Microsoft.</p>
<p>As Gartner analyst Michael Silver declares:</p>
<blockquote>
<p><em>Microsoft’s Windows juggernaut is collapsing as it tries to support
20 years of applications and becomes more complicated by the minute.
Meanwhile, Windows has outgrown hardware and customers are pondering
skipping Vista to wait for Windows 7. If Windows is going to remain
relevant it will need radical changes….”Windows is too monolithic,”
says Silver.</em></p>
</blockquote>
<p>Well, what can we say? It’s long deserved.</p>
<p>Source: http://www.cnet.com/8301-13505_1-9916813-16.html</p>
<p>P.S. I think a smart move from Microsoft would actually be to base their
new operating system on a Unix-compatible architecture. And why not even</p>
<ul>
<li>an open-source one? Just like Apple did. Seriously, if you think about
it - every major, modern operating system is Unix-compatible, except
Windows. Does not make sense, does it?</li>
</ul>
Bring SFTP to OS-X: Magnetk ExpanDrive
2008-04-11T00:00:00-04:00
http://www.freshblurbs.com/blog/2008/04/11/bring-sftp-os-x-magnetk-expandrive.html
<p>Today is a great day for Macintosh users! Magnetk has released
<a href="http://www.magnetk.com/expandrive">ExpanDrive</a> - a tool allowing to
mount remote servers as local drives over ssh/sftp. Their press-release
promises to add more protocols. I am taking a not-so-wild guess here
that S3 will be one of the first protocols to get in.</p>
<p>But back to Magnetk. In the past I have used the Windows version of the
same tool they had - SftpDrive and have come to love it. It was actually
one of the few things I used to miss from Windows. I remember e-mailing
them and asking to give us, Mac users something like that, as well. They
promptly e-mailed back saying it was in works. And here we are with
ExpanDrive! Magnetk is clearly a company that lives up to its promises.</p>
<p>I have been evaluating ExpanDrive for couple hours now and it is
<strong>AWESOME!</strong>. I am gonna try it for a day or two more and am definitely
buying it.</p>
<p><strong>P.S.</strong> To be completely fair, we have to mention that there is an
open-source tool that aims at solving the same problem and it has been
around for a while: <a href="http://code.google.com/p/macfuse/">MacFuse</a> is its
name. I have used it.</p>
<p>Well, quite honestly bare-naked MacFuse is not in the same league, at
least for now (I suspect ExpanDrive is using MacFuse at least partially
if not in its totality). I am always the first to favor an open-source
alternative, but quite honestly, if you are serious about your SFTP
needs (like: developing a web application on a remote server),
ExpanDrive is <strong>well</strong> worth its modest price.</p>
Installing GIT on OS-X In 3 Minutes
2008-03-10T00:00:00-04:00
http://www.freshblurbs.com/blog/2008/03/10/installing-git-os-x-3-minutes.html
<p>How to install <a href="http://en.wikipedia.org/wiki/Git_(software)">GIT</a> on
OS-X in under 5 minutes:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git --version
</code></pre></div></div>
<p>I personally, also like to set:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git config --global color.ui "auto"
</code></pre></div></div>
Fortune Magazine: The trouble with Steve Jobs
2008-03-06T00:00:00-05:00
http://www.freshblurbs.com/blog/2008/03/06/fortune-magazine-trouble-steve-jobs.html
<p><img src="http://www.freshblurbs.com/files/jobs-iphone.png" alt="" />Fortune Magazine
published a great article about the legend, the Steve Jobs:\</p>
<p>http://money.cnn.com/2008/03/02/news/companies/elkind_jobs.fortune/index.htm</p>
<p>And while you are at that, checkout today’s <a href="http://events.apple.com.edgesuite.net/rtp20e92/event/index.html?internal=fj2l3s9dm">iPhone SDK Announcement
Video</a>,
as well. Some <strong>AWESOME</strong> announcements!</p>
Drupalcon 2008 Boston - Live
2008-03-03T00:00:00-05:00
http://www.freshblurbs.com/blog/2008/03/03/drupalcon-2008-boston-live.html
<p><strong>We are doing it!</strong></p>
<p><strong>Drupalcon 2008 Boston Live</strong></p>
<p>Check it out at: <a href="http://drupalconlive.com">http://drupalconlive.com</a></p>
Google Sites
2008-02-29T00:00:00-05:00
http://www.freshblurbs.com/blog/2008/02/29/google-sites.html
<p>http://sites.google.com/</p>
<p>One word - wow!</p>
<p>P.S. In the last years, Google has launched a number of mind-blowing
services, built on top of the products from the companies they had
acquired, but in most cases - failed miserably to gain user traction.
IMHO, one bright example of this is Google Apps (“Google Office”), but
examples are numerous. Will “Sites” be different?</p>
How Many Drupal Modules Are Out There?
2008-02-26T00:00:00-05:00
http://www.freshblurbs.com/blog/2008/02/26/how-many-drupal-modules-are-out-there.html
<p>We all know that Drupal has a lot of modules. But do you know –
exactly how many?</p>
<p><[ <a href="http://agileapproach.com/blog-entry/quick-trivia-how-many-drupal-modules">Find out
here</a>
]></p>
TDD Can Be Horseshit?
2008-02-18T00:00:00-05:00
http://www.freshblurbs.com/blog/2008/02/18/tdd-can-be-horseshit.html
<p>InfoQ has published a very insightful discussion between Jim Coplien and
Bob Martin about some advanced aspects of test-driven-development,
unit-testing and software architecture. It’s been a while since I have
listened to a wise discussion about software architecture like this one.</p>
<p>Check it out: http://www.infoq.com/interviews/coplien-martin-tdd</p>
<p>In case you are wondering, I definitely agree with Jim. Bob is taking
TDD way too far, for the sake of “code-purity”, rather than business
need and I have no interest in that kind of nerdiness :)</p>
<p>To give one example, Bob claims that writing a production code without a
unit-test, in 2007, is irresponsible and unprofessional. Too radical!
Most of Linux is written without unit-tests, most of Drupal is written
without unit-tests. Both of them are awesome examples of quality code
that “just works”. And the reference to “2007” is just lame. Whatever
worked 10 years ago, still does.</p>
<p>Yes, we may have learned some new things and there is definitely some
merit to unit-testing, but no production code without a unit-test?
Whatever, dude!</p>
The Infamous Apple Customer Care
2008-02-18T00:00:00-05:00
http://www.freshblurbs.com/blog/2008/02/18/infamous-apple-customer-care.html
<p><img src="http://www.freshblurbs.com/files/applelogo.jpg" alt="" /> Apple’s products are
usually of high quality, on the bleeding edge of innovation and always -
cool. None of these characteristics are applicable to Apple retail
service. Yes, stores are clean and cozy and the online store - very
intuitive, but those are about the only positive things anyone can say
about shopping at Apple. The producer of iPods has very outdated (hence
weird) distribution rules. They are trying to protect regional
distributors from the cannibalization of each-other’s businesses, by
enacting a plethora of constraints, governing who can sell what, where.</p>
<p>Couple days ago, I was looking for a Macbook Air with French keyboard
layout for a buddy of mine. I called a local Apple store (one of the
largest in the area) and inquired about the availability of a French
layout. I got a very cold “no way” in response. Not willing to give up,
I asked what would somebody need to do in the US, if he or she wanted to
get a laptop with French keyboard layout.</p>
<p>“In order to get one, you will have to fly to Paris or Canada, at least”</p>
<ul>
<li>was the “response of reason” that left me speechless.</li>
</ul>
<p>Cruuuuhaaaaazyyyyy</p>
Some Thoughts About Hiring The Right People
2008-02-15T00:00:00-05:00
http://www.freshblurbs.com/blog/2008/02/15/some-thoughts-about-hiring-right-people.html
<p>In the Information Age, any competitive advantages that a company may
possess can quickly disappear. Any unique assets can become commodity
overnight. The only true differentiator companies can rely on is the
skill-set and talent of its workforce. We share with you some thoughts
about how to acquire and retain the best people, in the tough market.</p>
<p><a href="http://agileapproach.com/blog-entry/do-you-dig-your-employer">Click
here</a> for
a full text.</p>
Clear DNS Cache on OS-X
2008-02-01T00:00:00-05:00
http://www.freshblurbs.com/blog/2008/02/01/clear-dns-cache-os-x.html
<p>If you are a developer (just a geek will do, too), you have definitely
put a fake DNS entry or two in your /etc/hosts file, at one time or
another. Few things are more frustrating than doing that and having to
restart your computer for the change to pick up. If you are running a
local caching dns server (e.g. BIND) a glitch like that can happen all the time.</p>
<p>No worries, though. The little command below, ran from the Terminal,
will clear dns cache and let your changes be applied instantaneously:</p>
<p>On OS-X:</p>
<ul>
<li>OS-X (before Leopard): <code class="language-plaintext highlighter-rouge">lookupd -flushcache</code></li>
<li>OS-X 10.5+ (Leopard and up): <code class="language-plaintext highlighter-rouge">dscacheutil -flushcache</code></li>
</ul>
<p>On other platforms:</p>
<ul>
<li>Windows (NT-based versions): <code class="language-plaintext highlighter-rouge">ipconfig /flushdns</code></li>
<li>Linux: <code class="language-plaintext highlighter-rouge">/etc/rc.d/init.d/nscd restart</code></li>
</ul>
Recursively Removing Subversion Files
2007-12-20T00:00:00-05:00
http://www.freshblurbs.com/blog/2007/12/20/recursively-removing-subversion-files.html
<p>More often than we’d like to acknowledge we get a need to remove
Subversion .svn files in the working copy.</p>
<p>This will do it:\</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>find . -name .svn -print0 | xargs -0 rm -rf
</code></pre></div></div>
Drupal Theme Developer's Cheat Sheet
2007-12-19T00:00:00-05:00
http://www.freshblurbs.com/blog/2007/12/19/drupal-theme-developers-cheat-sheet.html
<p>A very handy PDF with a list of variables available when themeing
Drupal: <a href="http://www.minezone.org/blog/2007/12/18/drupal-theme-developers-cheat-sheet/">Download
PDF</a></p>
Google Knol
2007-12-18T00:00:00-05:00
http://www.freshblurbs.com/blog/2007/12/18/google-knol.html
<p>Ok, finally Google is starting to make a move against Wikipedia, with
the private launch of <a href="http://googleblog.blogspot.com/2007/12/encouraging-people-to-contribute.html">Google
Knol</a>.
The specifics of the system are not yet known, but from what we can read
between the lines, the interesting difference betwen Knol and Wikipedia
is that in Knol content will be authored by a “group of experts” (that
will later be able to share ad-revenue with Google for their efforts?).</p>
<p>If this is true, then clearly Google is responding to the long-standing
joke (started in the TV show Office) that Wikipedia is reliable “because
anybody can edit it”. Google must be proud to “have gotten the
message”… of all conservatives who refuse to accept Wikipedia.</p>
<p>Good job, Google! Nice swing from a progressive thinking away and into
aligning with stagnating conservativism. So, Google does not believe in
the <a href="http://en.wikipedia.org/wiki/The_Wisdom_of_Crowds">Wisdom of
Crowds</a>, anymore? And
here we thought the whole point James Surowiecki was making was that
crowds are always smarter than a bunch of “experts”. Ironic, how we are
going back to “experts”, is not it?</p>
<p>You, my friends, can make “Knols” (What the heck is this with Google
people trying to come up with an alternative English, anyway?) as your
“the first thing someone who searches for this topic for the first time
will want to read.”, but I am sticking with Wikipedia. Wiki has been the
first entry into a new subject, for me, for a long time now and I am not
complaining.</p>
<p>I think Google is just desperately reacting to the unfortunate reality
that people now prefer to start research in Wikipedia rather than
Google. Desperation is never a good adviros, though and Google seems to
be missing the point.</p>
<p>I assess the chances of Knol’s success somewhere near that of Google
Video and Orkut.</p>
<p>*sigh*</p>
The Best SFTP Plugin for Eclipse
2007-12-11T00:00:00-05:00
http://www.freshblurbs.com/blog/2007/12/11/best-sftp-plugin-eclipse.html
<p>The best and, honestly, the only usable SFTP and/or FTP plugin for
Eclipse is <a href="http://www.eclipse.org/dsdp/tm/">Target Management</a>. This
plugin makes over-the-SSH development in Eclipse a practical
possibility.</p>
<p>One of the greatest features of this plugin is that it allows working
with files, without creating a project, something that vanilla Eclipse
is insanely paranoid about. Out-of-the-box Eclipse forces you to first
create a project. As a consequence, even if you map a remote server as a
network drive, over SSH, you may still have problems working in Eclipse.
Reason being - Eclipse constantly analyses project files and over SSH it
is just too darn slow.</p>
<p>You can use Target Management for local development, too, if you hate
creating projects. Actually, it makes sense for PHP development. Whilst
Java developers always think in terms of projects and dependencies
(guess why - they need to build the darn thing), PHP developers do not
have to carry the same burden and may choose to avoid the overhead. By
the way - if you are using Eclipse for PHP, you definitely need to
install PDT plugin and the easiest way is to install a pre-built,
“bundled” version that you can find on the PDT download page:
[<a href="http://download.eclipse.org/tools/pdt/downloads/">http://download.eclipse.org/tools/pdt/downloads/</a>]</p>
<p>If you are serious about using Eclipse as your IDE, you definitely need
this plugin.</p>
<p>Please note that you have to install
<a href="http://www.eclipse.org/cdt/downloads.php">CDT</a> plugin, before you can
install Target Management. Also, CDT is not part of standard Eclipse
distribution so you need to add the update site, just “install required”
will not help. The update URL for CDT is:
http://download.eclipse.org/tools/cdt/releases/europa</p>
<p>When you are done installing TM, add its primary view to your
perspective via:<br />
Window -> Show View -> Remote Systems<br />
and start enjoying.</p>
Del.icio.us Tag Filtering in PHP/Drupal
2007-11-29T00:00:00-05:00
http://www.freshblurbs.com/blog/2007/11/29/del-icio-us-tag-filtering-php-drupal.html
<p>Filtering content through <a href="http://del.icio.us/help/navigation">URI
tagging</a> was initially popularized
by <a href="http://del.icio.us/">Del.icio.us</a> and is now a common way to quickly
navigate content. For instance, in a system that supports this type of
navigation, you can constract a URL:\</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>http://example.com/tag/drupal+news,rss
</code></pre></div></div>
<p>and get a vertical view of the domain data. In this markup, “+” stands
for logical AND, whereas “,” stands for logical OR.</p>
<p>Following is a PHP code snippet that processes “delicioused” query
string into a logical expression (you can modify the code slightly and
get an SQL where clause instead). In addition to the original
del.icio.us syntax, it allows tags with spaces in them. You just need to
enclose those in single or double quotation marks. For instance, the
following expression is a valid one:
http://example.com/tag/drupal+news,rss,’Steve Jobs’. Note: using
quotation marks inside the tag names is still invalid syntax!</p>
<p>And following is the code sample:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><?
//Node: URL processor converts "+"s in the URL into spaces " ", so we are taking
//additional steps to distinguish the two post-factum. Namely, you need to enclose
//all spaces-containing tags in quotation marks
function parseargs ( $reqstr ) {
//escape the spaces in tags inside quotation marks:
$pattern = '/\'.*?\'/';
$reqstr = preg_replace_callback ($pattern,"replacementcallback",$reqstr);
$pattern = '/".*?"/';
$reqstr = preg_replace_callback ($pattern,"replacementcallback",$reqstr);
//replace the rest of the spaces with plus signs
$reqstr = preg_replace ( '/\s+/', '+', $reqstr);
//remove quotation marks
$reqstr = preg_replace ( array('/"/', '/\'/'), '', $reqstr );
//split into tags and corresponding operands: + and ,
$arguments = preg_split( '/([,+])/',$reqstr,-1,PREG_SPLIT_DELIM_CAPTURE );
//You can modify the code from here if you need to generate an
//SQL Where clause instead.
$rejoined = implode(" ",$arguments);
$rejoined = preg_replace ( array( '/\+/', '/,/'), array('AND','OR'), $rejoined);
$rejoined = urldecode ( $rejoined );
// echo "
$rejoined
";
return $rejoined;
}
// in parseargs, we need to replace spaces
// in all quote-enclosed substrings with "%20s". The
// only practical way of doing that is with preg_replace_callback
function replacementcallback ( $match ) {
$input = $match[0]; // For our case, it's always one match.
$ret = preg_replace('/\s+?/', '%20', $input );
return $ret;
}
?>
</code></pre></div></div>
Drupal: Latest Comments Block in User Profile.
2007-11-26T00:00:00-05:00
http://www.freshblurbs.com/blog/2007/11/26/drupal-latest-comments-block-user-profile.html
<p>In Drupal 5, if you want the User Profile page (e.g.
http://example.com/user/stevejobs) to display latest comments by that
user, you can apply a quick hack:</p>
<ol>
<li>Create or edit <em>user.profile.tpl.php</em> file in your theme</li>
<li>
<p>Add the following code anywhere (wherever you want latest comments
to appear) in the file:\</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><?php$output = ""; $nlimit = 7;$userid=$user->uid;// ATTENTION: status=0 - approved, status=1 in queue.$query= "SELECT c.cid, c.nid, c.name, c.subject FROM {comments} c WHERE c.uid = %d AND c.status = 0 ORDER BY c.timestamp DESC";$result = db_query_range($query,$userid,0,$nlimit);$output .= "<div class=\"item-list\"><ul>\n";$no_comments = mysql_affected_rows ();if ( $no_comments > 0 ) { while ($obj = db_fetch_object($result)) { $link = url("node/$obj->nid"); $link = $link."#comment-".$obj->cid; $output .= "<li><a href=\"$link\">$obj->subject</a></li>"; }} else { $output .= 'No Comments left so far.';}$output .= "</ul></div>";print $output;?>
</code></pre></div> </div>
</li>
</ol>
How Addicted To Apple Are You?
2007-11-23T00:00:00-05:00
http://www.freshblurbs.com/blog/2007/11/23/how-addicted-apple-are-you.html
<p><a href="http://www.justsayhi.com/bb/apple_addiction">Just how addicted to Apple are
you?</a></p>
<p>Apparently, I am 94% addicted.</p>
<p><img src="http://www.freshblurbs.com/files/addictedtoapple.png" alt="" /></p>
<p>Not really a surprise to anybody who knows me :)</p>
How to Hack 'Read More' in Drupal
2007-11-21T00:00:00-05:00
http://www.freshblurbs.com/blog/2007/11/21/how-hack-read-more-drupal.html
<p>As you know Drupal displays the “Read more” link among all other
after-teaser links in the blog postings view. This is not a usual
user-experience. Most users expect “read more” link to be right after
the teaser part of the posting. It can get confusing, so following is a
quick-n-dirty hack that can fix it for you:</p>
<p>Locate the piece of code in node.tpl.php where it reads like:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <?php print $content ?>
</code></pre></div></div>
<p>Put the following right after it:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><?php
// Extract "read more" link from $links so we can display it separately.
if (preg_match('!<a[^>]+>'.t('Read more').'</a>!', $links, $match)) {
$links = preg_replace('/<a.+?href.+?>'.t('Read more').'<\/a>/i', '', $links);
$more = '<div align="right">'. $match[0] . '</div>';
$more = str_replace ("Read more", "Read the rest of the posting...", $more);
}
else {
$more = '<span class="readmore-fill"></span>';
}
if ($more) { print $more; }
?>
</code></pre></div></div>
FCKEditor in HTTP Secured Websites
2007-11-21T00:00:00-05:00
http://www.freshblurbs.com/blog/2007/11/21/fckeditor-http-secured-websites.html
<p>Usually, you do not want websites that are still under development to be
visible to the Web at large. Even if you do not care about that, at the
least - you do not want such websites to be indexed by search engine
bots. Bottomline - you want the “dev” websites behind a lock. One way to
secure, is to restrict IP addresses, but then - that is so ’90s! In the
modern world we are way too mobile, for such approaches. They will just
add annoyance and stand in the way of productivity. If you are using
Drupal, one solution is to use the
<a href="http://drupal.org/project/securesite">Securesite</a> module. Or maybe not.
In a busy development shop you usually deal with a dozen of
under-the-development projects and triple that amount of projects that
you maintain, hence still have dev environments for. Maintaining
Securesite for each one of them is a maintenance nightmare. Please note,
we are not even mentioning how buggy Securesite is and how it conflicts
every time you try to do something advanced. Where I work, we chose a
parsimonious approach.</p>
<p>We keep virtual-host folders of all our “dev” sites under /var/www/dev.
In the same folder we have an “.htaccess” file that protects folders
underneath with a universal user/password (clearly, in this case
security is not a matter of life-and-death). Everything works like a
charm - you want a site protected? Move it under /var/www/dev. You want
it public? Move it to /var/www/vhosts. The problem, however, arises when
trying to use FCKeditor with the protected sites. FCKeditor issues some
“interesting” HTTP request as part of the file (image) upload workflow.
When website is HTTP protected, you will get an error message like this:
<img src="http://www.freshblurbs.com/files/fckeditor-apache.png" alt="" /> Bummer! The
workaround is to allow the specific URI FCKEditor is requesting. Since
we are mainly looking for a way to “scare” the search bots away and
security is not a pressing issue, we can do it without a worry. The
final .htaccess file will look something like the following:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>AuthUserFile /opt/lampp/etc/.htpasswd-usersAuthGroupFile /dev/nullAuthName "Protected Area. Please, provide login credentials."AuthType Basic <Files "*"> require user devsec </Files> <FilesMatch "connector.*?$"> Allow from all </FilesMatch>
</code></pre></div></div>
FCKeditor vs TinyMCE
2007-11-16T00:00:00-05:00
http://www.freshblurbs.com/blog/2007/11/16/fckeditor-vs-tinymce.html
<h2 id="its-official---we-are-migrating-to-fckeditor">It’s official - we are migrating to FCKeditor</h2>
<p>A WYSIWYG HTML editor is a necessary part of any Web-based, CMS system.
You simply can not expect user audience to be fluent in HTML.</p>
<p>We’ve been using <a href="http://drupal.org/project/tinymce">TinyMCE</a> with
<a href="http://drupal.org/project/imce">IMCE</a> (for image upload), in all our
Drupal installations, for a long time now. About 2 years ago we did
comparison of TinyMCE vs
<a href="http://drupal.org/project/fckeditor">FCKeditor</a> and Tiny came up as an
undoubted winner. However, it’s far from flawless and during these
years, we’ve had loads of headache dealing with its bugs and frustrated
users.</p>
<p><img src="http://www.fckeditor.net/images/demo_screenshot.gif" alt="" /> Recently, we
re-visited our WYSIWYG editor policy and noticed that FCKeditor has come
a very long way during last year. We installed it and immediately saw
huge difference in both stability, as well as user-friendliness.</p>
<p>We’ve been using FCKeditor on some of our Drupal installations for some
time, now and today we made a final decision to migrate all our
installations to FCKeditor. We are using the latest stable release:
2.4.3. We tried the beta release of 2.5.x because this is the first
version that supports Safari browser, but unfortunately it’s still too
buggy for production use (or Drupal integration is). Hopefully, 2.5 will
mature soon, since we are very eager to add Safari support.</p>
Drupal Request Handlers - Callbacks
2007-11-15T00:00:00-05:00
http://www.freshblurbs.com/blog/2007/11/15/drupal-request-handlers-callbacks.html
<p><img src="http://www.freshblurbs.com/files/train.jpeg" alt="" /> In our <a href="http://www.freshblurbs.com/drupal-bootstrap-request-processing-drupal">recent
post</a>
we tried to introduce you with the HTTP request life-cycle in Drupal. If
you read the post, hopefully you have a better understanding of what
stages a request goes through in Drupal. Today we will try to give a
specific example of how this understanding can help you in your daily
work with Drupal.</p>
<p>Drupal is a modular and extensible content-management system (CMS).
Among other things, this also means that a typical complex web-site is
built using large number of Drupal modules. Some of these modules even
change each-other’s functionality through the use of
<a href="http://api.drupal.org/api/group/hooks/5">Hooks</a>.</p>
<p>The spirit of open-source is in “hacking” (by which we mean building
your work on top of other people’s genius creations, not - damaging
software systems) code. With a system so large and complex - how do you
know which piece of code to mess with? When tweaking complex Drupal
installations, more often than not, you find yourself wondering the same
question:</p>
<h2 id="where-is-the-code-that-renders-the-output-for-uri-xxxyyy">Where is the code that renders the output for URI /xxx/yyy?</h2>
<p>The answer to this question is non-trivial. Drupal allows any module to
register callback functions for any URI or a portion of URI. For
instance different functions can be handling “/rss/*” and
“/rss/xml/*”. Callback handlers matching more specific URIs take
precedence. Handlers are registered in <a href="http://api.drupal.org/api/function/hook_menu/5">menu
hook</a> functions within
the module source code.</p>
<p>That’s all sweet and cute, but if you have 30 modules installed, how are
you going to find the specific handler? An easy solution is to get
Drupal’s help and have Drupal log a handler for each request. To achieve
this, you need to edit menu_execute_active_handler() function in
includes/menu.inc. In the beginning of that function, locate the lines
containing the following code:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> // Determine the menu item containing the callback.
$path = $_GET['q'];
while ($path && !isset($menu['callbacks'][$path])) {
$path = substr($path, 0, strrpos($path, '/'));
}
</code></pre></div></div>
<p>and insert this code snippet, directly after it:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> if ($path !== '' || isset($menu['callbacks'][$path])) {
$callback = $menu['callbacks'][$path];
if ( is_array($callback) ) {
$cb = $callback['callback'];
error_log ("===> URI Path: \"$path\" is handled by: $cb()");
}
}
</code></pre></div></div>
<p>Some final comments:</p>
<ul>
<li>Make sure you have <a href="http://www.freshblurbs.com/basic-php-logging">PHP
Logging</a> properly
configured and you know where log files are for a specific virtual
host.</li>
<li>
<p>Please pay attention to the output. Drupal uses URI for both
resource and arguments, if Clean URLs are enabled and you may get a
response that indicates that request handler matches only part of
the URL. For instance, if you are requesting a URI
/supertag/programming, the actual resource may be “supertag” and the
token “programming” - just an argument. In such case the code above
will say something like:\</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>===> URI Path: "supertag" is handled by: supertag_somefunction()
</code></pre></div> </div>
</li>
<li>If you the output says that request is handled by
views_view_page(), it means you are requesting a Drupal
Views-driven page and you may want to look for more details in the
Views admin user-interface, rather than in the code.</li>
</ul>
Basic PHP Logging
2007-11-15T00:00:00-05:00
http://www.freshblurbs.com/blog/2007/11/15/basic-php-logging.html
<p>One of the most powerful ways to debug a web application is using
logging; especially for a highly complex system like Drupal. PHP comes
with a built-in logging function:
<a href="http://us2.php.net/error_log">error_log();</a>. The exact behavior of
this function depends on several configuration parameters.</p>
<p>We suggest that you log into standard Apache error log and create one
log per virtual host. To achieve this, make sure that in php.ini you
have “error_log = “ directive commented-out, so that PHP does not log
either in one specific file or syslog, and also make sure you have
“log_errors = On”. In addition, in httpd.conf (or wherever you have
virtual hosts configured in Apache) for the virtual host configurations,
make sure you have separate log files per a Virtual Host with a
directive like: ErrorLog logs/buzzmonitor.log</p>
<p>The basic logger is not as powerful as the <a href="http://www.freshblurbs.com/drupal-debugging-pear-logging">PEAR
logger</a>, but
is much safer. If you use PEAR logger, you must be sure that anywhere
your code will be installed, PEAR Log module will be installed, too.
That is not a safe assumption, especially for Drupal developers that
publish their code in open-source.</p>
Drupal: TinyMCE Youtube Plugin
2007-11-13T00:00:00-05:00
http://www.freshblurbs.com/blog/2007/11/13/drupal-tinymce-youtube-plugin.html
<p><img src="http://www.freshblurbs.com/files/youtube.png" alt="" /> You can not use
YouTube’s “embedable” code snippet in a WYSIWYG Javascript editor like
TinyMCE. That can get very uncomfortable, leading to frequent need to
switch back-and-forth between the HTML view and WYSIWYG view. Not
user-friendly at all. Fortunately, TinyMCE does have a “plugin” that
supports Youtube.</p>
<p>Download: file youtube_xhtml_workaround.zip from the<br />
<a href="http://sourceforge.net/tracker/index.php?func=detail&aid=1669296&group_id=103281&atid=738747">YouTube
Button</a>
Issue ticket on SourceForge. <a href="http://sourceforge.net/tracker/download.php?group_id=103281&atid=738747&file_id=223305&aid=1669296">Direct
Link</a></p>
<p>Follow the instructions at:<br />
http://drupal.org/node/154877#comment-253803</p>
Drupal Bootstrap - Request Processing in Drupal
2007-11-12T00:00:00-05:00
http://www.freshblurbs.com/blog/2007/11/12/drupal-bootstrap-request-processing-drupal.html
<p><img src="http://www.freshblurbs.com/files/drupal.png" alt="" /> In this blog post I try
to list the sequence of steps Drupal 5 takes to process an HTTP request.
I have not seen it all put together in any one place. I do, however,
believe that understanding the request life-cycle is crucial to grasping
how a web-system works, so I hope this post will be useful to some
people.</p>
<p>Drupal 5 uses a mechanism it calls Bootstrapping, to process an HTTP
request. It is so complex that a book can easily be written about it,
but that is obviously not my purpose. Therefore, I try to be laconic and
concentrate on making the “diagram” rather expressive than detailed.</p>
<p>Disclaimer: inline comments from Drupal source code were used to compile
this text.</p>
<ul>
<li>index.php</li>
<li><strong>bootstrap.inc:</strong></li>
<li>drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
<ul>
<li>_drupal_bootstrap(DRUPAL_BOOTSTRAP_CONFIGURATION);</li>
<li>_drupal_bootstrap(DRUPAL_BOOTSTRAP_EARLY_PAGE_CACHE); -
non-database cache.</li>
<li>_drupal_bootstrap(DRUPAL_BOOTSTRAP_DATABASE);</li>
<li>_drupal_bootstrap(DRUPAL_BOOTSTRAP_ACCESS); - identify and
reject banned hosts.</li>
<li>_drupal_bootstrap(DRUPAL_BOOTSTRAP_SESSION);</li>
<li>_drupal_bootstrap(DRUPAL_BOOTSTRAP_LATE_PAGE_CACHE); -
start the variable system and try to serve a page from the
cache.</li>
<li>_drupal_bootstrap(DRUPAL_BOOTSTRAP_PATH); - set $_GET[‘q’]
to Drupal path of request</li>
<li>_drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);</li>
<li><strong>common.inc</strong>->_drupal_bootstrap_full();
<ul>
<li>drupal_set_header(‘Content-Type: text/html;
charset=utf-8’); - hard-coded!</li>
<li>unicode_check();</li>
<li>fix_gpc_magic(); - undo magic quotes</li>
<li>module_load_all();</li>
<li>locale_initialize(); - initialize the localization system.
Depends on i18n.module being loaded already</li>
<li>module_invoke_all(‘init’);</li>
</ul>
</li>
<li><strong>menu.inc</strong> -> menu_execute_active_handler();<br />
<em>via</em> menu_get_menu() - going through the <a href="http://api.drupal.org/?q=api/function/hook_menu/HEAD">menu
hooks</a> of
all modules, determines the callback function registered to
process current URI and delegates to it, or returns either
MENU_ACCESS_DENIED or MENU_NOT_FOUND.</li>
</ul>
</li>
<li><strong>theme.inc</strong> -> theme(‘page’, $return); - wraps the output of the
callback function into a page-wide theme.</li>
</ul>
Feed Aggregators in Drupal
2007-11-08T00:00:00-05:00
http://www.freshblurbs.com/blog/2007/11/08/feed-aggregators-drupal.html
<p>An interesting review, from Aron Novak, of different feed aggregators
available in Drupal:<br />
http://groups.drupal.org/node/4547</p>
Drupal: Limit Roles in Users List
2007-11-06T00:00:00-05:00
http://www.freshblurbs.com/blog/2007/11/06/drupal-limit-roles-users-list.html
<p><a href="http://pierrelord.com/">Pierre</a> today needed a Drupal hack to limit the
set of roles, members of which would be displayed on a Drupal users
listing page. This is the listing that comes up when you access a URI
like: http://example.com/profile. Of course, it took us less than 5
minutes to figure-out how to do it, since Drupal is so awesome. When we
were done, we thought about it (yes, it was quicker to do than analyze)
and it’s a pretty useful hack. I mean, it should be a quite common need
to only display, say, bloggers in the user listing but not expose admin
user and other technical members.</p>
<p>I am too lazy to make a module of the hack, but here are simple steps of
how to do the same on your Drupal install:</p>
<ol>
<li>Open modules/profile/profile.module file for editing</li>
<li>Find function definition for theme_profile_listing($account,
$fields = array())</li>
<li>
<p>In the beginning of the function insert something like:\</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> //--- HACKED.
if ( !in_array("blogger", $account->roles ) ) return "";
//--- End HACK
</code></pre></div> </div>
<p>where “blogger” is the role members of which you want to be
displayed in the listing. If you have several such groups, you can
do something like:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> //--- HACKED.
if ( !in_array("blogger", $account->roles )
&& !in_array("editor", $account->roles ) ) return "";
//--- End HACK
</code></pre></div> </div>
</li>
</ol>
<p>where you will now be displaying members of “blogger” and “editor”
groups. You can keep adding groups like that until the code gets too
ugly at which point you can ask yourself - why in the world do you need
so many groups? or write a different code.</p>
<p>Have fun</p>
OpenSocial - The Future of The Web?
2007-11-05T00:00:00-05:00
http://www.freshblurbs.com/blog/2007/11/05/opensocial-future-web.html
<p><img src="http://www.freshblurbs.com/files/opensocial.png" alt="" /> Last week, the
major news on the Web was the launch of
<a href="http://code.google.com/apis/opensocial/">OpenSocial</a>. Google did an
excellent job documenting APIs and publishing quick-start tutorials and
videos, as well as signing-up an impressive group of early adopters. All
that is left to us, the blogger by-standers, is to review, envy and
criticize. That is exactly what we are going to do.</p>
<p>Since it’s too early, I, personally have only a few, quick comments.
These comments may be totally off, so I insist on the right to change my
statement at-will. Nevertheless, the first impression of OpenSocial is
highly positive. The API is clear, concise and pragmatic. Pragmatism and
(at least an attempt of) parsimony are a necessary feature for such API.
It seems like Google is on the right track on that front.</p>
<p>Some of our readership, coming from the Java/J2EE world, may draw
parallels between OpenSocial and Java Portlets API
(<a href="http://jcp.org/en/jsr/detail?id=168">JSR-168</a>). Java Portlets API was
created about four years ago, intended to be a plugin infrastructure for
Java-based web sites (a plan much less ambitious than that of
OpenSocial) and - failed miserably. The main reason why it failed was
that it was too restrictive in the areas that do not matter, and too
general in the areas they should have described in detail. Areas like
user profile management, user actions, user interactions. Basically,
JSR-168 was page-centric, rather than user-centric and the demand is for
a user-centric integration. Rendering is a job of a container.</p>
<p>OpenSocial has clearly avoided the trap that JSR-168 fell into. They
concentrate on the right features: people, activities, persistence. The
choice of the platform - Javascript, REST (bye-bye SOAP), Atom, RSS,
HTML and CSS makes complete sense. The API is quite modular, reasonably
high-level and what seems like flexible-enough to allow for all kinds of
applications. We were shown some very different applications in the
demos, created by different vendors.</p>
<p>Now that we have praised OpenSocial enough, and probably nobody had any
doubt in its huge potential, anyway, let’s mention some oddities, we’ve
noticed:</p>
<ol>
<li>Quickly scanning through the API, we could not find any direct
support for internationalization. The ultimate API for social
networks, without a strong support for transparent, easy translation
mechanism?</li>
<li>The API, whilst clean and lean, is very conservative in its
architecture. Not that it’s wrong or bloated, but it’s too
straightforward. Let’s use an analogy to explain what we mean. There
are many Ajax-based libraries. Out of these,
<a href="http://jquery.com/">jQuery</a> stands out like a rock-star. Not only
it gets job done, and gets it done well, but it has a unique,
elegantly revolutionary approach that none of the other libraries
have (not even Google’s own GWT).
When you look at an API that is supposed to change the reality on
the Web, you do kindof expect the design to be revolutionary as
well. Not safe, correct and conservative, but - leaping in the
future. Well, maybe I am too much of a geek and just complaining,
but I do think there’re enough of other code-purists that would
agree.</li>
</ol>
Beware: eAccelerator and PHP ZLIB Compression
2007-11-05T00:00:00-05:00
http://www.freshblurbs.com/blog/2007/11/05/beware-eaccelerator-and-php-zlib-compression.html
<p><img src="http://www.freshblurbs.com/files/code.jpg" alt="" />On numerous LAMP servers
we run, we repeatedly experienced an odd and disturbing problem. Users
were fed some “random” ASCII text, instead of a rendered page, leaving
them in complete frustration. After rigorous investigation, we came to a
conclusion that the problem lies in a combination of PHP’s zlib
compression and eAccelerator. The odd part that greatly complicated
debugging was that only some users experienced the problem.</p>
<p>eAccelerator is a “free open-source PHP accelerator, optimizer, and
dynamic content cache”. It’s also one of the most widely used and stable
implementations. The performance gains from eAccelerator are very
imperssive, especially since there is no code-change involved and cache
is transparent - data is real-time.</p>
<p>zlib comperssion is a PHP feature that compresses output (pages) and can
significantly decrease both traffic usage, as well as page load times.</p>
<p>Unfortunately, the two do not work well together.</p>
<p>In our case, we decided to retain eAccelerator, since Apache was
handling content compression on the front-end for us, anyway. To disable
zlib comperssion in php.ini, you need to set:<br />
zlib.output_compression = Off</p>
<p>Gzip compression in Apache is enabled with a code like below, that you
put in httpd.conf or .htaccess file.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><Location />
# Insert filter
SetOutputFilter DEFLATE
# Netscape 4.x has some problems...
BrowserMatch ^Mozilla/4 gzip-only-text/html
# Netscape 4.06-4.08 have some more problems
BrowserMatch ^Mozilla/4\.0[678] no-gzip
# MSIE masquerades as Netscape, but it is fine
# BrowserMatch \bMSIE !no-gzip !gzip-only-text/html
# NOTE: Due to a bug in mod_setenvif up to Apache 2.0.48
# the above regex won't work. You can use the following
# workaround to get the desired effect:
BrowserMatch \bMSI[E] !no-gzip !gzip-only-text/html
# Don't compress images
SetEnvIfNoCase Request_URI \
\.(?:gif|jpe?g|png)$ no-gzip dont-vary
# Make sure proxies don't deliver the wrong content
Header append Vary User-Agent env=!dont-vary
</Location>
</code></pre></div></div>
reCaptcha and Save a Book
2007-11-02T00:00:00-04:00
http://www.freshblurbs.com/blog/2007/11/02/recaptcha-and-save-book.html
<p><img src="http://www.freshblurbs.com/files/recaptcha.png" alt="" /> Web these days is
full of spam-bots, malicious crawlers and other “e-pests” that post
junk-advertising all over the Net. These parasites give the most
headache to blogs and social sites, where moderators want to free-up
comments to general audience (“Two-Way Communication”, eh?), but have no
desire to promote illegal Viagra sales.</p>
<p><a href="http://en.wikipedia.org/wiki/Captcha">Captcha</a>, or <em>Completely
Automated Public Turing test to tell Computers and Humans Apart</em>, is one
of the most effective tools to fight evil machines with. Unfortunately,
not all Captcha is equal. Many Captcha systems are vulnerable and have
been hacked, rendered useless against all but the most primitive
spamming.</p>
<p><a href="http://recaptcha.net/">reCAPTCHA</a> is a service from Carnegie Mellon
University. This service is a prime example of blending pleasant with
useful in a very Web 2.0-ish way. reCAPTCHA provides a free,
high-quality protection and at the same time helps digitize old books.
Every time you use reCaptcha, you help digitize one word of a book that
was written before the digital age. How much cooler can it get? Well,
reCaptcha also provides enhanced accessibility through audio-Captchas.
That one is not easy to “code” yourself, and I don’t know of any other
free service that offers it.</p>
<p>Great job, guys!</p>
Syntax-Highlighted Textareas with HTML and Javascript
2007-11-01T00:00:00-04:00
http://www.freshblurbs.com/blog/2007/11/01/syntax-highlighted-textareas-html-and-javascript.html
<p><img src="http://www.freshblurbs.com/files/codepress.png" alt="" /> As web applications
become increasingly smarter and powerful, we start to spend more time in
a browser window than in any other desktop application. MS
Office-replacement suites like <a href="https://www.google.com/a/org/">Google
Apps</a>, are first to come to mind, but
there are many other cool apps. Web-based collaboration is especially
web-centric. Wikis, blogs and community sites are all authored using
text-areas in a browser. In most cases a WYSIWYG editor is provided.
Geeks like us, however, prefer to mess with raw code (HTML?) directly.
Nice and dandy, but then you are stuck with boring black-on-white
listing. Or maybe not…</p>
<p><a href="http://codepress.org">Codepress</a> is an absolutely amazing Javascript
library that provides syntax-highlighting for programming code,
including the ones written on PHP, Javascript, HTML, CSS, Java, Perl and
SQL. It’s very solid and performance is great.</p>
<p>I must confess, back in 2003, I did try to create something similar but
failed miserably. It was either because I did not have enough time or
Javascript was not powerful enough, yet, or I was not that good at it,
depending who use ask. Either way, I am double excited now to see that
somebody else was able to deliver this very useful and much appreciated
tool.</p>
<p>P.S. I am going to look-around if anybody has already integrated it into
Drupal and if not - you bet it is going there ;)</p>
World Bank Google-Mapped
2007-10-30T00:00:00-04:00
http://www.freshblurbs.com/blog/2007/10/30/world-bank-google-mapped.html
<p><a href="http://geo.worldbank.org"><img src="http://www.freshblurbs.com/files/GEO-WORLDBANK.jpg" alt="" /></a>
I have slowed down on blogging lately. It’s not because there is nothing
to write about anymore, but because things have been very busy for the
past couple of months. One of the projects that has kept us entertained
and excited at work went live yesterday.</p>
<p><a href="http://geo.worldbank.org">geo.worldbank.org</a> is a new, free web
product of the World Bank that was masterminded by <a href="http://personomies.com/">Pierre-Guillaume
Wielezynski</a> and created by yours truly using
<a href="http://www.google.com/apis/maps/">Google Maps API</a>. It provides an
intuitive, visual view of development information around the world.</p>
<p>You can safely claim that the majority of the Earth’s population has
heard about the World Bank. Most of them also know that the Bank
finances development efforts all around the world. However, that is by
far not the only thing the World Bank does. Having been at the center of
poverty reduction efforts for decades, the World Bank has accumulated
enormous amounts of development data. The World Bank is as much an
information bank as it is a financial institution. By creating an easy,
visual entry point into its data, the Bank attempts to make the
information more accessible to the public and to further its
transparency efforts.</p>
<p>Being an entry point, the map is much more light-weight than the
underlying data-sets. Different tabs provide snapshot views of country
news, World Bank projects, statistical data for countries, and the links
to drill-down into more comprehensive portals. Where available, the
addresses of the local, brick-and-mortar information centers are given
too. Map is equally geared towards general audience and professional
researchers.</p>
iPhone-Friendly Hosting
2007-10-24T00:00:00-04:00
http://www.freshblurbs.com/blog/2007/10/24/iphone-friendly-hosting.html
<p><img src="http://www.freshblurbs.com/files/iphone-mediatemple.png" alt="" /><a href="http://www.mediatemple.net">Media<strong>Temple</strong></a>
is a remarkable virtual-dedicated and dedicated hosting provider for
numerous reasons. It is well-known for legendary reliability, quality of
service and the level of expertise of the support staff. MediaTemple
solutions like grid-deployed MySQL hosting are at the very frontier of
industry innovation.</p>
<p>Recently, though, MediaTemple pleasantly surprised its clientele
(including yours truly) with an iPhone-friendly control-panel. First in
the industry, as far as we know. This sweet thing is definitely worth
checking out: http://www.mediatemple.net/iphone/</p>
<p>You can bet that when a company is great, it’s great in more than one
way. Our deepest respects go to you, MediaTemple!</p>
Open-Source Or Open-Minded?
2007-10-17T00:00:00-04:00
http://www.freshblurbs.com/blog/2007/10/17/open-source-or-open-minded.html
<p><img src="http://www.freshblurbs.com/files/mechanicalbrain.jpg" alt="" />
<a href="http://en.wikipedia.org/wiki/Open-source">Open-source</a>, as a concept
and a phenomenon, is quite special. What fascinates me in the Free/Open
Source model is how efficiently it <a href="http://www.freshblurbs.com/node/72">addresses several
concerns</a> at the same time: social,
business and technological/innovative. Not to forget that it’s been
proven to actually work.</p>
<p>What is the major driving force behind the Open-Source model? A lot of
people have tried to answer this question, with the different degrees of
success. There probably is not a single correct answer. The Open-Source
idea, like any other philosophical notion, touches aspects of human
interaction, and the answer largely depends on the personal perceptions
of an individual. I have changed my opinion several times, myself,
through the years. Still, I dare give my two cents about the subject.</p>
<p>With the few exceptions, of people like Mother Theresa and Mahatma
Gandhi, human beings are largely ego-driven. Most software projects are
labor-intensive undertakings that require significant number of people
working towards the same goal, in unison.
<img src="http://www.freshblurbs.com/files/pieces.jpg" alt="" /> Unfortunately, egos and
personal agendas get into the way. I am no statistician, but from the
personal, very non-scientific observations, it seems that the majority
of successful open-source projects have one characteristics in common.
In all of these projects, the initial leaders decided to share the
authority and the responsibilities with others, at an early stage. In
less abstract terms - giving up Ego seems to be the Nitro-boost of
software projects. Apparently, it happens more naturally in an open,
global environment of a typical open-source project compared to the
usual cubicle environment of a proprietary project.</p>
<p>In the light of this observation, one may speculate that a more precise
term to describe what we have come to know as Free/Open-Source process
is - Open-Minded Process. At the end of the day, it really is about
being able to rather capture somebody else’s mind than try prove the
superiority of your own brain-power.</p>
City Government Against the Wisdom of Crowds
2007-10-15T00:00:00-04:00
http://www.freshblurbs.com/blog/2007/10/15/city-government-against-wisdom-crowds.html
<p><img src="http://www.freshblurbs.com/files/trail.png" alt="" />In college, our civil
engineering professor opened his first class with an anecdote. According
to the story, a bunch of engineers were planning trail paths at a newly
built campus in city X. There was a large set of lawns on campus.
Instead of building sophisticated simulation models to find optimal
trails, the engineers did not pave trails for the first couple months.
During these months people walked on certain paths on the lawns enough
to cut natural trails through the grass. Eventually, the engineers
simply paved those trails. The story concludes that the paths turned out
to actually be the optimal trails.</p>
<p>In the modern Web 2.0 world we would inevitably call this story a
blazing example of the “wisdom of crowds”. Back then, however, James
Surowiecki had not yet written his famous essay, so the story was told
to us as simply a great example of a common-sense approach.</p>
<p>Fast forward many years. Washington, DC has a park with a round-shaped
lawn across the street from my office. Since my garage is on the other
side, I have to pass it every day. There was a well-defined, natural
trail across the lawn. Two days ago I saw a bunch of uniform,
city-employees hovering over the lawn. My unconcerned thought was that
they were doing some kind of cleaning or maintenance. How wrong was I!
Only when they were done did we, the innocent users of the path, find
out that these clowns were actually removing the path and “healing” the
lawn.</p>
<p>Now, seriously, maybe the idea was a novelty in the 1970s, but who goes
against the wisdom of crowds in the 21st century?</p>
<p>Sigh!</p>
Converting Character Encodings to UTF-8 in PHP
2007-10-04T00:00:00-04:00
http://www.freshblurbs.com/blog/2007/10/04/converting-character-encodings-utf-8-php.html
<p><img src="http://www.freshblurbs.com/files/ascii.png" alt="" />Character encodings are
always “fun” to deal with. The fortunate and naive ones amongst you, who
believe that utf-8 solved all pains in the multilingual encoding arena,
let me tell you: “you are lucky to be in your surreal world”.</p>
<p>I was trying to hook up a PHP application with a web-service wrapped
around a legacy application, today. Unfortunately, that web-service was
only capable of sending me a ISO-8859-15-encoded output. Since the guy
who did the service was in enough pain having had to script it in Lotus
Notes Scripting Language, I did not dare ask to fix the problem. Neither
do I know (or want to know) enough about Lotus Notes to assume that it
was possible, at all.</p>
<p>So I tried fixing the problem on the PHP side. Now, PHP does have a nice
method called <a href="http://us2.php.net/utf8_encode">utf8_encode</a> that
encodes ISO-8859-1 strings into UTF-8. You may say - No brainer? Well,
not quite. My input was ISO-8859-1<strong>5</strong>. The bratty “5” in the end
stands for some extra characters mainly used in French and Finnish, but
popping up in Turkish, in my case.</p>
<p>What finally worked was encoding the tricky characters with
<a href="http://us3.php.net/htmlentities">htmlentities</a> like this:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$htmlized = htmlentities( $rawinput, ENT_NOQUOTES, 'ISO-8859-15');
</code></pre></div></div>
<p>In PHP5, you can actually decode it right away and get a “clean” output
if you do something like:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$rawinput_utf8 = html_entity_decode( $htmlized, ENT_NOQUOTES, 'UTF-8');
</code></pre></div></div>
<p>but it does not work in PHP4, for multibyte encodings (e.g. UTF-8) so -
watch out.</p>
The Best PHP IDE for Windows
2007-09-20T00:00:00-04:00
http://www.freshblurbs.com/blog/2007/09/20/best-php-ide-windows.html
<p><strong>UPDATE [April 14, 2012] :</strong> This blog post is quite old, but it still
gets a decent amount of traffic, so I think it’s important to update the
information, since obviously “the best” IDE 5 years ago is not the same
as now. These days (judging by the same criteria as the ones outlined
further in the blog post) I think the absolute winner on all platforms
is: <a href="http://www.jetbrains.com/phpstorm/">PHPStorm</a>. It’s a commercial
product, but they are really awesome at providing free licenses to
open-source projects (full disclosure: they provided me one for
<a href="http://zaphpa.org">Zaphpa</a>). If you are really against commercial
software then <a href="http://aptana.com/">Aptana Studio</a> (based on Eclipse) is
probably your best bet.</p>
<p><img src="http://www.enginsite.com/image/PHP-Editor-small.gif" alt="" />I am always on
the lookout for good IDEs, including the ones for PHP. There are several
decent ones on the market. From the open-source ones, <a href="http://www.freshblurbs.com/drupal-and-eclipse-pdt">Eclipse with
PDT</a> does a decent
job, for local development, if you do not mind extra weight of a
JDK-based IDE. It has some other issues as well (poor support of
on-the-server development via SFTP and forcing the use of pre-configured
projects are a few), but Eclipse is not what we’d like to discuss in
this post, today.</p>
<p>Today I stumbled upon a new (for me) Windows-based, PHP IDE: <a href="http://www.enginsite.com/php-editor.htm">EngInSite
PHP IDE</a> and I was, quite
frankly, blown away! EngInSite is, quite simply, the best PHP IDE on a
Windows platform. I have been playing around with it for a couple hours
now and I have to yet find a feature I would like that it does not have.
It’s a very rare example of a perfect tool.</p>
<p>Few important features from the long list of this IDE’s capabilities:</p>
<ul>
<li>File Navigator (display of a file’s structure as a tree: functions,
objects, variables)</li>
<li>Wonderfully implemented SFTP Support</li>
<li>Support for projects but no need to create a project. Folder view
supported (useful for remote projects).</li>
<li>SVN support, CVS support, Diff support.</li>
<li>CSS/HTML/etc support.</li>
<li>PHP integration (embedded and/or external) and debugging. Support
for both PHP4 and PHP5 and easy switching.</li>
<li>PHPDoc support</li>
<li>Rich set of debugging features like IP Monitor, HTTP Request modeler
etc.</li>
<li>and many more…</li>
</ul>
<p>Only two complains: I am very sad, personally, that it is not available
for Macs and they really should create a much better website for such a
nice product.</p>
$100 iPhone Credit
2007-09-19T00:00:00-04:00
http://www.freshblurbs.com/blog/2007/09/19/100-iphone-credit.html
<p><img src="http://www.freshblurbs.com/files/iPhoneCredit.png" alt="" /> Since I was one
of the roughly 1 million fanatics, that against all rational arguments,
bought iPhone early, I became eligible for the $100 Apple credit. I got
it back today from <a href="http://www.apple.com">Apple</a> website (look in the
footer). It took me about 40 seconds.</p>
<p>Now the big question is - what to buy with it, since I already own like
half of anything at the Apple store? :)</p>
Barack Obama Really Gets The Social Media
2007-09-12T00:00:00-04:00
http://www.freshblurbs.com/blog/2007/09/12/barack-obama-really-gets-social-media.html
<p><img src="http://www.freshblurbs.com/files/barackobama-linkedin.png" alt="" />… or his
campaign team does. Either way, when I logged into my
<a href="http://www.linkedin.com">Linkedin</a> account yesterday and saw a banner
spotlighting Barack Obama’s participation in one of my interest groups,
I could not help a “wow” reaction.</p>
<p>We <a href="http://www.freshblurbs.com/whos-got-more-myspace-friends-presidential-candidates-2008">have already
blogged</a>
that 2008 Presidential campaign is being run in an unprecedentedly
Web-savvy manner. Pretty much all candidates, in both parties, have a
MySpace page and a bunch of YouTube videos, at the least. This may sound
trivial now, but if you look back 4 years ago - the picture was quite
different, was it not? The candidates have come a long way, but Barack’s
team is taking it a notch further. Whilst most candidates do suffice
with the minimal - MySpace, YouTube, maybe FaceBook, the featured
participation of Obama in a specific interest group on Linkedin is a
great example of entering the conversation on the Web at the right spot.</p>
<p>We have all heard, by now, that Web 2.0 / Social Media is all about
“two-way communication” as opposed to the one-way channels of Web 1.0.
You can, also, say that the Web 2.0 is a global discussion or a
collection of discussions. Everybody is welcome to participate, but for
practical reasons nobody can participate in every possible discussion.
Therefore, targeting the discussions that matter is crucial. This was a
point we raised at the <a href="http://blog.executivebiz.com/web-20-roundtable-recap/">ExecutiveBiz Roundtable
Breakfast</a> last
Friday and most attendants seemed to agree. The staging of involvement,
place and time are important on the New Web.</p>
<p>A lot of organizations make a mistake of staging the “Web 2.0-ish”
discussion on their own turf and then naively expecting good
participation from the audience they want to reach or spending vast
amounts of money to attract that audience. But that audience is already
somewhere else! Why not go there and jump into an existing discussion?
It seems like Obama’s campaign is not making this mistake and there are
all indications that they are the most successful campaign on the Web.
That said, just being a social media guru can not get you an office in
the White House, so we have to see how this one goes, but as far as
being web-savvy goes, Obama’s team gets an A+ from us.</p>
<p>Good job.</p>
iTunes Ringtones Are Live
2007-09-11T00:00:00-04:00
http://www.freshblurbs.com/blog/2007/09/11/itunes-ringtones-are-live.html
<p>If you followed Steve Jobs’ <a href="http://www.apple.com/quicktime/qtv/keynote/">latest
keynote</a> (the one where he
dropped iPhone price by $200 and pissed lots of folks off), you may
remember that he announced iTunes Store would have ringtones, soon. Not
only it would just have ringtones that users would be able to
edit/create them themselves.</p>
<p>Well, looks like it is here:</p>
<p><img src="http://www.freshblurbs.com/files/itunes-ringtones.png" alt="" /></p>
Get Real Online
2007-08-22T00:00:00-04:00
http://www.freshblurbs.com/blog/2007/08/22/get-real-online.html
<p>The subject of real.com is a broad one. You can talk about it for hours,
touching the matters of outdated technology and lousy business model or
falsely admiring their desperate attempts of come-back, but then - is it
worth it? I find it much more amusing to bust their balls for petty
archaic spellings, like this one:</p>
<p><img src="http://www.freshblurbs.com/files/getrealonline.jpg" alt="" /></p>
<p>“On-line” for God’s sake? Real, how 90s, of you :)</p>
<p> </p>
<p> </p>
<p> </p>
<p> </p>
<p> </p>
<p> </p>
US News Expands The Ranking Service
2007-08-14T00:00:00-04:00
http://www.freshblurbs.com/blog/2007/08/14/us-news-expands-ranking-service.html
<p><img src="http://www.freshblurbs.com/files/usnewsrankings.png" alt="" />Anybody who has
ever applied to a US university has at least heard the name of <a href="http://www.usnews.com/">the US
News & World Report</a>. Their website of <a href="http://www.usnews.com/sections/education/index.html">the US
educational institutions’
rankings</a> is the
most comprehensive and authoritative one. To give you a flavor, the US
News ranking for business schools is equally, or maybe even more
recognized than the one from the Financial Times.</p>
<p>It was a pleasant news to find-out that the authoritative publication
has expanded its ranking outreach into other areas as well. The recently
launched US News Rankings and Reviews website
[<a href="http://www.rankingsandreviews.com">rankingsandreviews.com</a>] is in
public beta, right now, featuring only car reviews. One can assume,
however, that this is just a first step and we should expect more from
the reliable source.</p>
<p>Stay tuned.</p>
Where Linus Gets It Wrong
2007-08-12T00:00:00-04:00
http://www.freshblurbs.com/blog/2007/08/12/where-linus-gets-it-wrong.html
<p><img src="http://www.freshblurbs.com/files/linux.png" alt="" /><a href="http://en.wikipedia.org/wiki/Linus_Torvalds">Linus
Torvalds</a>, <a href="http://en.wikipedia.org/wiki/Richard_stallman">Richard
Stallman</a> and <a href="http://en.wikipedia.org/wiki/Eric_Raymond">Eric
Raymond</a> are truly the
founding fathers and patriarchs of the <a href="http://en.wikipedia.org/wiki/Free_software">Free/Open
Source</a> movement. The fruits
of this movement are well-known even for the non-geek audience. They
include the Linux operating system, Firefox browser, OpenOffice suite,
MySQL database, plus a plethora of PHP-based content-management systems
like <a href="http://wordpress.org">WordPress</a> and <a href="http://drupal.org">Drupal</a>
which are the driving engines behind the <em>blogosphere</em>… and the list
goes on and on.</p>
<p>Despite the fact that the three patriarchs often disagree with each
other, their authority is overwhelming enough that when any of them
states an opinion, it would be unimaginable for mere mortals like us to
disagree with or, God forbid, criticize their ideas. Nevertheless, the
“free” in “free software” stands for “liberty”, the word that precisely
characterizes the Free Software community, a community where any opinion
has the right for existance and search for ultimate truth is the path of
continued “disrespect” towards authoritative opinions. Besides, we the
bloggers are well-known for our arrogance so, the heck with it! We are
going to disagree with Linus Torvalds in this posting.</p>
<p>Linux.com published a feature story: <a href="http://www.linux.com/feature/118380">Linus explains why open source
works</a> in its August 10, 2007
issue. In this article, Linus is quoted as drawing strong parallels
between the open-source software and scientific query. He tries to
explain how the scientific model of ascertaining the truthfulness of a
hypothesis through peer-review is similar to the community-driven
development process of free/open source software. This, he concludes,
makes open-source software development model like a scientific research.</p>
<p>False! Sweet but wrong, Linus.</p>
<p>Let’s get rid of the romantic view of science and look at hard facts.
How does the scientific model really work? It works in one of two ways:
the research is either conducted in corporate labs under an absolute
secrecy, or funded by universities. The former case is similar to
proprietary software development, with zero outside review, so we
disregard it. The research conducted in universities and other research
institutions is often peer-reviewed, published, collaborated on and
widely discussed, but does it resemble the open-source development
model? How many collaborators can a single scientific research project
have? Maybe four or five labs around the world. How many contributors
does a successful open-source project have? Hundreds</p>
<p>As Linus himself admits - <em>Diversity</em> is integral to the open-source
model, but that’s not quite true for a scientific query! In conducting
scientific research, approving nods from a couple of authoritative peers
is considered more than sufficient. Rarely do a sufficient number of
“random” scientists <strong>contribute</strong> to research in an effort to achieve
any level of meaningful diversity. This is the polar opposite approach
to that of the open-source model.</p>
<p>Linus concludes by stating that it’s all about advancing knowledge and
that knowing more is what mankind really wants. Well, I hate to break it
to you, Linus, but there are plenty of people that just want more money
and are not too bothered about their ignorance. :) Sad or not, we have
to accept the fact that money makes the world go around. If we want
something to work, we need to figure out a way in which higher
aspirations make business sense. The Open Source community has spent
years trying to prove that open-source is a viable business model. Let’s
not ruin that with some naively romantic, but highly visible remarks,
shall we?</p>
GMail Storage Quota
2007-08-07T00:00:00-04:00
http://www.freshblurbs.com/blog/2007/08/07/gmail-storage-quota.html
<p>When Google first launched <a href="http://www.gmail.com">GMail</a>, it
fundamentally changed the free, web-based email service arena. The “big”
players back then, Yahoo! Mail and Microsoft’s Hotmail were only
allowing up to 5MB of storage, forcing users to spend more time on
cleaning up their inboxes than actually using the e-mail service. Then
there came Google with unimaginable mailbox sizes of 1GB for free and
aggressively PRed mantra of “<em>so you’ll never need to delete another
message.</em>”.</p>
<p>That was all nice and dandy, but apparently did not quite live up to the
promise, since I just got this message today:</p>
<p><img src="http://www.freshblurbs.com/files/gmailquota.png" alt="" /></p>
<p>Bummer.</p>
<p>I was part of the early cohort of GMail users that got the service
through private invitations, so I have been using it for about three
years, now. That, granted, is quite a number of emails. However, I do
not use my <a href="http://richard.jones.name/google-hacks/gmail-filesystem/gmail-filesystem.html">GMail as a hard
disk</a>
or anything of the kind. I simply follow the mantra of GMail, by almost
never bothering to delete any of my e-mails (except spam or things that
get in my way). And in return I get this ungrateful message saying that
I exceeded blah blah?</p>
<p>Grrrr… Google, shame on you! :)</p>
iPhone Update 1.0.1
2007-08-01T00:00:00-04:00
http://www.freshblurbs.com/blog/2007/08/01/iphone-update-1-0-1.html
<p>The much awaited first software update of iPhone is out!</p>
<p><img src="http://www.freshblurbs.com/files/iPhone-update.png" alt="" /></p>
<p>One of many novel things about iPhone, setting it aside from the
<em>CellPhones 1.0</em>, is that it is supposed to be frequently and
significantly improved through a series of software updates. This first
update is not <em>that</em> exciting - just a collection of bug-fixes, but
marks a point in the history. I installed the update - the phone still
works, so - good news :)</p>
<p>I wonder if the update will shut down some of the breaches the community
was able to make into the closed world of iPhone.</p>
3G Mobility with ATT
2007-07-27T00:00:00-04:00
http://www.freshblurbs.com/blog/2007/07/27/3g-mobility-att.html
<p><img src="http://www.freshblurbs.com/files/aircard_875u.png" alt="" /> Now that I am an
AT&T subscriber for my cellphone service (thanks, iPhone!), I decided to
try some of the other goodies that AT&T has to offer, as well. I am part
of the large [<del>anti</del>]social class of people who get physically
uncomfortable if they can not access Internet for an extended period of
time (and, yes, half an hour can be an extended period of time).
Considering this personal deficiency, the first natural choice was to
try the <a href="http://en.wikipedia.org/wiki/3G">3G</a> mobile internet
connectivity.</p>
<p>Unfortunately, iPhone does not support
<a href="http://en.wikipedia.org/wiki/3G">3G</a>. It only supports an older and
slower <a href="http://en.wikipedia.org/wiki/EDGE">EDGE</a> technology.
Furthermore, I can not use even EDGE from my laptop since iPhone does
not support Bluetooth modem protocol and can not be used as a modem from
a laptop. I was very upset with this shortcoming, when I first got
iPhone. Considering that I use a Mac and iPhone is an Apple product as
well, I was convinced that they would have the integration squared. I
still think the only reason they don’t is because AT&T has a separate
service for that. You bet AT&T was not too excited by the possibility of
iPhone cannibalizing that line of business for them.</p>
<p>Long story short, I went to a local AT&T store and signed-up for a
separate data plan for laptops. They gave me a <a href="http://www.sierrawireless.com/product/ac875U.aspx">Sierra AirCard
875U</a> USB modem. With
an existing voice plan, I got it for just $150 after $100
mail-in-rebate and my monthly fees for 3G came to $60, which I believe
is at $20 discount. All-in-all it was not a bad deal. I used to pay a
comparable $40/month for a HotSpot access with T-mobile before. That,
however works only at Starbucks and select other shops, whereas my 3G
access works almost anywhere in urban areas and coverage will grow
rapidly.</p>
<p>The great thing about the specific new model of the USB modem (875U) is
that it supports Macintosh, as well. The CD it comes with only has
Windows drivers, but you can download the Mac installation DMG from the
<a href="http://www.sierrawireless.com/resources/software/8x0/Mac/Watcher2.0.6.dmg">SierraWireless.com</a>.
It installs an application called SierraWatcher that allows you to
connect to available 3G networks in the area. It is pre-configured for
AT&T but supports an impressive list of providers world-wide.</p>
<p>I have been using the modem and the service for a while now. The
connectivity has been a little erratic. Download speed per se is quite
stable at around 1MBit/sec, which is not bad at all, but I’ve had
problems with ping time. The first time I hooked the modem up, it chose
a profile called AT&T Auto. Ping time with that profile was at 800ms,
which is horrible. Then I switched to another available profile called
just AT&T and got ping times of 300-400, still not too good.</p>
<p><strong>HINT ALERT:</strong> Finally, I enabled <a href="http://www.macosxhints.com/article.php?story=20050420025219402">Local Caching DNS
Server</a>
(i.e. BIND) on Mac and told SierraWatcher to use it. In named.conf I
used the famous, speedy 4.2.2.2 and 4.2.2.1 DNS servers as my
forwarders. In addition, I added “listen-on { 127.0.0.1; };” in the
options section of the named.conf for extra security. After this last
trick, I was able to get 150-200ms ping time to Google servers (as
opposed to typical 50ms on a wired broadband), which is not great but
pretty good for a mobile Internet.</p>
<p>I still have couple weeks left on my 30-day trial so I will see how it
goes. At this point I am more inclined to keep the service, the feeling
of freedom and flexibility is just amazing and supersedes the downside
in the quality of service.</p>
Kijiji Fun
2007-07-26T00:00:00-04:00
http://www.freshblurbs.com/blog/2007/07/26/kijiji-fun.html
<p><a href="http://www.kijiji.com">Kijiji US</a> is eBay’s attempt to bury
<a href="http://www.craigslist.org/">Craigslist</a>. It has been buzzed about for a
while now, but I received an e-mail announcement, from eBay, only this
morning. I guess, it is official starting today.</p>
<p>Kijiji is wrong on many levels, as in - it should have never existed in
the first place wrong. An industry leader with wallet as fat as eBay’s
simply <em>has</em> to absorb iconic successes like Craigslist that rub
shoulders against its primary business. Instead, eBay purchased minority
share (25%) of Craigslist, in 2004 and a year later launched Kijiji
overseas. Now it is bringing Kijiji to the US market, to directly
compete with the company that it owns a large part of.</p>
<p>I have no idea what kind of world does the sequence of eBay’s moves
makes sense in, but who am I to judge? No doubt, eBay’s executives are
plotting something that our simple minds can not reach. After all, that
is why they are eBay executives and us - just a bunch of lousy bloggers
with too much time on our hands, right?</p>
<p>With a modest attitude like that, I give up analyzing the business
strategy behind Kijiji and its future prospects. Instead, let me offer
you a screenshot snippet that I found quite amusing:</p>
<p><img src="http://www.freshblurbs.com/files/kijiji-dc.png" alt="" /></p>
<p>Now, District of Columbia has indeed been “blessed” to have a special
status, taxation without representation and alternatives for spelling,
but I swear I have never seen it spelled as “D. Columbia”. eBay did
really go down the innovative path on this one.</p>
<p>Laughing out loud.</p>
Fine-Grained Input Filtering in Drupal
2007-07-09T00:00:00-04:00
http://www.freshblurbs.com/blog/2007/07/09/fine-grained-input-filtering-drupal.html
<p><img src="http://www.freshblurbs.com/files/drupal.png" alt="" /><a href="http://www.drupal.org">Drupal</a>
is the best<em>social web community management</em> software in existence,
period. I dare make a blunt statement like this, because I have
seen/worked with many “CMS” (oh, how much I hate this bloated
abbreviation) systems, including couple I architected and lead the
implementation of and I insist - as imperfect as Drupal may be, it is
the best. Now that we have this basic fact squared, let me introduce a
<a href="http://drupal.org/project/filterbynodetype">new, wonderful Drupal
module</a> to you and explain
what exact need it meets.</p>
<p>One of the most useful features of Drupal is undoubtedly a feature
called <a href="http://www.lullabot.com/articles/drupal_input_formats_and_filters">Input
Filters</a>.
Input Filters allow us to do all kinds of fancy transformations of the
input text. For instance, input filter is your savor, your bread and
butter if you need BBCode or Wiki markup support. You can combine input
filters, apply them in a specific order, set a default filter - all of
it from a web interface. Sounds cool? That’s because it is cool, cooler
than your girl-friend.</p>
<p>Unfortunately, there used to be a glaring hole in the paradise - you
could not specify node-type specific settings. Like, you could specify
the default input filter (note: most users will use that and never
switch, simply because they don’t know how), but you could not specify
different ones for different node types.</p>
<p>Why is it a problem? Well, for one, it is a problem when you want to set
up a
<a href="http://drupal.tschannen.net/wiki/set_up_a_wiki_with_drupal_5">Wiki</a> and
blogging together in Drupal. Drupal comes with blogging support and you
can <a href="http://drupal.tschannen.net/wiki/set_up_a_wiki_with_drupal_5">install
Wiki</a>,
but… Your bloggers want the Full-HTML filter to use
<a href="http://drupal.org/project/tinymce">TinyMCE</a> WYSIWYG editor on top of,
whereas your wiki users need a MediaWiki or
<a href="http://wikicreole.org/wiki/AllMarkup">Creole</a> filter, they neither need
or can use the HTML filter. Both of the user groups want their filter to
be the default one. What to do?</p>
<p>Once you are done crying, swearing and tearing your hair off, you can
check out the recently released <a href="http://drupal.org/project/filterbynodetype">Filter by Node
Type</a> module. That is what I
did and have been blessing <a href="http://drupal.org/user/26398">Larry
Garfield</a> ever since (that is for the past
couple days). This module does not exactly allow you to set different
default input filters (feature suggestion?), but it does allow you to
limit the available filters. What you do next is - you only allow the
Wiki filter for the Wiki node types and guess what - it works!</p>
<p>The power of the combined talent of the Drupal community never stops to
amaze me. Good job, guys!</p>
Do iPhone Simulators Work? No!
2007-07-09T00:00:00-04:00
http://www.freshblurbs.com/blog/2007/07/09/do-iphone-simulators-work-no.html
<p>Several “iPhone simulators” have been published on the Web, lately, that
claim aiding web developers in creating iPhone-compatible web
applications. Beware of them! Aside from a bunch of other issues, they
<strong>do not</strong> display text and graphics the same way (size, proportion,
layout) that iPhone does so you may fall in false confidence and when
people do actually open your page in iPhone it will look freakish -
neither like a normal site, nor iPhone-optimized.</p>
<p>I will list two of the most populart ones, here<br />
freemacware.com/iphone-simulator<br />
testiphone.com</p>
iPhone Works With Third-Party Bluetooth Headsets
2007-07-08T00:00:00-04:00
http://www.freshblurbs.com/blog/2007/07/08/iphone-works-third-party-bluetooth-headsets.html
<p><img src="http://www.freshblurbs.com/files/motorola-h700.png" alt="" /> Good news on the
iPhone’s bluetooth support front: you do <strong>not</strong> have to buy the
$129.00 <a href="http://store.apple.com/1-800-MY-APPLE/WebObjects/AppleStore.woa/wa/RSLID?mco=20F63045&nplm=MA817LL/A">Apple
headset</a>
of questionable wearing comfort. Third-party bluetooth headsets seem to
be supported just as well.</p>
<p>We had no trouble hooking up a much cheaper, yet nicer <a href="http://www.motorola.com/motoinfo/product/details.jsp?globalObjectId=111">Motorola
H700</a>
headset with an iPhone.</p>
<p>Apparently, headset model is one of the few things Apple decided not to
lock its users into. Happy iPhoning!</p>
iPhone Quirks - Continued
2007-07-07T00:00:00-04:00
http://www.freshblurbs.com/blog/2007/07/07/iphone-quirks-continued.html
<p><img src="http://www.freshblurbs.com/files/iphone-word.png" alt="" />There’s been plenty
of whining going on the Net about “iPhone does not do this” and “iPhone
does not do that”, so I am not going to bore you with all the known
shortcomings like: half-ass (even less) bluetooth support, no Flash
support, yadda, yadda, yadda. You’ve heard it, you know it.</p>
<p>However, having been using iPhone, for a while, I found couple of new
suckers, that I have not seen mentioned elsewhere, yet, so I will annoy
you with those.</p>
<p>First of all, aside from all the criticism that very naturally
accompanies something so innovative, I must declare - iPhone is an
amazing phone and you do want to have it. I know it, you know it, your
mom knows it, so - stop pretending. The touch-screen keyboard is
extremely usable, very easy to get used to, AT&T Edge is not too slow
for a mobile network, zoom and pan finger-gestures are sweet and the
screen quality is amazing.</p>
<p>Now, in addition to other goodies, iPhone is capable of displaying MS
Office attachments in Mail. However, and this is when we approach the
subject of my complaint, for some obscure, unfair and completely
unjustified reason you can not view the e-mail attachements in
wide-screen. As you were repeatedly shown, when you turn iPhone 90^o^,
iPod and Safari re-adjust to display content in wide-screen and give you
more horizontal room. Guess what? Does not work for the attachments. No
matter how many times and how I turned the iPhone, the Mail attachment
viewer kept displaying the Word file vertically. Such a small detail,
such a huge disappointment! :(</p>
<p>Oh, and one more thing: in case you missed it, iPhone has no file
browser, repeat - none. You can not download anything from the Web, or
otherwise store and view later. Wow!</p>
Mobile Computing, The iPhone Way
2007-07-04T00:00:00-04:00
http://www.freshblurbs.com/blog/2007/07/04/mobile-computing-iphone-way.html
<p><img src="http://www.freshblurbs.com/files/iPhone.png" alt="" />The confusion is over -
Apple
<a href="http://developer.apple.com/iphone/designingcontent.html">revealed</a> the
secrets of creating slick iPhone applications.</p>
<p>When <a href="http://www.apple.com">Apple</a> announced
<a href="http://www.iPhone.com">iPhone</a> in January, this year, the shocking news
and the source of much speculation became the alleged lack of
third-party application support. An intelligent cellphone without
Java/J2ME was so unusual that for a long while it gave Apple-haters a
thing to wave in front of everybody’s face and left Apple-lovers
confused and curious for what it really meant.</p>
<p>The first clarification came during the Steve Jobs’s WWDC keynote on
June 11th and once again proved how risky it is for mediocre minds to
challenge the design decisions of the Cupertino-based centre of
innovation excellence. The message was quite short and ambiguous, yet
loud and telling: the future of the mobile applications, as Apple saw
it, were Web applications.</p>
<p>In the hindsight it all made sense. When Internet connectivity improved
for desktop and laptop computers, traditional, “desktop” applications
started making a strong leap towards the Web (think Google Docs &
Spreadsheets, Calendar etc.). Likewise, as Internet connectivity is
finally progressing in the mobile arena, as well (think
<a href="http://en.wikipedia.org/wiki/3G">3G</a>) it makes a perfect sense for
mobile applications to also want to break out of their tiny cages.</p>
<p>Whether it made sense or not, the concept was still very unusual and
obscure. How can web applications adapt to the mobile user-interface?
Will Safari-based “web pages” be able to look as slick as the “native”
mobile applications on iPhone? How can they integrate with the Apple
apps?</p>
<p>As big of a master of shock-therapy as Apple is, and you can not help a
feeling that they were perfectly OK with “a little” confusion their
half-statements created, they had to end the intrigue eventually and let
people reap the benefits off of the breakthrough innovation. Which is
exactly what they did.</p>
<p>Apple Developer Connection published an excellent
<a href="http://developer.apple.com/iphone/designingcontent.html">guide</a> for Web
Developers interested in creating well-integrated iPhone applications.
The Guide answers a lot of open questions and is a hard proof that the
path Apple has chosen for third-party applications is the path of the
future. See yourself:\</p>
<p><a href="http://developer.apple.com/iphone/designingcontent.html">[http://developer.apple.com/iphone/designingcontent.html]</a></p>
<p>MacRumors
<a href="http://www.macrumors.com/iphone/2007/07/03/meebo-instant-messaging-support-for-iphone/">reports</a>
that the famous, multi-service, online instant-messaging service
<a href="http://www.meebo.com">Meebo</a> is one of the first, prominent web-based
services to move into the direction of iPhone compatibility. Being able
to use GoogleTalk, AOL, MSN, ICQ and others with comfort on iPhone is a
great news. There’s no doubt that the capabilities of iPhone will
increase rapidly with the help of services like Meebo.</p>
<p>P.S. On a related note,
<a href="http://www.techcrunch.com/2007/07/04/iphone-weekend-one-700000-sold-200million-profit-for-apple/">reportedly</a>
there were over 700,000 iPhones sold over just the first weekend.
Obviously, we are not talking about a niche product that will have no
impact on the general direction of the industry. It is clear that iPhone
penetration will be even more dramatic in Europe with its more advanced
mobile infrastructure.</p>
Men Prefer Men Online?
2007-06-15T00:00:00-04:00
http://www.freshblurbs.com/blog/2007/06/15/men-prefer-men-online.html
<p><img src="http://www.freshblurbs.com/files/sex-sells.png" alt="" /> OK, I am not a
marketing guy. I know how to use <a href="http://en.wikipedia.org/wiki/Porters_five_forces">Porter’s Five
Forces</a> analysis, and
I always happily escape to it when I have no real idea about the subject
matter, but that’s about it. Being so ignorant in marketing, I used to
share the general misconception that pretty, female face can sell
products like a magic - anywhere, everywhere. Well, now I know better.</p>
<p>Our friends at the <a href="http://www.developmentseed.org">Development Seed</a>
published a very interesting <a href="http://www.developmentseed.org/blog/design/statistics/sex_appeal">blog
post</a>
today explaining how sexy, female faces may not be effective for online
marketing. Check it out - very nice reading.</p>
Safari 3 - Not Just on Windows
2007-06-12T00:00:00-04:00
http://www.freshblurbs.com/blog/2007/06/12/safari-3-not-just-windows.html
<p><a href="http://www.freshblurbs.com/files/SafariWebInspector.png"><img src="http://www.freshblurbs.com/files/safariwebinspector-sm.png" alt="" /></a>Steve
Jobs announced the availability of <a href="http://www.apple.com/safari/">Safari 3.0 Public
Beta</a> during yesterday’s WWDC Keynote. For
audience at large the biggest news about the release was that it is now
available on Windows, as well. However, apparently there is a “hidden”
(well, unpublicized) new feature that is just as exciting for Mac geeks
like <em>moi</em> - <a href="http://www.freshblurbs.com/files/SafariWebInspector.png">Web
Inpsector</a>.</p>
<p><strong>Web Inspector</strong> is a context menu-activated DOM analyzer a-la
<a href="https://addons.mozilla.org/en-US/firefox/addon/1843">FireBug</a> for
Firefox. This thing is sweet (!) and will make Safari troubleshooting
much nicer, from now on.</p>
<p>Thanks, Apple! Well done.</p>
Vertical Views of the Web with BuzzMonitor
2007-06-08T00:00:00-04:00
http://www.freshblurbs.com/blog/2007/06/08/vertical-views-web-buzzmonitor.html
<p><img src="http://www.freshblurbs.com/files/buzzbee.png" alt="" />You might have noticed
that I have not been blogging quite so frequently, lately. Part of the
reason has been that we were breaking nights launching BuzzMonitor. I am
happy to report that it is live now at
[<a href="http://buzzm.worldbank.org">buzzm.worldbank.org</a>].</p>
<p>BuzzMonitor is a nifty Web 2.0 tool conceived by <a href="http://personomies.com">Pierre-Guillaume
Wielezynski</a> that allows you to create dynamic,
vertical views of the web.</p>
<p>Let’s say, you need to stay on top of what’s the current buzz about
certain subject(s) on the web. One, simple way to do so is to subscribe
to a bunch of <a href="http://en.wikipedia.org/wiki/RSS">RSS</a> feeds filtered by
the subject-specific keyword(s) in your RSS Reader. The problem with
such approach is not only how to filter duplicate items brought by
different feeds, but more importantly - inability to effectively share
the aggregated information with other people, collaborate with them in
making sense of it and building a community around the vertical views.
BuzzMonitor was built to overcome a challenge like this. In time it
acquired additional <a href="http://buzzm.worldbank.org/features">features</a>
supporting better aggregation and collaboration.</p>
<p>We and some people we showed BuzzMonitor to found it so effective that
we thought it was worth publishing under an <a href="http://www.gnu.org/copyleft/gpl.html">open-source
license</a>. That is what we did. You
can freely <a href="http://buzzm.worldbank.org/download">download</a> and even
tweak or redistribute it for non-commercial use.</p>
<p>Your <a href="http://buzzm.worldbank.org/contact">feedback</a> is most welcome.</p>
You Tube, I Tune - Now We Rock Together.
2007-06-02T00:00:00-04:00
http://www.freshblurbs.com/blog/2007/06/02/you-tube-i-tune-now-we-rock-together.html
<p><img src="http://www.freshblurbs.com/files/youtubeitunes.png" alt="" /> Apple is
undoubtedly a leading innovator in the industry (if you wonder which one
– both), and so is Google; so expectations from the
<a href="http://www.apple.com/appletv/tour.html?section=youtube">announced</a>
integration of AppleTV and YouTube are very high. Whatever may your (or
my) feelings be about YouTube, it is certainly a defining phenomena in
Web 2.0, and bringing YouTube to the living rooms of the millions of
households is no small deal.</p>
<p>On a more obscure front, Apple also announced <a href="http://phobos.apple.com/WebObjects/MZStore.woa/wa/iTunesPlusPage">iTunes
Plus</a></p>
<ul>
<li>new DRM-free, higher quality audio format offered through the iTunes
store. Unfortunately, so far, the selection of music in iTunes Plus is
rather limited. Considering the level of paranoia in the recording
industry, whether iTunes Plus can take off remains an open question.</li>
</ul>
Adobe Photoshop CS3 Performance
2007-05-25T00:00:00-04:00
http://www.freshblurbs.com/blog/2007/05/25/adobe-photoshop-cs3-performance.html
<p><strong>Highly Efficient Rosetta or Darn Slow Photoshop?</strong></p>
<p><img src="http://www.freshblurbs.com/files/adobe-creative.png" alt="" />When Apple
introduced Intel-based Macs, a year ago, it provided comprehensive
migration support, as well. Free compiler (program “translating”
human-readable source code of programs into “machine code”) shipping
with OS X is able to produce so-called Universal Binary - code that both
old and new processors can understand. So, for many software vendors
migration was just a matter of recompiling their source code.
Unfortunately, it was more complicated and time-consuming for vendors of
large systems where recompilation is not as trivial. Several large
software vendors were not able to have their code recompiled and
debugged, yet.</p>
<p>To support those more inert, Apple developed technology called
<a href="http://www.apple.com/rosetta/">Rosetta</a>. Rosetta is a virtualization
engine that allows programs, written for old, G# processors to run on
Intel-based Macs without changing single line of code. Microsoft Office
for Mac, still runs on top of Rosetta, with no plans to recompile it
into Universal Binary. Adobe, also, did not have universal binary
version of its graphical applications, until recently. In Adobe’s case
they were very eager to complete the migration, though, as
virtualization is a performance hit and performance is important for a
graphical information processing software like that from Adobe.</p>
<p>The highlight of and the biggest advancement in the recently released
Adobe Creative Suite 3 is the fact that it is compiled in universal
binary - with full support of Intel processors and avoiding Rosetta.
Adobe is very excited about it and has been honking all over the press
how much better/faster the new version is.</p>
<p>Is it really?</p>
<p>A friend of mine got CS3 and we did a quick-n-dirty test on it. CS3 does
start-up pretty quickly compared to the under-Rosetta CS2 , but that’s
about it. We had both versions apply a 100%, best-quality radial spin
blur to a hi-rez (3004x3760, 1.1MB) photo on a Macbook Core Duo with
1.5GB RAM. Results are as follows:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>CS2 (w/ Rosetta): 2.04 sec
CS3: 1.33 sec
</code></pre></div></div>
<p>That, my friends is just 53% increase in speed and, honestly, would
hardly impress anybody, even in a quick-and-dirty test. Either Rosetta
is incredibly efficient (kudos to Apple) or Adobe did not do too good of
a job, or both.</p>
<p>Concluding analysis, we need to mention another metrics, as well, to be
fair. The memory footprint of CS3 was significantly lower - 80MB vs
255MB consumed by CS2. Not bad.</p>
Why Google Should Buy Adobe
2007-05-24T00:00:00-04:00
http://www.freshblurbs.com/blog/2007/05/24/why-google-should-buy-adobe.html
<p><img src="http://www.freshblurbs.com/files/ms_silverlight.png" alt="" /><a href="http://en.wikipedia.org/wiki/Microsoft_Silverlight">Microsoft
Silverlight</a>,
pet-named “Flash killer” by the Web <del>2.0</del> community, replicates many
of the features of Macromedia Flash technology. Silverlight was first
unveiled at the NAB Show, in early 2006, but it is only recently that it
has gotten increasing spotlight from the industry. Somewhat intriguing,
yet quite telling was that Microsoft featured Silverlight at the
recently held Java One 2007, a major, traditionally M$-unfriendly
annual conference of Java developers and vendors. Less surprisingly, it
was the center point of the Microsoft’s own Mix 2007, annual conference
of web developers. Even though Silverlight is still left behind by Paris
Hilton, it surely bypassed Britney in making headlines, at least - in
the geek world. Judging by the enormous marketing blast, it is obvious
that when it comes to Silverlight, Microsoft makes no jokes.</p>
<p><strong>Why is Silverlight so important?</strong></p>
<p>The new web, the so-called Web 2.0, is a two-headed phenomena. On one
side it is a culture, a web-philosophy with the notions of the power of
social unity, global outreach, two-way communication and extreme
personalization at its foundation. On another side, it is a breakthrough
in user-experience technology -
<a href="http://en.wikipedia.org/wiki/Ajax_%28programming%29">Ajax</a> being the
most famous example. Ajax is great for responsive, ergonomic interfaces,
the kinds you find in Gmail, Google Maps, Flickr, Meebo and every other
Web 2.0 site, but it is not the only important technology driving the
web revolution. New web is heavy on rich media and until recently Flash
was the dominant technology for multimedia delivery on the web. YouTube
would not exist without the Flash Streaming technology and Flash Video
format. Many audio podcast websites have flash audio players. Fancy
image galleries are driven by Flash technology enabling greater
interactivity. And the list goes on…</p>
<p>Unsurprisingly Microsoft, in response, did what it knows the best -
“photocopied” all of Flash’s features and launched a heavy marketing
campaign to shove the next [Microsoft] “breakthrough” down the throats
of its army of customers. And those our Redmond buddies have plenty, of
course. For the sake of greater market penetration, they decided to
support even Safari - the standard browser on Apple OS X operating
system, archrival platform of MS Windows.</p>
<p>The direct exposure through the existing client base, huge financial
strength and the top-notch marketing department give Microsoft
significant advantage to successfully compete with Adobe, the owner
company of the Flash technology with almost ten times less financial
resources and hundred times less market influence.</p>
<p><strong>Google, help!</strong></p>
<p>Call me paranoid, if you will, but I simply can’t help the analogy with
Microsoft-Netscape situation at the dawn of Web <del>1.0</del>. Netscape had
this cool thing called Javascript. There came Microsoft, “stole”
Javascript, made its own thing out of it, completely incompatible with
the Netscape original and put the whole Web into many years of
stagnation through the <a href="http://en.wikipedia.org/wiki/Browser_wars">Browser
Wars</a>. As soon as the
industry managed to heal itself through the Web 2.0, Microsoft is trying
to do the whole thing all over again. The scary thing is - if it has to
face just Adobe, Microsoft <strong>can</strong> do it again.</p>
<p>Fortunately, there are other strong players in the market, this time
around, who don’t usually lie under Microsoft’s pressure. Google, of
course, is the most resourceful and innovative of the crowd. And Google
we look-up to, for help.</p>
<p>With the risk of pissing off O’Reilly Media, who claim they coined the
name, yet never did much about it since, I would say Google is the
father of Web 2.0. Google made Web 2.0 possible by, at times, starting
prominent 2.0 services (Google Maps, Gmail) and, at other times,
financing (MySpace through the advertising deal) or purchasing (YouTube)
them – therefore validating the sustainability, reality of the notion
for the rest of the industry.</p>
<p>Flash, as the backbone technology for the rich-media Web 2.0 is too
important. Microsoft can not be allowed to burry it, or create another
incompatibility war, and it’s not Adobe who can put up the fight. Adobe
is too small, it does not understand Flash too well (got it through the
acquisition of Macromedia) and treats Flash in a way that is way too
proprietary and closed. Adobe made Flash-based Rich Internet Application
(RIA) framework Flex a commercial product, seriously constraining its
spread and growth. Google, on the other hand is big enough to take
better care of Flash, has much more experience in opening-up
technologies and can afford to do so, financially. Google does not need
to make money off of Flex sales. Saving the multi-billion investment in
Flash-driven YouTube is more important.</p>
<p>To close the argument, it’s useful to remember that Adobe owns another
very important, proprietary format - Portable Document Format (PDF). PDF
is a universal format for storing electronic documents, dominant on all
platforms most importantly – mobile devices like PDAs and smartphones.
It sure would not hurt Google to get PDF as a “by-product” of “saving”
Flash. Pitch in there the ultimate creativity suite of Photoshop,
Indesign and Illustrator combination, for a complete office experience
and acquiring Adobe sure does not sound like a bad idea.</p>
<p>Of course, Adobe will not be cheap to buy. According to
<a href="http://www.valueline.com">Valueline</a>, market cap. of Adobe is at
$25.4B. That is one expensive acquisition for Google, with market cap.
of $147B. Difficult – not impossible. Google can definitely afford it,
but Eric, Larry and Sergei will have to spend some time with the Google
board, explaining just how strategically important the move is.</p>
Linus Torvalds Presents: Git - Truly Distributed SCM
2007-05-18T00:00:00-04:00
http://www.freshblurbs.com/blog/2007/05/18/linus-torvalds-presents-git-truly-distributed-scm.html
<p>Linus Torvalds recently gave a
<a href="http://www.youtube.com/watch?v=4XpnKHJAok8">presentation</a> at Google
about a new source-control management (SCM) system he has authored and
that is being actively maintained by an open-source community -
<a href="http://git.or.cz/">Git</a>.</p>
<p>If you are a happy user of Subversion, you should take a break right now
and watch the <a href="http://www.youtube.com/watch?v=4XpnKHJAok8">video</a> (if
you are a “happy” user of CVS, you are hopeless), because it will change
and broaden your thinking. Git is not just another version control, it
is fundamentally different the way it works.</p>
<p>And it is better! But, how? Ask yourself some questions about your
current SCM:</p>
<p><img src="http://www.freshblurbs.com/files/linus-git.png" alt="" /></p>
<ul>
<li>Do you commit every day? Should you?</li>
<li>Can you commit if you are offline?</li>
<li>Do you use branches?</li>
<li>Do you look forward to merging branches?</li>
<li>Do you need to have guidelines about naming branches/tags?</li>
<li>What if your SCM server’s disk died?</li>
</ul>
<p> </p>
<p>Now imagine that you have a system where none of these questions give
you a shiver. That would be Git.</p>
<p>Linus, once again - you rock!</p>
Joost Disk Space Hunger
2007-05-15T00:00:00-04:00
http://www.freshblurbs.com/blog/2007/05/15/joost-disk-space-hunger.html
<p><img src="http://www.freshblurbs.com/files/joost.png" alt="" />
<a href="http://www.freshblurbs.com/free-joost-invitations">Joost</a>, the
revolutionary online TV service, is the new craze on the Web. However,
if you have been using it extensively, you may have noticed that you are
running out of disk space. Ouch!</p>
<p>Not sure how it behaves on Windows, but on OS X, Joost demonstrated an
early bug - it “eats” disk space through thoughtless caching. Hopefully,
Joost guys will fix the problem, in time, but for now, unless you have
unlimited disk space, make sure that you periodically delete:</p>
<p><strong>~/Library/”Application Support”/Joost/anthill/anthill_cache</strong> under
your home folder.</p>
<p>Have fun</p>
Line Delimiters in Eclipse
2007-05-13T00:00:00-04:00
http://www.freshblurbs.com/blog/2007/05/13/line-delimiters-eclipse.html
<p><img src="http://www.eclipse.org/eclipse.org-common/themes/Phoenix/images/header_logo.gif" alt="" /><a href="http://www.eclipse.org">Eclipse</a>
is an IDE of choice for many. It’s been very popular among Java
developers for a long time, but lately it is getting some traction in
the PHP world, as well. A big contributor has been the absolutely
fabulous <a href="http://www.eclipse.org/pdt/">Eclipse PDT</a> project that makes
Eclipse PHP-intelligent.</p>
<p>Whether you are developing in Java, PHP or any other language Eclipse
supports, you most probably have to deal with cross-platform issues. One
of the most trivial, yet annoying is the matter of line-delimiters. For
whatever historical reasons Windows, Unix/Linux and Macintosh use
different delimiters. It almost makes you wonder if the creators of the
three major operating systems were sadistic enough to intentionally
employ all three possible variations to make our lives more difficult.</p>
<p>To avoid ugly problems, it is essential to make sure all developers on a
project have the same settings for line-delimiters. Usually, teams use
Unix version for two major reasons. First, both Windows and Macintosh
understand it and mostly treat well. The second reason is related to
version control. Most popular version control systems - CVS and
Subversion are usually installed on Unix/Linux. In such case using Unix
line delimiting makes sense.</p>
<p>How can we set up Eclipse to use Unix file delimiter even on OS-X or
Windows?</p>
<p>To set up default ending for new files created, across the entire
workspace:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Window -> Preferences -> General -> Workspace -> New text file line delimiter.
</code></pre></div></div>
<p>To convert existing files, open file for editing and for the currently
edited file, go to the menu:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>File -> Convert Line Delimiters To
</code></pre></div></div>
<p>and select Unix.</p>
Scalable User Interface
2007-05-09T00:00:00-04:00
http://www.freshblurbs.com/blog/2007/05/09/scalable-user-interface.html
<p><img src="http://www.freshblurbs.com/files/web20.png" alt="" />The dominant question
popping up in a pragmatist’s mind, observing the Web <del>2.0</del>, is: how
come people get so much free time in an increasingly hyper world? With
the
<a href="http://www.blogherald.com/2005/04/14/number-of-blogs-now-exceeds-50-million-worldwide/">amount</a>
of blogging going on, either half of the literate population is
procrastinating or the sales of Red Bull has to be booming.</p>
<p>Either way, even a child knows, these days, that it’s all about content.
If you got content - you got audience, with which comes influence,
network effects, possibly money and vast amounts of bloated ego.</p>
<p>The thing about content is - presentation is every bit as important as
the substance. Therefore, it is no surprise that the boom of Web 2.0 was
inevitably followed by the
<a href="http://mittermayr.wordpress.com/2006/02/03/20-culture/">revolution</a> in
the user-interface aesthetics.</p>
<p>The rarely addressed, yet important feature of the user-interface design
is - <strong>scalability</strong>. If scalability for a software system means its
ability to take <del>brutally</del> high user traffic without major changes to
the source code, scalability for a user-interface means the ability to
display vast amounts of content with the same crispiness which it
handles just a handful of entries with.</p>
<p>You may think it is no big deal, but if even a mogul of the ergonomic
design like Apple gets it wrong, occasionally, - it must be challenging
enough to be worth a blog post.</p>
<p>When Apple added movies to iTunes, it was a long-expected move. Apple
made video iPods available in a timely manner to make the user
experience complete. Yet, Apple customers had to hold their breath -
there was painfully limited amount of movies to choose from.
<img src="http://www.freshblurbs.com/files/itunesmovie.png" alt="" />For whatever
reason, Apple was not able to secure enough movie content to make the
experience truly complete.</p>
<p>Having such limited amount of content, Apple designed the user interface
accordingly. Browsing in iTunes Movies is as simplistic as it gets -
plain listing with some “paging” and filtering by a handful of
categories. Granted, what else do you need for slightly more than
hundred movies?</p>
<p>The problem - scalability. A year later Apple was finally able to cut
deals with more movie studios and bump up the number of available movies
by an order of magnitude. Unfortunately, the user interface design
stayed the same and in the new reality - unusually useless for something
Apple.</p>
<p>Another interesting case-study is the recently introduced -
<a href="http://www.freshblurbs.com/free-joost-invitations">Joost</a>. The
user-interface is slick and sexy - well in-line with all the latest
trends. Yet, Joost, being beta and all, has limited content right now.
If it is to grow and live up to its promise - the amount of content will
soon go through the roof. Will the user-interface scale?</p>
<p>The way Joost interface is currently designed, it does not look
particularly scalable. Hopefully, this is one of the main aspects Joost
team plans to address before the official launch.</p>
Free Joost Invitations
2007-05-03T00:00:00-04:00
http://www.freshblurbs.com/blog/2007/05/03/free-joost-invitations.html
<p><img src="http://www.freshblurbs.com/files/joost.png" alt="" />If you are a Web 2.0
enthusiast you, probably, have already heard of
<a href="http://www.joost.com/">Joost</a> - the Web 2.0 version of the future of
the television.</p>
<p>Joost is in its beta phase. It is free but invitation-only. To use the
service, somebody has to invite you.</p>
<p>I have some invitations available and you can get them by simply asking.
Leave a comment to this message, if you want me to invite you.</p>
<p>Please, do not forget to provide your valid e-mail address in the
comment form. You can enter it in the contact information section, not
necessarily in the comment body - this way I will still be able to see
it and your privacy will be protected.</p>
<p>Please, note: some people have reported problems receiving Joost
invitations on Hotmail and Yahoo accounts. If you don’t get an
invitation, get a free <a href="http://www.gmail.com">GMail</a> account and try
again.</p>
Managing Your Personomy In the World Without Privacy Boundaries
2007-05-02T00:00:00-04:00
http://www.freshblurbs.com/blog/2007/05/02/managing-your-personomy-world-without-privacy-boundaries.html
<p><img src="http://www.freshblurbs.com/files/gonewild.jpg" alt="" /> Unless you’ve lived
in a cave in a desert, for the past three years or so, you must have
noticed the social revolution that took over the Internet. Some call it
“blogging craze”, yet others prefer to more fashionably number-version
the Web into “2.0”. Either way, the reality is that mass-services like
MySpace and YouTube stormed into our lives and changed them forever,
both online and offline. To further complicate the matters, Google made
it possible for your boss to find the little MySpace profile you meant
only for your boyfriend’s amusement.</p>
<blockquote>
<p><strong>Personomies</strong> are digital manifestations of an individual. They
combine identity (who you are), activity (what you do) and “sociality”
(who you know) - <strong><a href="http://www.personomies.com">Pierre-Guillaume
Wielezynski</a></strong>.</p>
</blockquote>
<p>Any reasonably web-literate hiring manager will Google your name before
making the final decision. What does she find in the first three pages
of the search results can determine your career. Have you “googled”
yourself? Do you know what your personomy on Google looks like?</p>
<p>The wrong perception many people share is thinking that Web only “knows”
what they’ve “told” it. Getting
<a href="http://en.wikipedia.org/wiki/Dooced#.22Dooced.22">“dooced”</a> -
publishing something your employer (current or future) may not like used
to be the most common way of getting in trouble. Not anymore, at least -
not the only way, by far.</p>
<p>Significant part of your personomy is “sociality” - who you know and who
talks about you online. If you are in your teens or twenties, most of
your friends probably blog in one way or another, or at least have
Myspace, Friendster etc. profile. Even if you don’t have one, they may
publish something and it will effect you nevertheless. Do you think your
boss cares whether the a-la “gone-wild” photo with you in it that he
found online was on your blog or your best girl-friend’s? Imagine that
you are applying for a deputy-sheriff position or for a very uptight law
firm and a photo like that pops up?</p>
<p>Most web pages stay online for a long period of time. It is not unusual
photos and texts from years before to surface. The careless decisions
you may have made when you were younger can haunt you years after.
Unfortunately, younger generation does not yet understand how important
digital identity - personomy has become. And it will only increase in
importance, as more and more people will start checking the personomy of
people they consider for hire or for going in business with.</p>
<p>You have to take care of your personomy.</p>
<p>First - know the current state of your personomy - monitor it. Second -
try to improve it. If the first search hit is some stupid blog post your
careless friend wrote about you, counter it - go to the professional
forums, bulletin boards and blogs and get into conversations there.
Popular blogs and forums are indexed often by Google and have high rank.
Most probably your posts on these websites will take lead over the
things you do not want to pop up and will squeeze the unwanted content
to deeper pages in the search results. Any content that shows up on 5th
or latter page in the search results is not anything to worry much
about.</p>
<p>If you don’t like your personomy, you can improve it, but it takes time
so - start now.</p>
Who's Got More MySpace Friends? Presidential Candidates 2008.
2007-04-30T00:00:00-04:00
http://www.freshblurbs.com/blog/2007/04/30/whos-got-more-myspace-friends-presidential-candidates-2008.html
<p><img src="http://images.cafepress.com/product/71578223v4_150x150_Front.JPG" alt="" />As
employees all over the country keep <a href="http://www.google.com/search?hl=en&safe=off&client=safari&rls=en&q=%22fired+over+myspace+profile%22&btnG=Search">getting
fired</a>
over their MySpace profiles, <a href="http://profile.myspace.com/index.cfm?fuseaction=user.viewprofile&friendid=156831770&MyToken=f3e2eeda-2cf4-4d16-ae51-b598fa7ffe99">one
man</a>
is trying to get “hired” as nothing less than the President of the
United States of America. That’s right, <a href="http://profile.myspace.com/index.cfm?fuseaction=user.viewprofile&friendid=156831770&MyToken=f3e2eeda-2cf4-4d16-ae51-b598fa7ffe99">Dennis
Kucinich</a>,
has a professionally designed MySpace profile with all the bells and
whistles that, typically, only <a href="http://myspace.com/u2">music bands</a> or
TV shows get.</p>
<p>Mr. Kucinich currently has 10,280 friends, which falls short of <a href="http://www.myspace.com/johnmccain">John
McCain</a>’s 20,173. With all fairness,
these numbers are very impressive for a 60 and 70 years old men on
MySpace. Yet, both of them get beaten hands down by Hillary Clinton’s
two MySpace profiles
<a href="http://profile.myspace.com/index.cfm?fuseaction=user.viewprofile&friendID=163712750">one</a>
with 35,370 friends and
<a href="http://profile.myspace.com/index.cfm?fuseaction=user.viewprofile&friendID=64552165">another</a>
with 41,873. If you ever doubted Hillary’s charms, now you know!</p>
<p>Profiles of Kucinich and McCain seem to be part of their official
campaigns, but senator Clinton’s profiles are clearly just fan pages.</p>
<p>Last but not least, a shocking result from <a href="http://www.myspace.com/barackobama">Barack
Obama</a> - with 161,728 “friends” he
beats even <a href="http://myspace.com/u2">U2</a> at 136,270.</p>
Install PECL Memcache with XAMPP and PHP4
2007-04-23T00:00:00-04:00
http://www.freshblurbs.com/blog/2007/04/23/install-pecl-memcache-xampp-and-php4.html
<p><a href="http://www.apachefriends.org/en/xampp-linux.html">XAMPP</a> is an
absolutely wonderful, packaged, self-contained distribution of apache,
mysql, php and tons of hard-to-install php extensions. Not only does it
make sysadmin’s life easier, by solving 99.9% of LAMP problems
out-of-the-box, but it also allows PHP-vendors to create packaged
distributions of complex systems.</p>
<p>However, even with a long list of packaged extensions, obviously there
may be a need to install an additional one. <a href="http://pecl.php.net/package/memcache">PECL
Memcache</a> client of
<a href="http://www.danga.com/memcached/">memcached</a> distributed cache server,
is a very probable candidate for high-load systems.</p>
<p>Unfortunately, PECL is broken in a vanilla XAMPP installation with php4.
Typically you won’t be able to use “pecl” directly and when you try to
install manually with phpize you will get an error like:<br />
“ PHP Warning: Unknown(): Unable to load dynamic library
‘/opt/lampp/lib/php/extensions/no-debug-non-zts-20020429/memcache.so’ -
/opt/lampp/lib/php/extensions/no-debug-non-zts-20020429/memcache.so:
undefined symbol: OnUpdateLong in Unknown on line 0”</p>
<p>Below is step-by-step guide of how to install a PECL extension (Memcache
in this case) in the latest XAMPP:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>make sure you uninstall all and any PHP installations you may have had before along with PECL and PEAR
Download and install XAMPP 1.6.1
Add /opt/lampp/bin to your PATH
Download and install XAMPP Development Package
caution: it will overwrite any configuration changes you may have made previously
backup /opt/lampp/include directory to /opt/lampp/include-bak. This directory
is part of XAMPP-DEV but seems to be broken vis-a-vis PECL
Download source distribution of the PHP corresponding to your XAMPP installation
(for 1.6.1 it is PHP 4.6.4) and put it under "include" older so that the root of the
php source distribution is /opt/lampp/include/php (rename the php-4.6.4 directory
to php after unpacking).
Run "./configure" and "make" on that php source.
Caution: Do NOT run "make install"!!!
Download memcache-2.1.2 anywhere
# cd memcache-2.1.2
# phpize
# ./configure
# make
# make install
Edit /opt/lampp/etc/php.ini and add a line:
extension="memcache.so"
Enjoy
</code></pre></div></div>
<p>memcache is just a client-side of the whole cache thing. You need to
install server, as well, to do anything useful. The server (called
memcached, as in memcache-daemon) requires <a href="libevent">libevent</a> dynamic
library. There is a small pitfall in instaling libevent. The
installation itself is a straightforward “configure, make, make install”
but once you install libevent and memcached, you may not be able to run
memcached and get the following error, instead:</p>
<p>“memcached: error while loading shared libraries:
libevent-1.1.so.1:cannot open shared object file: No such file or
directory”</p>
<p>This is because memcached was not able to find the library location. Run
memcached with:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ LD_DEBUG=libs memcached -v
</code></pre></div></div>
<p>to see where is it looking for the libraries and install libevent there.</p>
<p>I had to run libevent configure as:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>./configure --prefix=/usr
</code></pre></div></div>
<p>to fix this problem. You will need to uninstall/recompile/reinstall
memcached if you reinstall libevent.</p>
<p>cheers</p>
Advanced Apache Security
2007-04-23T00:00:00-04:00
http://www.freshblurbs.com/blog/2007/04/23/advanced-apache-security.html
<p><strong>Task</strong>: allow unrestricted access to a virtual host from a range of
IPs, require MySQL-based authentication from any other IP.</p>
<p><strong>Solution</strong>:</p>
<p>Database Table:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>use auth;
CREATE TABLE `user` (
`id` int(10) unsigned NOT NULL auto_increment,
`fullname` varchar(127) NOT NULL default '',
`email` varchar(127) NOT NULL default '',
`country` varchar(64) NOT NULL default '',
`userid` varchar(32) NOT NULL default '',
`passwd` varchar(32) NOT NULL default '',
`groupid` varchar(32) NOT NULL default 'user',
`modified` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `email_2` (`email`),
UNIQUE KEY `userid_2` (`userid`),
KEY `groupid` (`groupid`),
KEY `country` (`country`),
KEY `groupid_2` (`groupid`(8),`userid`),
KEY `userid` (`userid`,`groupid`(4))
);
</code></pre></div></div>
<p>.htaccess or httpd.conf snippet:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>AuthMySQLUser www
AuthMySQLDB auth
AuthMySQLUserTable user
AuthMySQLNameField userid
AuthMySQLPasswordField passwd
AuthMySQLGroupField groupid
AuthMySQLCryptedPasswords On
AuthMySQLScrambledPasswords Off
AuthMySQLMD5Passwords On
AuthMySQLKeepAlive Off
AuthMySQLAuthoritative On
AuthMySQLNoPasswd Off
AuthName "Corporate Authentication"
AuthType basic
require group user
Satisfy any
order deny,allow
deny from all
allow from127.0.0.1 192.168.0.1 192.168.0.7 freshblurbs.com 4.4.4.2 example.com
ErrorDocument 401 /error.htm
</code></pre></div></div>
SOA In Buzz-Word Laden Prose
2007-04-09T00:00:00-04:00
http://www.freshblurbs.com/blog/2007/04/09/soa-buzz-word-laden-prose.html
<p>SOA is probably the most overused/abused buzzword. I would say even more
so than AJAX - which is scary, really. It’s also funny how “SOA experts”
can make the subject even blurrier.</p>
<p>That was the subject of the conversation between
<a href="http://wemmick.blogspot.com/">Doug</a> and I, recently that I am quoting
below. We were discussing <a href="http://www.theserverside.com/tt/articles/article.tss?l=ChurchandState">a recent SOA
article</a>.
Nothing too serious, just fun.</p>
<blockquote>
<p><strong>irakli:</strong> Got a minute?<br />
<strong>dharris:</strong> sure<br />
<strong>irakli:</strong> Trying to catch a blasphemy in this:
http://www.theserverside.com/tt/articles/article.tss?l=ChurchandState</p>
<p>Quote #1:\</p>
<blockquote>
<p>But what if I am building a new application that has little to do
with integration? Say I’m building a Business Intelligence (BI) tool
for analyzing and reporting on data from a data warehouse and have
no requirement to integrate any legacy systems, expose any Web
Services, or provide any BPEL processes. Is SOA relevant in the
design of such a system? Would I apply any SOA principles in
architecting this application? Would it make sense to say that my
new system’s architecture is SOA-based? The answer to all of these
questions is “Yes”.</p>
</blockquote>
<p><em>Interpretation:</em> SOA should be used in any application, at least at
the module level</p>
<p>Quote #2:\</p>
<blockquote>
<p>The above brings out one of the key principles of SOA-based design
that is often not well articulated or recognized - separation of
state and behavior. Just as many countries hold dear the principle
of separation of church and state, the separation of state and
behavior is important to SOA-based design.</p>
</blockquote>
<p><em>Intepretation:</em> State and behaviour should be separated in SOA</p>
<p><strong>dharris:</strong> There are too many buzzwords/buzz-acronyms in Quote #1</p>
<p><strong>irakli:</strong> End result of Quote1 + Quote2 =<br />
In any application, state and behaviour should be separated</p>
<p>So, what exactly happened to Encapsulation - the core principle of OO,
again?</p>
<p><strong>dharris:</strong> heh</p>
<p><strong>irakli:</strong> He got me lost there. Does it make sense to you, maybe?</p>
<p><strong>dharris:</strong> that’s what can happen with buzz-word laden prose</p>
<p><strong>irakli:</strong> God bless you. So it’s not just me?</p>
<p><strong>dharris:</strong> SOA seems to me to be a redefinition of some core OO
principles… clear interface to encapsulated objects.</p>
<p><strong>irakli:</strong> Well, in my humble understanding, SOA is higher in the
architecture stack, much higher than OO</p>
<p><strong>dharris:</strong> It’s just that in a modern SOA application, the “objects”
are often separate applications running on separate hardware.<br />
<strong>dharris:</strong> exactly<br />
<strong>dharris:</strong> The scary thing….</p>
<p><strong>irakli:</strong> … is when people start using it on lower levels<br />
:)</p>
</blockquote>
Developer's List of Firefox Extensions
2007-04-05T00:00:00-04:00
http://www.freshblurbs.com/blog/2007/04/05/developers-list-firefox-extensions.html
<p>There are tons of wonderful Firefox add-ons. In fact, that is what makes
this browser stand out among other browsers. However, be cautious to
install every other extension you think may be cool. Firefox performance
can significantly degrade when you install many/random extensions.</p>
<p>Anyway, for what it’s worth, following is the list of Firefox extensions
that I can not live without (alphabetically):</p>
<ul>
<li>Aardvark</li>
<li>Add N Edit Cookies</li>
<li>CookieSwap</li>
<li>del.icio.us</li>
<li>Extended Statusbar</li>
<li>Fire Encrypter</li>
<li>Fire Bug ( I bless the day Joe Hewitt started programming!)</li>
<li>MeasureIt</li>
<li>Server Spy</li>
<li>Talkback (well, i can live without it but keep it installed as
courtesy to Firefox)</li>
<li>User Agent Switcher</li>
</ul>
<p>P.S. I am not trying to be lazy or annoying when not linking these
plugins. First, such links may soon get invalidated because URLs change
all the time, second - if you google “firefox plugin <addon name>” you
will find any of them, easily - promise!</p>
April DC Drupal Meetup is Today!
2007-04-04T00:00:00-04:00
http://www.freshblurbs.com/blog/2007/04/04/april-dc-drupal-meetup-today.html
<p>Unforgivable: I’ve been so busy lately that almost forgot to post -
April DC Drupal meetup is Today!</p>
<p><img src="http://farm1.static.flickr.com/227/444066422_1c06c176fb_o.png" alt="" /></p>
<p>Please, note that the meetup place has changed and read more details
about it on <a href="http://www.developmentseed.org/blog/march2007_dc_drupal_meetup">Eric’s
Blog</a></p>
<p>See you there!</p>
Five Nines Availability - Kaizen of Performance and Scalability
2007-04-02T00:00:00-04:00
http://www.freshblurbs.com/blog/2007/04/02/five-nines-availability-kaizen-performance-and-scalability.html
<p><img src="http://www.freshblurbs.com/files/Toyota_Assembly_Line.jpg" alt="" /> As far as
<a href="http://en.wikipedia.org/wiki/Enterprise_architect">Enterprise
Architects</a> are
concerned, there is no other, single characteristic of a software system
more important than the performance and scalability. Or, at least -
there should not be. Sadly, in reality, performance is often an
afterthought. Inexperienced development teams look at it in disdain and
refuse to “waste” time on performance tuning. They amuse themselves with
“feature enhancements” and only remember performance when things start
to fall apart. That moment in time is usually before the champagne
glasses, in celebration of the “successful” launch, get a chance to dry.</p>
<p>When the panic day hits, things don’t get any better. Developers,
typically, jump “fixing” code, based on a bunch of wrongful perceptions
they have acquired on some
<a href="http://www.theserverside.com">i-am-smarter-than-you-if-i-talk-more</a>
forums or go begging management for “better hardware”. Benchmarking,
profiling and systematic analysis are ignored because nobody has much
experience with any of those. Eventually management gets frustrated,
hires a highway-robber a.k.a consultant and either gets things
temporarily fixed, or in the worst-case scenario - gets a huge,
meaningless report of “what’s wrong”.</p>
<p>On the other side of the spectrum are the overly concerned,
control-freak architects that design and redesign architecture for
months, in anticipation of the performance problems. The typical
end-result of such effort is a stack of UML diagrams and little to none
production code.</p>
<p><img src="http://www.freshblurbs.com/files/speed.png" alt="" />So, what is the solution
for achieving <a href="http://en.wikipedia.org/wiki/Myth_of_the_nines">Five
Nines</a>? Well, actually -
the same as in any other industry striving for exceptional quality. How
does Car Manufacturing sound?</p>
<p><a href="http://en.wikipedia.org/wiki/Kaizen">Kaizen</a>, or the Process of
Continuous Improvement was developed at Toyota and is largely
responsible for the legendary reliability, durability and efficiency of
the Japanese cars.</p>
<p>“Kaizen is a daily activity whose purpose goes beyond improvement. It is
also a process that, when done correctly, humanizes the workplace,
eliminates hard work (both mental and physical), and teaches people how
to do perform experiments using the scientific method and how to learn
to spot and eliminate waste in business processes.”
(<a href="http://en.wikipedia.org/wiki/Kaizen">Wikipedia</a>)</p>
<p>Along those lines, the 5 “commandments” of performance and high
availability are:<br />
**<br />
**</p>
<p>Performance benchmarking and tuning is an ongoing activity.</p>
<p>It should be a well-defined process.</p>
<p>Bottlenecks should be identified in a “scientific” way - through
measurements, not - presumptions.</p>
<p>When done properly, it humanizes the workplace and eliminates crisis
situations.</p>
<p>It is learned and perfected only through doing.</p>
In Search Of Open-Source Designers.
2007-04-01T00:00:00-04:00
http://www.freshblurbs.com/blog/2007/04/01/search-open-source-designers.html
<p><img src="http://www.freshblurbs.com/files/redhat.png" alt="" />I am a huge fan of
<a href="http://en.wikipedia.org/wiki/Linux">Linux</a>. On most counts: code
quality, cultural/social, stability, performance and security, I think
it is superb. There is no other operating system that I would like to
see on my servers. However, there is a huge issue with Linux as a
desktop operating system. And it has little to do with programmers, to
be honest and fair.</p>
<p>The issue is the
<a href="http://en.wikipedia.org/wiki/Look_and_feel">look-and-feel</a> of Linux and
other <a href="http://en.wikipedia.org/wiki/Free_software">free software</a> that
come with it. The dreadful graphics a-la Windows 3.0 from two decades
ago is not just a minor nuisance but effectively daunts and depresses to
the extent of making user less productive. Especially when you have the
polished perfection of OS-X interface to compare with. Even Mac’s
inferior copycat - Windows looks much better than most of the Linux
software. If they can’t create, in Redmond, at least they try to copy.</p>
<p>Why are things so bad? It’s hard to buy the argument that
Free/Open-Source Software is created by geeks with degenerated sense of
aesthetics. A lot of free software is backed by big companies like IBM,
Suse, RedHat, HP, Oracle and others, or resourceful organizations like
Apache Foundation. So, what’s the deal? For instance, why does
<a href="http://en.wikipedia.org/wiki/GIMP">GIMP</a>, a major graphics suite on
Linux, look like an early experiment in GUI design from ’80s, when
calendar shows 2007? Why is even Ubuntu, a wonderful Linux distribution
striving to make Linux as user-friendly as possible, still so far behind
OS X and Windows, even if far ahead other Linux distributions vis-Ã -vis
user-interface?</p>
<p>Linux and Free/Open-Source Software have always been about community
much more than anything else. Main driving force is social and it seems
the social component is missing in the graphical design part. Does
anybody know of any sizable open-source designer community? If not - why
does not one exist? It’s not like graphical design is more creative than
programming and therefore designers are not inclined to share. They are.
<a href="http://www.csszengarden.com/">CSS Zen Garden</a> is one of the prominent
proofs. However, there is an apparent disconnect between open-source
programmer and designer community, with very little invested in the
latter.</p>
<p>I hope somebody finds an innovative business model to fix the issue.
Obviously, I am not talking about employing some hot-shot designer and
creating a decent KDE or Gnome skin, for the first time. The issue seems
to be much deeper, and the solution must be more fundamental.</p>
The Truth About ISO 9000
2007-03-30T00:00:00-04:00
http://www.freshblurbs.com/blog/2007/03/30/truth-about-iso-9000.html
<p>Quite probably, you have seen more than a few companies bragging about
being ISO 9000 certified. In the marketing materials it is usually
presented as a doubtless proof of higher quality. However, what they
don’t necessarily want you to know, is that the perception has little to
do with the reality.</p>
<p>ISO 9000 is a family of standards that specify requirements for a
quality management system. The combination of “standard” and the
presence of “quality” in the name is what creates the confusion. This
standard is <strong>for</strong> quality management systems, not - certifying quality
of systems. See the difference?</p>
<p>In reality certification to ISO 9000 says nothing about the compliance
or quality of end products and services. It just certifies that
consistent business processes are being applied.</p>
<p>If a company is ISO 9000 certified and their process is bad, it will be
consistently bad. Pretty neat, huh?</p>
HOWTO: Enable PEAR on OS-X XAMPP
2007-03-30T00:00:00-04:00
http://www.freshblurbs.com/blog/2007/03/30/howto-enable-pear-os-x-xampp.html
<p>The current, OS-X version of XAMPP comes with PEAR but it’s not
installed/configured.</p>
<p>Here is what you need to do:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo su - [and type admin password]
/Applications/xampp/xamppfiles/lib/php/pear install PEAR
/Applications/xampp/xamppfiles/lib/php/pear install Log
/Applications/xampp/xamppfiles/lib/php/pear list
</code></pre></div></div>
<p>The last command outputs the list of installed pear modules. Log should
be one of them.</p>
<p>Once you configure pear and install Log plugin, you need to add PEAR to
include_path in XAMPP’s php.ini.</p>
<p>Edit /Applications/xampp/etc/php.ini and at the very end of the file
note the lines:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>1133 ;***** Added by go-pear
1134 include_path=".:/Applications/xampp/xamppfiles/lib/php"
1135 ;*****
</code></pre></div></div>
<p>change the configuration to read:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>include_path = ".:/Applications/xampp/xamppfiles/lib/php
:/Applications/xampp/xamppfiles/lib/php/pear"
</code></pre></div></div>
<p>(comment: of course, the entire include_path must be on the same line,
we had to break it at semicolon to avoid the long line destroying the
page layout).</p>
Drupal: Debugging with PEAR Logging
2007-03-22T00:00:00-04:00
http://www.freshblurbs.com/blog/2007/03/22/drupal-debugging-pear-logging.html
<p>Let’s admit, any PHP developer, at some point has “debugged” a PHP
application by inserting several “echo” statements here and there. It’s
easy and quick but it’s by far not the best way. For one, you can not
and should not do anything like that on a production server. The last
thing users need to see is debug messages from a desperate developer.
Besides, in the ever-increasing Ajaxization of web-applications the
“echo approach” simply does not work, anymore. Ajaxized server-side code
is executed without having any direct, “echo-compliant” output in the
response HTML stream. It’s time to get used to logging to a file on the
server.</p>
<p>Unfortunately, at the time of this writing, Drupal does not have
built-in support for file logging. Could be because somebody thought the
cumbersome database-logging was more than enough, could be because <a href="http://pear.php.net/package/Log">PEAR
Log</a> already provides the
functionality. Either way, let’s see how we can Integrate PEAR Log in
our Drupal development.</p>
<p>First, we need to initialize the logger, by putting the following code
in index.php, preferrably after the boostrap and before the call to
menu_execute_active_handler().</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>require_once 'Log.php';
$logconf = array('mode' => 0775, 'timeFormat' => '%X %x');
$logger = &Log::singleton('file', '/tmp/drupear.log', 'ident', $logconf);
</code></pre></div></div>
<p>We just told logger to log to /tmp/drupear.log file with permission mask
775.</p>
<p>Then, anywhere in the code, where we need output to log</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>global $logger; //once per scope e.g. once per function body.
$logger->log ( "LOREM IPSUM TESTS. DO NOT TOUCH");
</code></pre></div></div>
<p>P.S. PHP’s <a href="http://us2.php.net/error_log">error_log</a> function is
another way to log to a file. It is somewhat less flexible compared to
PEAR Log, however, so we recommend using the latter, when possible.</p>
Drupal: Display Block Only For a Specific Node Type
2007-03-20T00:00:00-04:00
http://www.freshblurbs.com/blog/2007/03/20/drupal-display-block-only-specific-node-type.html
<p>On the block configuration page, in the “page-specific visibility
settings”, enable option three: “Show if the following PHP code returns
TRUE (PHP-mode, experts only).” and enter the following code:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><?php
$bresval = false;
if (arg(0) == 'node' && ctype_digit(arg(1))) {
$node = node_load(arg(1));
if ($node->type == 'event') {
$bresval = true;
}
}
return $bresval;
?>
</code></pre></div></div>
<p>In this particular case, we will only display the block if node type is
“event”.</p>
Drupal: Monthly Tagging Statistics
2007-03-19T00:00:00-04:00
http://www.freshblurbs.com/blog/2007/03/19/drupal-monthly-tagging-statistics.html
<p>Ever wondered about the frequency of a particular tag or tags over time?
The SQL query below can quickly mine that information from a Drupal
database:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>select count(*), mons
from (
select n.nid,n.changed, t.tid,
DATE_FORMAT( FROM_UNIXTIME(n.changed), '%Y%m') mons
from node n
inner join term_node as t on t.nid=n.nid
where t.tid=14769
group by n.nid) as trm_x_node
group by mons order by mons asc
</code></pre></div></div>
$1500 Keyboard - Anybody?
2007-03-18T00:00:00-04:00
http://www.freshblurbs.com/blog/2007/03/18/1500-keyboard-anybody.html
<p>You probably know that <a href="http://www.cebit.de/exhibitorsproducts">CeBIT</a>
is going full force, right now. As you would expect from a leading IT
and telecom trade fair, loads of new interesting solutions were
presented. However, one stands out, right away. Not so much with its
features but rather by price - $1,500 for a keyboard? And it’s not even
platinum-plated or carrying proud tag of some insanely famous designer.</p>
<p><img src="http://www.freshblurbs.com/files/optmax3.jpg" alt="" /><a href="http://blog.wired.com/photos/uncategorized/2007/03/15/optmax4.jpg">Optimus
Maximus</a>
is a creation of Russian web/industrial design company <a href="http://en.wikipedia.org/wiki/Lebedev_studio">Art. Lebedev
Studio</a>. Each key on this
keyboard is an OLED screen that can be programmed to display any
character. So, effectively, the keyboard is fully customizable. Cool,
but… it ends up costing more than any keyboard you have ever seen.
According to some reports, it also “features” a constant high-pitch
noise from all the OLED goodness, but we have not tried it so - maybe
not.</p>
<p>In any case, even with the supposedly breakthrough approach to designing
keyboards, the first reaction when you look at the price tag is
inevitably in line with one of the comments to the <a href="http://blog.wired.com/gadgets/2007/03/cebit_2007_more.html#more">wired.com blog
post</a>:
“These Commie douches must be out of their arrogant minds. $1500 for a
keyboard? Yeah, right, how about - GET REAL?”. However, if you give it a
second thought you may appreciate the marketing genius behind the price.
Seriously, if not the scandalous price tag, what else would make this
gadget appear on the front-page of the wired.com coverage of CeBIT and
be a highlight of the show?</p>
<p>Well, maybe the “commie douches” are not so stupid, after all and
they’ve learned a thing or two about <a href="http://en.wikipedia.org/wiki/Shock_advertising">Shock
Advertising</a> from their
Western brothers? Maybe… We’ll see how this one goes and if the
keyboard will capture any real market. In my humble opinion, unless they
significantly drop the price very soon, they will prove right the
wired.com commenter.</p>
Hire: Prudent Specialist or Absent-Minded Genius?
2007-03-15T00:00:00-04:00
http://www.freshblurbs.com/blog/2007/03/15/hire-prudent-specialist-or-absent-minded-genius.html
<p><a href="http://dictionary.reference.com/browse/prudent">pru·dent</a> [prood-nt] -
<em>careful in providing for the future;</em></p>
<p>Mike Cannon-Brookes of <a href="http://www.atlassian.com">Atlassian</a> recently
wrote a wonderful <a href="http://blogs.atlassian.com/rebelutionary/archives/2007/03/life_is_a_hire_way_5_tips_for_startup_hi.html">blog
post</a>
about successful hiring practices.</p>
<p>A related, interesting subject is the matter of discipline, often
emphasized by HR professionals. Apparently, well-organized individuals
are better workers, or so they tell us. Well, we know it is not
necessarily true for creative work. But is it true for service industry?</p>
<p>I don’t know, but here is what Operations Management theory tells us.
Apparently, according to the <a href="http://www.google.com/search?client=safari&rls=en&q=waiting+line+models&ie=UTF-8&oe=UTF-8">Waiting Lines
Models</a>,
for constant arrival rate, flow time increases exponentially with mean
processing time, but it increases quadratically with the standard
deviation of processing time.</p>
<p>If you remember little off of your calculus class, in human language it
means: being able to, on average, complete jobs quickly is more
important than the variation in job completion times.</p>
<p>I will leave the pleasure of making conclusions to you :)</p>
Breakthrough: Java Implementation of PHP5
2007-03-14T00:00:00-04:00
http://www.freshblurbs.com/blog/2007/03/14/breakthrough-java-implementation-php5.html
<p>According to Caucho, you can run Drupal in Java now.</p>
<p>Following is the excerpt from Quercus website:</p>
<p>“<a href="http://quercus.caucho.com/">Quercus</a> is Caucho Technology’s 100% Java
implementation of PHP 5 released under the Open Source GPL license.
Quercus comes with many PHP modules and extensions like PDF, PDO, MySQL,
and JSON. Quercus allows for tight integration of Java services with PHP
scripts, so using PHP with JMS or Grails is a quick and painless
endeavor.</p>
<p>With Quercus, PHP applications automatically take advantage of Java
application server features just as connection pooling and clustered
sessions.</p>
<p>Quercus implements PHP 5 and a growing list of PHP extensions including
APC, iconv, GD, gettext, JSON, MySQL, Oracle, PDF, and Postgres. Many
popular PHP application will run as well as, if not better, than the
standard PHP interpreter straight out of the box. The growing list of
PHP software certified running on Quercus includes DokuWiki, <strong>Drupal</strong>,
Gallery2, Joomla, Mambo, Mantis, MediaWiki, Phorum, phpBB, phpMyAdmin,
PHP-Nuke, Wordpress and XOOPS.”</p>
<p>This is very impressive. I am going to try installing Drupal over
Quercus soon and share the experience.</p>
March DC Drupal Meetup
2007-03-12T00:00:00-04:00
http://www.freshblurbs.com/blog/2007/03/12/march-dc-drupal-meetup.html
<p>The next Washington, DC, Drupal Meet-up will be on Wednesday, March
14th, at the Science Club (1136 19th Street, NW) at 7pm.</p>
<p>You can find more information in <a href="http://groups.drupal.org/node/3087">Eric’s
announcement</a>.</p>
Corporate Communications Gone Dorky
2007-03-11T00:00:00-05:00
http://www.freshblurbs.com/blog/2007/03/11/corporate-communications-gone-dorky.html
<p>We have all heard about the relaxed corporate atmosphere at Google.
Nothing wrong about that. In fact, it’s awesome.</p>
<p>However, aparently somebody at Google’s external communications (or
whatever the department is called there) thought it was a good idea to
share a piece of internal “nerdiness” with the public at large.
Recently, they have published a teaser on the GMail log-in page:</p>
<p><img src="http://www.freshblurbs.com/files/gmailshot.jpg" alt="" /></p>
<p>Clicking on the link, not surprisingly, brings you to a <a href="http://www.youtube.com/watch?v=uBbmiQhuAhU">YouTube
video</a> posted below.
Ugggggggh, no comments :)</p>
To Flash Or Not To Flash
2007-03-10T00:00:00-05:00
http://www.freshblurbs.com/blog/2007/03/10/flash-or-not-flash.html
<p>Adobe (ex-Macromedia) Flash is a core technology of today’s Web.
Unfortunately, it got a wrong start back in the days. Many designers
sold their souls to the unprecedented opportunities offered by graphical
web and forgot that Flash is a complement to HTML, not - a replacement.
This confussion ended us in the initial flood of all-Flash websites - a
complete nightmare, by any reasonable standards.</p>
<p>You might remember that even some big media companies made the mistake.
I will spare their good names, considering that they [relatively]
quickly corrected the mistake, but to make a point - the confusion did
not infect only amateur designers. Unfortunately, the cure was not any
less damaging - many websites and designers refused to use Flash, at
all. It also helped that right at the time, Ajax emerged, giving buzzers
new “hot” thing to buzz about.</p>
<p>It is an interesting story with an interesting ending and I was thinking
for a while, now to blog about it, but I was late - <a href="http://www.alistapart.com/authors/m/danmall">Dan
Mall</a> from A List Apart,
recently published a wonderful post about the whole matter: <a href="http://www.alistapart.com/articles/semanticflash/">Semantic
Flash: Slippery When
Wet</a>. It’s an
excellent reading that I completely agree to. There is not much I could
add to it and I would highly recommend it to anybody interested in the
subject.</p>
<p>The only point I would like to make is one concerning license and vendor
lock-in. Flash is a proprietary technology and it is a problem. Adobe,
having so much experience with PDF, will probably be able to mitigate
this concern. However, it will never be gone. You can see the effects
watching the battle of Ajax and Flex (a rich-client solution spring-off
of Flash). It does not look like Flex will do much harm to Ajax,
partially because it is a proprietary technology.</p>
Web 2.0 - Not Just On The Web, Anymore.
2007-03-09T00:00:00-05:00
http://www.freshblurbs.com/blog/2007/03/09/web-2-0-not-just-web-anymore.html
<p>BMW gets it. Watch the phenomenal integration of Google Maps and German
manufacturer’s navigation system.</p>
Incorrect Date Formatting in Sun JDK 1.5 Russian Locale Implementation
2007-03-07T00:00:00-05:00
http://www.freshblurbs.com/blog/2007/03/07/incorrect-date-formatting-sun-jdk-1-5-russian-locale-implementation.html
<p>Even though Russian is one of the few languages i can speak and I have
worked on both the internationalization of Web applications, as well as
Java quite a lot, in the past, particular problem of Russian i18N has
never come to my attention. That is - until now.</p>
<p>Unfortunately, I was unpleasantly surprised as soon as I touched it -
Sun JDK 1.5.x does not format dates correctly with Russian Locale.</p>
<p>The deal with Russian language is that month names have different suffix
when they are presented stand-alone (i.e. in a list or smth) and yet
another one when they are part of a formatted date. So, even though
March is “Март” in Russian, correctly formatted today’s date would
be: “7 Март<strong>а</strong> 2007 г.”</p>
<p>Let’s see how JDK fortmats today’s date: 7 Март 2007 г. Clearly
wrong.</p>
<p>It’s very sad. No matter how you feel about it, Russian is one of the
major languages and Sun could have put enough effort to get it right.</p>
<p>Below is the test JSP code:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><%@page pageEncoding="UTF-8"%>
<%@page contentType="text/html;charset=UTF-8"%>
<%@ page import="java.util.*" %>
<%@ page import="java.text.*" %>
<HTML>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<BODY>
Current date (Russian):
<%
Locale locale = new Locale("ru","RU");
DateFormat full = DateFormat.getDateInstance(DateFormat.LONG, locale);
out.println(full.format(new Date()));
%>
</BODY>
</HTML>
</code></pre></div></div>
Flash Video - Delivered
2007-03-06T00:00:00-05:00
http://www.freshblurbs.com/blog/2007/03/06/flash-video-delivered.html
<h3 id="or-how-can-you-install-ffmpeg-encoder-on-linux">Or: how can you install FFMPEG encoder on Linux?</h3>
<p>How many times have you been annoyed by online videos in different
proprietary streaming encodings? Have you looked at the beauty of
Youtube, Google Video, Revver etc. with owe? Did you envy the way they
accept long list of different encodings, re-encode them into FLV and
display to the users in the most friendly format?</p>
<p>Well, envy no more. Open-source library
<a href="http://ffmpeg.mplayerhq.hu/">FFMPEG</a> is a fantastic video encoder. You
may need some help installing this beast, however. Unfortunately,
friendly installation seems to be very low on their priority list. Even
worse, when you spend hours struggling with the ffmpeg installation, you
will find out that once encoded into FLV sound is lost, videos are
completely mute! Bummer.</p>
<p>That is because FLV audio is mp3 and ffmpeg does not come with mp3
support by default. You will have to download and install <a href="http://lame.sourceforge.net/index.php">Lame mp3
encoder</a> first.</p>
<p>So, this is the bird’s eye-view:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>> sudo su - root
download lame, uncompress and all...
> ./configure --enable-shared --prefix=/usr
> make
> make install
make sure it was successful by issuing on bash: lame
Now, export ffmpeg HEAD from their SVN
(these dudes do not produce source distros).
If it breaks, try some earlier date.
> ./configure --enable-gpl --enable-libmp3lame --enable-shared
> make
> make install
and, then you can feel free to start encoding with a command as simple as:
ffmpeg -i source.mov output.flv
</code></pre></div></div>
Enhanced MySQL Transaction Security
2007-03-05T00:00:00-05:00
http://www.freshblurbs.com/blog/2007/03/05/enhanced-mysql-transaction-security.html
<p>A transaction in the database modifies data. Due to its impotance, any
extra care and security you can apply to a transaction, can pay back big
time in a critical situation. There is one measure which is relatively
easy to implement in MySQL and can save you a lot of headache if
something goes south.</p>
<p>There are transactions in program logic that developer knows should only
ever affect one row. It can be a Delete or Update statement and we can
predict that it never spans across multiple rows. If that is a case, it
is a good practice to add “Limit 1” at the end of the statement. That
way, even if for some reason our delete or update statement’s “where”
clause gets messed up, we will only damage one row at max per
transaction.</p>
<p>Now, let’s assume you are building your “where” clause on-the-fly
(disclaimer: generally, a security risk in itself). Let’s imagine that,
for whatever reasons, under some conditions you end up with a generated
statement like:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>delete from users where user_id is not null
</code></pre></div></div>
<p>now, compare this to</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>delete from users where user_id is not null Limit 1
</code></pre></div></div>
<p>better?</p>
<p>P.S. Bad things happen, ignoring their possibility is just inviting
trouble.</p>
Fix: Garbled TineMCE Windows in Drupal
2007-03-01T00:00:00-05:00
http://www.freshblurbs.com/blog/2007/03/01/fix-garbled-tinemce-windows-drupal.html
<p>A lot of nice <a href="http://www.drupal.org">Drupal</a> themes have HTML <strong>body</strong>
styled with fancy backgrounds. Unfortunately, most of the theme authors
do not test their themes with a popular WYSIWYG editor module
<a href="http://drupal.org/project/tinymce">TinyMCE</a>. If they did, they would
notice how bad the text entry window looks with their themes on:<br />
<img src="http://www.freshblurbs.com/files/tinymcedrupalthemes.png" alt="" /></p>
<p>As you can see, the body background affects TinyMCE text entry window,
as well. This is because that “window” is actually a separate HTMl
document with its own body that also gets affected by the style setting.
Ouch!</p>
<p>The fix is trivially easy, now that we know what’s going on. Edit the
theme’s style-sheet, to add an instruction:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>body.mceContentBody {
background: white;
}
</code></pre></div></div>
<p>The problem should be gone. I wish theme designers payed more attention
to this detail, though. TinyMCE is used all over the place, and as a
matter of fact, I am almost sure all other WYSIWYG editing modules have
similar problems, too, as they need to use sub-document for editing.</p>
How To Create favicon.ico Files on OS X
2007-02-27T00:00:00-05:00
http://www.freshblurbs.com/blog/2007/02/27/how-create-favicon-ico-files-os-x.html
<p>You can do it very easily using
<a href="http://www7a.biglobe.ne.jp/~ogihara/software/OSX/icom-eng.html">IcoMaker</a>.
Just compose the ico as a GIF in any editor of your choice, save it.
Start IcoMaker, go to “New Document”, import your existing image with
File->Include Image, then save.</p>
<p>That’s it.</p>
Correct Way of Adding JavaScript OnLoad Event to Drupal
2007-02-26T00:00:00-05:00
http://www.freshblurbs.com/blog/2007/02/26/correct-way-adding-javascript-onload-event-drupal.html
<p>In Drupal 4.7 and 5.x correct way to add your custom Javascript onload
events is to<br />
a) Make sure there is no onload attribute on HTML body tag.<br />
b) Make sure you are not calling window.onload= directly<br />
c) Insert the following snippet, in the generic section (outside any
methods!) of your module’s javascript file:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>if (isJsEnabled()) {
addLoadEvent(yourCustomJSFunction);
}
</code></pre></div></div>
<p>You can call addLoadEvent method as many times as you wish. It will
stack-up multiple functions and call them in queue.</p>
Boosting Firefox Performance
2007-02-26T00:00:00-05:00
http://www.freshblurbs.com/blog/2007/02/26/boosting-firefox-performance.html
<p>If you noticed that your Firefox installation takes significant time to
connect to websites, there may be an easy solution. It will take you 30
seconds and save you a lot of time/annoyance in the future.</p>
<p>So:</p>
<ul>
<li>Type “about:config” in the address field and have Firefox open it as
if it was an Internet URL. Firefox configuration page will appear.</li>
<li>In the “Filter” text field, type: “dns” to get dns-related
configurations only.</li>
<li>Note the configuration named “network.dns.disableIPv6”. It’s value
should be “true” (IPv6 should be disabled). If not, click on the
value field to make it true.</li>
</ul>
<p>Restart Firefox and enjoy faster connection times.</p>
Scheduling Skype Phone Call - Geek's VoIP
2007-02-25T00:00:00-05:00
http://www.freshblurbs.com/blog/2007/02/25/scheduling-skype-phone-call-geeks-voip.html
<p>On unix-compatible systems, you can schedule
<a href="http://en.wikipedia.org/wiki/Skype">Skype</a> to make phone calls. For
instance, On OS X, you can do it with a simple crontab setup, like:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>55 7 * * * open callto://+13056740165 > /tmp/skype.log
</code></pre></div></div>
<p>which will call certain <a href="http://www.freshblurbs.com/tag/registerfly">unfriendly
company</a>’s customer service
number, every day at 7:55 AM.</p>
Registerfly and Domains Dropping
2007-02-23T00:00:00-05:00
http://www.freshblurbs.com/blog/2007/02/23/registerfly-and-domains-dropping.html
<p>Most of you, probably, already know the whole deal with the <a href="http://slashdot.org/articles/07/02/20/0024233.shtml">Registerfly
crisis</a>, so I won’t
bore you re-telling weeks-old story. I happen to be a misfortunate
customer of theirs, too, however. So, I wanted to share some of my
experiences that may be helpful if you have domains with them.</p>
<p>Firstly, you have to know that you can not transfer domains from
Registerfly. They will not provide AuthCodes. Secondly, for most domains
you will experience problems when you try to renew expiring domains.</p>
<p>Now, good luck getting in touch with ICANN. All they’ve done so far is
published <a href="http://www.icann.org/correspondence/registerfly-notice-of-breach-21feb07.pdf">a
memo</a>
describing in detail the situation. That’s nice but it does not help at
all when you have domains expiring in couple days.</p>
<p>I called ICANN and they provided an e-mail address: authcodes AT_SIGN
registerfly dot com. This is an e-mail address that supposedly
Registerfly gave ICANN to forward customers with problems to.</p>
<p>I have written to this e-mail but I am not hopeful at all because I have
contacted Registerfly customer service several times, over the phone,
during the past week. The response was the same all the time: they are
having technical difficulties, can not access the system and have NO
idea when it will be resolved.</p>
<p>Honestly, the situation is absolutely outrageous and I believe ICANN is
as much at fault as Registerfly. They should have never given
accreditation to such a messed-up company and right now they are doing
next to nothing to help customers.</p>
<p>How about, putting expiry on hold? Or something that would actually
help? Good luck finding anything of that kind.</p>
Steve Jobs on Conspiracy
2007-02-20T00:00:00-05:00
http://www.freshblurbs.com/blog/2007/02/20/steve-jobs-conspiracy.html
<p>It’s an old quote from Steve Jobs (1996, imho) but in the light of
current events, it still seems very relevant:</p>
<blockquote>
<p>“When you’re young, you look at television and think, There’s a
conspiracy. The networks have conspired to dumb us down. But when you
get a little older, you realize that’s not true. The networks are in
business to give people exactly what they want. That’s a far more
depressing thought. Conspiracy is optimistic! You can shoot the
bastards! We can have a revolution! But the networks are really in
business to give people what they want. It’s the truth.”</p>
</blockquote>
<p>:-)</p>
Printer-Friendly Calendar View
2007-02-13T00:00:00-05:00
http://www.freshblurbs.com/blog/2007/02/13/printer-friendly-calendar-view.html
<p><a href="http://drupal.org/project/calendar">Calendar</a> module is one of the most
useful modules in Drupal. It allows to create and view different events
in time. Equally important module is
<a href="http://drupal.org/project/print">Printer-Friendly</a> which allows to have
Print link and formats page in a printer-friendly style.</p>
<p>Unfortunately, Printer-Friendly module only works with node pages and
calendar views are Views module pages so printer-friendly does not work
with them. Following is a quick tutorial (inspired by <a href="http://drupal.org/node/94098">Chill35’s
suggestion</a>) on how to create
printer-friendly pages for Calendar. Actually, the trick can be used for
any views page, with some modifications.</p>
<p>The essence of the trick is that when we need a printer-friendly version
of a page, we add “printit” to the end of the URL and when it is in the
URL modify CSS accordingly to strip-off header/footer/etc. In Calendar
module’s case (which is actually called “events”) you need to edit
event_link() method in event.modules file.</p>
<p>In there, at the section where links are generated ( “elseif
(user_access(‘access content’)) {“ section ) insert the following
snippet:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>-- snippet --
$curLink = $_SERVER["REQUEST_URI"];
// We gotta have full URl to do printer-friendly trick.
// If we do not have one, we gotta construct month view.
if ( !strpos ( $curLink, "all/")) {
$links['Printer-Friendly'] = l(t('Printer-Friendly'), $base .'month/'.
$node->filter.'/printit', array('title' => t('Printer-Friendly')));
}
if ( !strpos ( $curLink, "printme") && !$links['Printer-Friendly']) {
$links['Printer-Friendly'] = l(t('Printer-Friendly'),
$curLink."/printit", array('title' => t('Printer-Friendly')));
}
-- snippet --
</code></pre></div></div>
<p>This will add Printer-Friendly link to the links and only show it when
you are not already in the printer-friendly mode.</p>
<p>Then in page.tpl.php of your Theme, in the head section, insert:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><?php
$curLink = $_SERVER["REQUEST_URI"];
if ( strpos ( $curLink, "printit")) {
print theme('stylesheet_import', base_path() .
path_to_theme() . '/print.css', 'all');
}
?&gt:
</code></pre></div></div>
<p>And the print.css file that you put in themes/ folder may look something
like:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.header, .bar, .right_articles, .left_articles, .footer, .event-filter-control, .feed-icon {
display: none;
}
</code></pre></div></div>
DrupalCon 2007
2007-02-12T00:00:00-05:00
http://www.freshblurbs.com/blog/2007/02/12/drupalcon-2007.html
<p><img src="http://www.freshblurbs.com/files/oscmsSummit.png" alt="" /></p>
<p>Yahoo!’s Open Source CMS Summit will host DrupalCon on March 22 and 23,
2007, at Yahoo! campus in Sunnyvale, CA. Do not miss it!</p>
<p>Register today and learn more about this amazing, open-source CMS system
from the source - people working on Drupal.</p>
Shame On You, Wal-Mart!
2007-02-11T00:00:00-05:00
http://www.freshblurbs.com/blog/2007/02/11/shame-you-wal-mart.html
<p>Irresponsible and short-sighted behaviour like this of Wal-Mart is why
people have to put up with
<a href="http://news.com.com/Next+Explorer+to+fail+Acid+test/2100-1032_3-5813897.html"><strong>evil</strong></a>
<a href="http://files.myopera.com/tarquinwj/albums/45511/IE6.png">garbage</a> like
Internet Explorer:</p>
<p><img src="http://www.freshblurbs.com/files/walmart-ms-pussy.png" alt="" /></p>
<p>P.S. Before you start frowning or chuckling, I encourage you to follow
the links objectively demonstrating an example of why Internet Explorer
is indeed
<a href="http://news.com.com/Next+Explorer+to+fail+Acid+test/2100-1032_3-5813897.html">evil</a>
and equally
<a href="http://files.myopera.com/tarquinwj/albums/45511/IE6.png">garbage</a></p>
Web 2.0 and Cheesy Marketing from Sun Microsystems
2007-02-09T00:00:00-05:00
http://www.freshblurbs.com/blog/2007/02/09/web-2-0-and-cheesy-marketing-sun-microsystems.html
<p><a href="http://en.wikipedia.org/wiki/Sun_microsystems">Sun Microsystems</a> is a
decent company with arguable marketing strategies. A shiny example of
the desperation of their marketing team has recently appeared on the
homepage of Sun’s Java website:</p>
<p><img src="http://www.freshblurbs.com/files/javaweb2.0.jpg" alt="Sun Web 2.0 Java Ad" />
Honestly, I have no idea why is Sun of such low opinion of its target
audience. I would doubt that JEE developer community can not see through
the obvious gibberish of the ad.</p>
<p>Seriously, what does Java EE 5 offer to building Web 2.0 applications?
Does it come with a set of templates that adhere to the <a href="http://mittermayr.wordpress.com/2006/02/03/20-culture/">Web 2.0
Culture</a>? Does
it even come with a user-interface engine or theming engine that does?
(If you comment anything about “JSF”, i will ban your IP from this blog,
I swear) Does it have some groundbreaking AJAX implementation embedded?
Is it Agile to develop in and easy to interface to? Does it even come
with an RSS/Atom and OPML parser/generator? Or does it just come with
bloated implementations of SOAP and handful of other, modified to the
extent of being almost-proprietary, XML-based protocols?</p>
<p>Is that it? OK, but does it make Java EE 5 SOA-ready? Do you mean,
consequently it is - Web 2.0?</p>
<p>You know, I believe that you can not sell gibberish to people who
understand the subject matter batter than you do and that is what this
ad is trying to do, obviously.</p>
<p>The only encouraging thing about the whole story is that I did a quick
search and it seems like Sun is actively hiring marketing people, so we
can hope this misery will end soon :)</p>
Marc Fleury Quits JBoss
2007-02-09T00:00:00-05:00
http://www.freshblurbs.com/blog/2007/02/09/marc-fleury-quits-jboss.html
<p>The biggest news of the day, in the tech industry, is that Marc Fleury
<a href="http://www.localtechwire.com/business/local_tech_wire/news/story/1198568/">has
quit</a>
JBoss/RedHat. Honestly, I do not think there is much to say about this
fact. As soon as RedHat acquired JBoss many of us knew it would happen,
because of how unfitting Fleury’s personality is in a culture like
RedHat.</p>
<p>I will just say that I hope Marc will prove himself for the
entrepreneurial visionary he has been marketing himself as and will
start something new with the money he collected. I would presume “new”
would be something in more agile arena: Ruby On Rails, Drupal, Ajax are
first things that come to mind.</p>
<p>I really hope he does. It would be interesting.</p>
Drupal 5 Performance Benchmark vs Drupal 4.7
2007-02-08T00:00:00-05:00
http://www.freshblurbs.com/blog/2007/02/08/drupal-5-performance-benchmark-vs-drupal-4-7.html
<p><a href="http://buytaert.net/">Dries</a> recently published Drupal 5 performance
<a href="http://buytaert.net/drupal-5-performance">benchmark</a> results.</p>
<p>I would like to share some of my thoughts about the subject.</p>
<p>First, of course, we should appreciate that Dries took time and
performed the test. Better some results than none. However, it is only
natural that objective audience mostly meets benchmark results with
certain level of skepticism. I won’t be an exception. Personally, I
especially do not like or trust black-box performance tests. If you tell
me that A is faster than B, tell me why, show me the specific part of A
that makes it faster. It will make results much more interesting,
trustworthy and educational.</p>
<p>We’ve heard about the CSS optimization in Drupal 5 via consolidation of
many CSS files into one. We were told that the same technique is on its
way for javascripts as well. It’s great, it really is, but honestly I
think such optimization mostly affects scalability, not necessarily pure
performance at some arbitrary level. Which brings us to the next point:
I don’t like performance tests done on one arbitrary level of load. A
serious performance benchmark should show me the performance at several
load levels, so I can at least try to see the scalability trend.</p>
<p>Having criticized the methodology, let’s look at the results, per se.
What do they say?</p>
<p><img src="http://www.freshblurbs.com/files/drupal-5-performance-1.jpg" alt="" /></p>
<p>As we can see, the performance without caching is comparable if not
equal. The difference is only visible with caching turned on. Apparently
Drupal 5 has better tuned or more aggresive caching. I am not sure how I
feel about it, honestly. Generally, I do not like systems with stale
cache. I firmly believe that systems MUST be tuned to the extreme with
all non-stale mechanisms (cache that does not cause stale information is
fine because it is smart cache). Only once that is done, can we allow
extreme caching for cases like “getting slashdotted” etc.</p>
<p>To conclude, I think Drupal is CMS with the best architecture and set of
modules, there is today. It has some distance to go for performance and
being pragmatic rather than falsely cheerful will be more helpful in
that journey.</p>
<p>There was some extraneous cheer in the comments to Dries article but
Dries himself gets it: “Furthermore, [test results] suggest that for
Drupal 6, we need to look at improving the page generation time of
non-cached pages. Let’s make that an action item”. I have no doubt that
Drupal will get much better. I myself intend to contribute to that
effort, too. It’s not like I just sit here and criticize :) I love
Drupal!</p>
Spam-Free Mailto Link
2007-02-06T00:00:00-05:00
http://www.freshblurbs.com/blog/2007/02/06/spam-free-mailto-link.html
<p>By now, we’ve all learnt that simply putting a link to your e-mail
address on a website means exposing yourself to spammers. Bad idea! For
this reason, contact forms with captcha are often used instead. But
sometimes we do want to display an e-mail address.</p>
<p>What to do?</p>
<p>Well, security through obscurity may not be 100% reliable but still
helps. Some people take it too easy and write something like:
smartypants AT yahoo dot com. First of all, it is not user-friendly. It
is not a link you can click and send e-mail from. Do you expect your
users to be deciphering it? Secondly, I am sure most spam bot algorithms
can decipher it by now quicker than humans.</p>
<p>So, here is a little more sophisticated obsfuscation which renders
proper link and has been working quite well for me, so far:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><script type="text/javascript" language="JavaScript">
var atChar = "@";
var obf_eml = "i"+"n"+"f"+"o";
obf_eml += atChar;
obf_eml += "i"+"bm"+".com";
</script>
<!-- Anywhere further in HTML: -->
<script type="text/javascript" language="JavaScript">
document.write ( "<a href=\"mailto:"+obf_eml+"\">"+obf_eml+"</a>" );
</script>
</code></pre></div></div>
<script type="text/javascript" language="JavaScript">
var atChar = "@";
var obf_eml = "i"+"n"+"f"+"o";
obf_eml += atChar;
obf_eml += "i"+"bm"+".com";
</script>
<p>Example:</p>
<script type="text/javascript" language="JavaScript">
document.write ( "<a href=\"mailto:"+obf_eml+"\">"+obf_eml+"</a>" );
</script>
My Favorite SuperBowl Ad
2007-02-06T00:00:00-05:00
http://www.freshblurbs.com/blog/2007/02/06/my-favorite-superbowl-ad.html
Linux Genuine Advantage
2007-02-02T00:00:00-05:00
http://www.freshblurbs.com/blog/2007/02/02/linux-genuine-advantage.html
<p>A colleague at work just sent this to me:
http://www.linuxgenuineadvantage.org/</p>
<p><img src="http://www.freshblurbs.com/files/genuinlinux.png" alt="" /></p>
<p>Well, I am glad to see that at least some people in the Linux community
take the Redmond company seriously and try to respond to the “powerful”
<a href="http://en.wikipedia.org/wiki/Windows_Genuine_Advantage">Genuine Windows
Advantage</a>
program with adequate measures.</p>
<p>J/K :)</p>
Hot in Web 2.0: Timeline.to
2007-02-02T00:00:00-05:00
http://www.freshblurbs.com/blog/2007/02/02/hot-web-2-0-timeline.html
<p>Arguably, Web 2.0 is a loaded, even bloated word. And yet, there are
things out there that are obviously 2.0, obviously cool and excite us to
the extent that we still keep using the term and it still sounds good.</p>
<p>One such thing is the new kid on the block: <a href="http://bendiken.net">Arto
Bendiken</a>’s free service to visualize RSS and Atom
feeds in time:
<a href="http://timeline.to/?url=http%3A%2F%2Fdrupal.org%2Fplanet">http://timeline.to</a>.</p>
<p>You can get a snippet of code to visualize your own feed and republish
on your website. Type in your blog’s RSS URL in the input box and after
it gets displayed, click “show source” link at the bottom.</p>
<p>Check it out!</p>
<p>P.S. <a href="http://drupal.org/project/timeline">Guess which</a> portal engine has
Timeline module?</p>
Fix: TinyMCE Window Squished in Drupal
2007-01-31T00:00:00-05:00
http://www.freshblurbs.com/blog/2007/01/31/fix-tinymce-window-squished-drupal.html
<p>For some content types and properties, default height of the textarea
field in Drupal is 5 rows. That’s too low in itself but if you install
TinyMCE, it just plain squishes:</p>
<p><img src="http://www.freshblurbs.com/files/tinymce.jpg" alt="" /></p>
<p>Obviously, you can resize the field but why should the default be
messed-up and scare users away? Following is a quick-fix for the
problem.</p>
<p>Open includes/form.inc file in your Drupal installation and in the
beginning of the theme_textarea($element) method, insert:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> if ( $element['#rows'] < 10 ) {
$element['#rows']=25;
}
</code></pre></div></div>
<p>Enjoy!</p>
A la Apple from Microsoft
2007-01-30T00:00:00-05:00
http://www.freshblurbs.com/blog/2007/01/30/la-apple-microsoft.html
<p><br />
<a href="http://www.metacafe.com/watch/403519/welcome_to_the_so_so/">Welcome To The So-So - video powered by
Metacafe</a></p>
Multidomain The Right Way in Drupal
2007-01-28T00:00:00-05:00
http://www.freshblurbs.com/blog/2007/01/28/multidomain-right-way-drupal.html
<p>Many websites purchase variations of a domain name to protect digital
brand identity. At the minimum, companies want to own .com, .net, .org
and ccTLD versions of their brand name. Logical step is to attach all
these domains to the same website. But, wait - then the same pages will
be accessible from different URLs - not good. It’s bad for your search
(e.g. Google) rank, traffic analysis and for many other reasons, I am
lazy to list here.</p>
<p>If you are using Drupal, the main .htaccess file has a commented-out
line that fixes this problem. In the demo version, it allows you to
redirect all www.example.com traffic to example.com or vice versa. But
following the example, you can easily figure-out how to do it for other
cases, as well.</p>
<p>However, there is a problem with the default version. It chops-off the
URI part of the URL. Meaning, it will send your request to
http://example.com/news/1234 to just http://www.example.com. Not too
good.</p>
<p>So, here is the code you need instead:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>RewriteCond %{HTTP_HOST} ^example\.com$ [NC]
RewriteRule (.*) http://www.example.com/$1 [L,R=301]
</code></pre></div></div>
Drupal: Who Is Subscribed to My RSS Feed?
2007-01-28T00:00:00-05:00
http://www.freshblurbs.com/blog/2007/01/28/drupal-who-subscribed-my-rss-feed.html
<p>The RSS feed subscribers are the most valuable users of your website.
Those are the loyal customers, the true audience of your website. You do
want to know how many of those you have and who they are.</p>
<p>Unfortunately, to my knowledge, Drupal does not currently have a good
module to track RSS Feed subscriptions. It is not an easy module to
write, either because identifying unique subscriptions is non-trivial
problem.</p>
<p>In any case, there is http://www.feedburner.com and we could use its
kind services. Linking directly to FeedBurner is not such a great idea.
though. First, you may already have subscribers and you want them to be
tracked, as well. Secondly, if FeedBurner suddenly goes south you do not
want to lose all your subscriptions and - you may not want to change
http://www.example.com/rss.xml in three places in a Drupal template.</p>
<p>So, what to do? If you have access to .htaccess and mod_rewrite - you
have a perfect solution. What you will do is - you will create an
account with FeedBurner and temp-redirect (HTTP Status 302) your
original feed URL to the FeedBurner one. Sounds easy, eh?</p>
<p>But, wait… If you redirect example.com/rss.xml to FeedBurner, how will
FeedBurner itself be able to fetch your RSS to republish later? Well,
are not we lucky that Drupal allows us to create URL aliases? Let’s say
you create a new alias like: <strong>fbrssfeed</strong> pointing to <strong>rss.xml</strong>
(note: do not create an alias like “fbrss.xml” - it still contains
“rss.xml” string and things will break).</p>
<p>Once you verify that feed is accessible from
http://www.example.com/fbrssfeed and indicate it as the feed URL in
FeedBurner, open the main .htaccess file for editing and put the
following somewhere in the existing rewrites:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> # Let FeedBurner Process the main RSS feeds
RewriteCond %{HTTP_HOST} ^www\.example\.com$
RewriteRule rss.xml http://feeds\.feedburner\.com/YourFeedBurnerID [R=302,L]
RewriteCond %{HTTP_HOST} ^www\.example\.com$
RewriteRule node/feed http://feeds\.feedburner\.com/YourFeedBurnerID [R=302,L]
</code></pre></div></div>
<p>This will solve a big part of the problem. Unfortunately, it will still
not solve the problem with other RSS feeds on your website, most
importantly - tag feeds, but well -it’s better than nothing.</p>
Extreme Drupal Performance for Authenticated Sites
2007-01-26T00:00:00-05:00
http://www.freshblurbs.com/blog/2007/01/26/extreme-drupal-performance-authenticated-sites.html
<p>Cache is an often-used, non-code related fix to performance problems. No
matter what kind of cache you use, though (query cache, app cache etc.)
you do need a mechanism to repopulate cache once it is invalidated by
the system. And you definitely do not want it to be an unfortunate
flesh-and-blood user who hit the non-cached page first time, to trigger
caching. You’d much rather have a cron do that.</p>
<p>Pretty simple - put a cron in place that hits your site every minute.
Job well done.</p>
<p>Yeah, but what if your website is accessed only through authentication?
You have to be able to allow cron pass through that, somehow. And here
is how:</p>
<ol>
<li>Add a cron user to the system, with no privileges just
authentication and page view ones. Let’s name it - cron</li>
<li>Enable “path” module and create a special alias for the home page
(or page you need recached). Let’s say: “node” -> “cronnode”.</li>
<li>Install “securesite” module and secure path “cronnode”. This will
allow cron to use HTTP Authentication for this path. You need a
special path to not disrupt your flesh-n-blood users.</li>
<li>
<p>Set up a cron like the following:\</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>*/1 * * * * /usr/bin/wget -q -O /dev/null --user cron --password cpass http://example.com/cronnode
</code></pre></div> </div>
</li>
</ol>
<p>Enjoy</p>
<p>P.S. One more thing: every session opened is logged by both user and
securesite modules, so if you mind filling-up your log (probably) with
meaningless messages, you may want to do something about it in :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>user_login_submit() in modules/user.module
and
securesite_init() in securesite/securesite.module
</code></pre></div></div>
HOWTO: Profile Memory in a Linux System
2007-01-25T00:00:00-05:00
http://www.freshblurbs.com/blog/2007/01/25/how-profile-memory-linux.html
<p><strong>Disclaimer:</strong> I found this great article on <a href="http://mail.nl.linux.org/linux-mm/2003-03/msg00077.html">a Linux mailing
list</a>. It is
written by Jake Dawley-Carr and I honestly do not know what the
copyright is on it but since it was posted on a mailing list, I assume
it is in public domain. If the author contacts me, I will remove it but
meanwhile, I would like to republish it because there is no knowing how
long the article is going to be indexed and it would be too bad it to
get lost.</p>
<p> </p>
<h2 id="howto-profile-memory-in-a-linux-system">HOWTO: Profile Memory in a Linux System</h2>
<h3 id="introduction">Introduction</h3>
<p>It’s important to determine how your system utilizes
it’s resources. If your systems performance is unacceptable, it is
necessary to determine which resource is slowing the system down. This
document attempts to identify the following:</p>
<ul>
<li>What is the system memory usage per unit time?</li>
<li>How much swap is being used per unit time?</li>
<li>What does each process’ memory use look like over time?</li>
<li>What processes are using the most memory?</li>
</ul>
<p>I used a RedHat-7.3 machine (kernel-2.4.18) for my experiments, but any modern Linux distribution
with the commands “ps” and “free” would work.</p>
<h3 id="definitions">Definitions</h3>
<p><strong>RAM (Random Access Memory</strong> – Location where programs reside when they are running.
Other names for this are system memory or physical memory. The purpose
of this document is to determine if you have enough of this.</p>
<p><strong>Memory Buffers</strong> – A page cache for the virtual memory system. The kernel keeps
track of frequently accessed memory and stores the pages here.</p>
<p><strong>Memory Cached</strong> – Any modern operating system will cache files frequently
accessed. You can see the effects of this with the following commands:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>for i in 1 2; do free -o; time grep -r foo /usr/bin >/dev/null 2>/dev/null; done
</code></pre></div></div>
<p><strong>Memory Used</strong> – Amount of RAM in use by the computer.
The kernel will attempt to use as much of this as possible through
buffers and caching.</p>
<p><strong>Swap</strong> – It is possible to extend the memory space of
the computer by using the hard drive as memory. This is called swap.
Hard drives are typically several orders of magnitude slower than RAM so
swap is only used when no RAM is available.</p>
<p><strong>Swap Used</strong> – Amount of swap space used by the computer. PID (Process IDentifier) - Each process (or
instance of a running program) has a unique number. This number is
called a PID.</p>
<p><strong>PPID (Parent Process IDentifier)</strong> – A process (or running
program) can create new processes. The new process created is called a
child process. The original process is called the parent process. The
child process has a PPID equal to the PID of the parent process. There
are two exceptions to this rule. The first is a program called “init”.
This process always has a PID of 1 and a PPID of 0. The second exception
is when a parent process exit all of the child processes are adopted by
the “init” process and have a PPID of 1.</p>
<p><strong>VSIZE (Virtual memory SIZE)</strong> – The amount of memory the process is currently using. This includes the
amount in RAM and the amount in swap. RSS (Resident Set Size) - The
portion of a process that exists in physical memory (RAM). The rest of
the program exists in swap. If the computer has not used swap, this
number will be equal to VSIZE.</p>
<h3 id="what-consumes-system-memory">What consumes System Memory?</h3>
<ul>
<li>The kernel – The kernel will consume a couple of MB of memory. The memory
that the kernel consumes can not be swapped out to disk. This memory is
not reported by commands such as “free” or “ps”.</li>
<li>Running programs – Programs that have been executed will consume memory while they run.</li>
<li>Memory Buffers – The amount of memory used is managed by the kernel. You
can get the amount with “free”.</li>
<li>Memory Cached – The amount of memory
used is managed by the kernel. You can get the amount with “free”.</li>
</ul>
<h3 id="determining-system-memory-usage">Determining System Memory Usage</h3>
<p>The inputs to this section were obtained with the command:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>free -o
</code></pre></div></div>
<p>The command “free” is a c program that reads the “/proc” filesystem.</p>
<p>There are three
elements that are useful when
determining the system memory usage. They are:</p>
<ul>
<li>Memory Used</li>
<li>Memory Used - Memory Buffers - Memory Cached</li>
<li>Swap Used</li>
</ul>
<p>A graph of “Memory Used” per unit time will show the “Memory Used” asymptotically
approach the total amount of memory in the system under heavy use. This is
normal, as RAM unused is RAM wasted.</p>
<p>A graph of “Memory Used - Memory Buffered - Memory Cached” per unit time will
give a good sense of the memory use of your applications minus the effects of your operating
system. As you start new applications, this value should go up. As you
quit applications, this value should go down. If an application has a
severe memory leak, this line will have a positive slope.</p>
<p>A graph of “Swap Used” per unit time will display the swap usage. When the system
is low on RAM, a program called kswapd will swap parts of process if
they haven’t been used for some time. If the amount of swap continues to
climb at a steady rate, you may have a memory leak or you might need
more RAM. 5.</p>
<h3 id="per-process-memory-usage">Per Process Memory Usage</h3>
<p>The inputs to this section were obtained with the command:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ps -eo pid,ppid,rss,vsize,pcpu,pmem,cmd -ww --sort=pid
</code></pre></div></div>
<p>The command “ps” is a c program that reads the “/proc”
filesystem. There are two elements that are useful when determining the
per process memory usage.</p>
<p>They are:</p>
<ul>
<li>RSS</li>
<li>VSIZE</li>
</ul>
<p>A graph of RSS per unit time will show how much RAM the process is using over time. A graph
of VSIZE per unit time will show how large the process is over time.</p>
<p>.</p>
<h3 id="collecting-data">Collecting Data</h3>
<ul>
<li>Reboot the system. This will reset your systems memory use</li>
<li>
<p>Run the following commands every ten seconds and redirect the results to a file.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> free -o ps -eo pid,ppid,rss,vsize,pcpu,pmem,cmd -ww --sort=pid
</code></pre></div> </div>
</li>
<li>Do whatever you normally do on your system</li>
<li>Stop logging your data</li>
<li>Generate a Graph: System Memory Use For the output of “free”, place the following on one graph:
<ul>
<li>
<ol>
<li>X-axis is “MB Used”</li>
</ol>
</li>
<li>Y-axis is unit time Memory Used per unit time</li>
<li>Memory Used</li>
<li>Memory Buffered</li>
<li>Memory Cached per unit time</li>
<li>Swap Used per unit time</li>
</ul>
</li>
<li>Per Process Memory Use For the output of “ps”, place the following on one graph
<ul>
<li>X-axis is “MB Used”</li>
<li>Y-axis is unit time</li>
</ul>
</li>
<li>For each process with %MEM > 10.0
<ul>
<li>RSS per unit time</li>
<li>VSIZE per unit time</li>
</ul>
</li>
</ul>
<h3 id="understand-the-graphs">Understand the Graphs</h3>
<ul>
<li>System Memory Use “Memory Used” will approach “Memory Total” If “Memory Used - Memory Buffered - Memory Cached” is 75% of “Memory Used”, you either have a memory leak or you need to purchase more memory.</li>
<li>Per Process Memory Use This graph will tell you what processes are hogging the memory. If the VSIZE of any of these programs has a constant, positive slope, it may have a memory leak.</li>
</ul>
Extra Drupal Security
2007-01-25T00:00:00-05:00
http://www.freshblurbs.com/blog/2007/01/25/extra-drupal-security.html
<p>After successful installation of Drupal, it is a good practice to put
some extra security in place. I did not see it anywhere in Drupal
documentation and I get this question all the time so here is the
solution:</p>
<p>Once you finish Drupal installation, secure the cron, install and update
scripts so that they are only accessible from localhost. Put the
following snippet at the end of the .htaccess file in your Drupal
installation:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><FilesMatch "[cron|install|update]\.php">
Order deny,allow
#Allow from your_public_ips here
Allow from 127.0.0.1
Deny from all
</FilesMatch>
</code></pre></div></div>
Microsoft adCenter and Web 2.0
2007-01-24T00:00:00-05:00
http://www.freshblurbs.com/blog/2007/01/24/microsoft-adcenter-and-web-2-0.html
<p><img src="http://www.freshblurbs.com/files/microsoftadcenter.jpg" alt="" /></p>
<p><a href="http://www.startadcenter.com/keyoff/">Microsoft adCenter</a> is an
interesting example of Microsoft’s attempt to adopt <a href="http://mittermayr.wordpress.com/2006/02/03/20-culture/">Web 2.0
aesthetics</a>. It
<strong>clearly</strong> is very different from <a href="http://www.microsoft.com/windows/default.mspx">traditional Microsoft
design</a> and if you look
in the source HTML - it is amazingly clean and semantic, especially for
Microsoft. Apparently it was not done in Frontpage :)</p>
<p>Alas, it’s one thing trying and another - doing. The Sign Up button on
the home-page has all the right stuff - big font, gradient color… but,
boy, it is UGLY! Especially next to the green gradient thingie.</p>
<p>And what happened to the three orphaned paragraphs in the bottom? Why in
the world do you need to write “sign up” in such an ugly manner,
repeatedly if you have a huge sign-up button in a visible place? All of
it just reminds a lot the <a href="http://www.youtube.com/watch?v=EUXnJraKM3k">infamous iPod/MS
packaging</a> video.</p>
ISP Market Share Report
2007-01-24T00:00:00-05:00
http://www.freshblurbs.com/blog/2007/01/24/isp-market-share-report.html
<p>Security Space has published this year’s <a href="https://secure1.securityspace.com/s_survey/data/man.200612/ISPreport_new.html?plot=localhost">ISP market share
report</a>.
It provides an interesting view of top ISPs on the Internet.</p>
<p>Very useful data for research and even just FYI.</p>
Drupal: The First Argument Should Be an Array warning.
2007-01-22T00:00:00-05:00
http://www.freshblurbs.com/blog/2007/01/22/drupal-first-argument-should-be-array-warning.html
<p>When using <a href="http://www.drupal.org">Drupal</a>, you may get a nasty error
like:</p>
<p>“warning: array_key_exists(): The second argument should be either an
array or an object in…”</p>
<p>It usually happens when you make DB dump and tar-up files and move all
of it to another server/domain.</p>
<p>Quick fix is as follows: you need to log into the database and empty
cache by issuing:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>delete from cache;
</code></pre></div></div>
<p>And then you need to access admin/themes page of your website. You may,
also, need to go to admin/modules and hit “Save Settings”. All of these
help Drupal to re-initialize in the new environment and the problem
should go away.</p>
Drupal DC Meetup - Jan 24th
2007-01-22T00:00:00-05:00
http://www.freshblurbs.com/blog/2007/01/22/drupal-dc-meetup-jan-24th.html
<p><img src="http://farm1.static.flickr.com/127/359439802_ebee8f4867_o.png" alt="" /></p>
<p>First 2007 Drupal meetup in DC is this Wednesday. You can find more
information in <a href="http://groups.drupal.org/node/2408">Eric’s Announcement</a></p>
Disabling MySQL and FTP in XAMPP on Linux
2007-01-20T00:00:00-05:00
http://www.freshblurbs.com/blog/2007/01/20/disabling-mysql-and-ftp-xampp-linux.html
<p><a href="http://www.apachefriends.org/en/xampp.html">XAMPP</a> is one of the
greatest (i.e most useful) bundled open-source packages that gives an
easy, rich LAMP installation in seconds.</p>
<p>If you have tried it, you know that installing many different PHP
extensions is neither easy nor fun on Linux. Well, except, maybe on
Debian/Ubuntu where you can easily add components with apt-get. Alas, a
lot of corporate production systems run RedHat and there XAMPP comes as
real life-saver.</p>
<p>One thing about XAMPP though - it installs a whole bunch of stuff like
Apache, PHP, MySQL, Proftpd, Webmin etc. I never use or enable FTP
because I think it is insecure, legacy protocol that should never be
used. Use SSH instead. As for MySQL, I like to install it myself from
official MySQL binary distribution. It\’s a database server, hence -
tricky and needs more attention than a vanilla installation. At least -
that is my taste.</p>
<p>So, how do we disable FTP, MySQL and WebMin in XAMPP installation and
use it only for Apache/PHP/Perl (we could install Python add-on, too) ?</p>
<p>It is actually, very easy. This is what you need to do:</p>
<ol>
<li>Edit /opt/lampp/lampp script. In start,stop and reload options
comment-out everything except apache-related calls.</li>
<li>Copy /opt/lampp/lampp script to /etc/init.d/httpd to make sure it
start during operating system startup. Do not forget to put symlinks
in default runlevels.</li>
<li>
<p>Default XAMPP PHP installation will try to use default MySQL
installation\’s socket and since we want to use “our” MySQL and do
not even start XAMPP MySQL, will be unable to connect. To fix this,
edit /opt/lamp/etc/php.ini and change the appropriate line to read:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> mysql.default_socket = /var/lib/mysql/mysql.sock
</code></pre></div> </div>
<p>whereas /var/lib/mysql/mysql.sock is the location of socket file for
your custom MySQL installation.</p>
</li>
</ol>
<p>Enjoy</p>
<p><strong>Special note</strong> for all Drupal users out there: Drupal is known to have
sesion problems on PHP5 in some configurations. Due to the problem,
Drupal will keep logging you out at every page request. It has been
reported for XAMPP/PHP5 (default config), too. If you intend to use
XAMPP for Drupal, at least for the time being, we recommend to switch to
PHP4. To do so just run once:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> /opt/lampp/lampp php4
</code></pre></div></div>
Language Wars Contd.
2007-01-19T00:00:00-05:00
http://www.freshblurbs.com/blog/2007/01/19/language-wars-contd.html
<p><a href="http://www.techreview.com/Infotech/17831/page3/" title="Technology Review: The Problem with Programming">Bjarne
Stroustrup</a>:
“The purpose of a programming language is to help build good systems,
where “good” can be defined in many ways. My brief definition is,
correct, <strong>maintainable</strong>, and adequately fast.”</p>
<p>Let’s see…</p>
<p>We will skip the “adequately fast” part since I have no idea what
adequate would be for Mr. Stroustrup and besides fast/slow is determined
by language compiler/interpreter implementation not by language syntax.
We will assume Bjarne is just trying to off-handedly dismiss scripting
and VM languages,</p>
<p>Moving on…</p>
<p>What does “correct” mean? In line with all those patterns and
“best-practices” they try to teach you in all the “right” books? And, of
course, maintainable goes hand-in-hand with that, too?</p>
<p>Well, I will have to disagree here. First of all, contrary to the
popular misconception it is not “maintenance” that modern businesses
care about. Thirty years ago, maybe, they wanted systems that last
forever in the original version but not anymore. We live in a fast-phase
business environment where demand changes all the time and so should the
software that supports it.</p>
<p>It is <strong>not</strong> “maintenance” that you should care about but ease of
future modifications! And these two are by far not the same thing.</p>
<p>People who think the “maintenance” way usually spend a lot of time
finding “ideal” architecture that, in their minds, will serve all future
needs (alas, the exact same ones they have no idea about right now) and
end up with half-baked, useless monster, way late than originally
planned .</p>
<p>People who think “ease of modifications” way employ agile methodology,
write unit-tests and continuously refactor the code. Big difference.</p>
<p>In conclusion- in my personal opinion, “good” code is way more about the
personality of the developer than underlying programming language or
technology. Some people are tidy, some people are mess. Period. <</p>
<p>Have a nice weekend!</p>
<p>P.S. I give all the respect to Mr. Stroustrup for his success but other
than that, let\’s just say - he is not my hero and C++ is not my
favorite language :)</p>
'Managing' Innovation
2007-01-18T00:00:00-05:00
http://www.freshblurbs.com/blog/2007/01/18/managing-innovation.html
<p>“Innovation is “a meta-stable entity”. Nothing will kill it faster than
trying to manage it, predict it, and put it on a timeline.”</p>
<p>Vishva Dixit, vice president for research of
<a href="http://www.gene.com">Genentech</a></p>
Legal Definition of the Copyright
2007-01-18T00:00:00-05:00
http://www.freshblurbs.com/blog/2007/01/18/legal-definition-copyright.html
<p>“The primary objective of copyright is not to reward the labor of
authors, but [t]o promote the Progress of Science and useful Arts.” “To
this end, copyright assures authors the right to their original
expression, but encourages others to build freely upon the ideas and
information conveyed by a work. This result is neither unfair nor
unfortunate. It is the means by which copyright advances the progress of
science and art.”</p>
<p>– US Supreme Court Justice Sandra Day O’Connor</p>
Drupal 5 Released!
2007-01-16T00:00:00-05:00
http://www.freshblurbs.com/blog/2007/01/16/drupal-5-released.html
<p>Today is the day!</p>
<p>After much waiting Drupal 5 <a href="http://drupal.org/drupal-5.0">is released</a>.
This is smoking hot release of a great open-source portal system and I
have no doubt it will make Drupal even more popular.</p>
Practical Common Lisp
2007-01-15T00:00:00-05:00
http://www.freshblurbs.com/blog/2007/01/15/practical-common-lisp.html
<p>Even though I have some Assembly language under my belt and have worked
with, what I like to see as, wide variety of programming languges, I am
still from the spoiled generation that learnt object-oriented
programming before calculus and got on Java bandwagon early on.</p>
<p>I was fortunate to have had privilege to work with a wonderful group of
programmers. In my earlier days, <a href="http://wemmick.blogspot.com/">one of
them</a> was kind enough to spend some time
(and I imagine patience) to argue with me that Java is not panacea and
\‘“hard facts” that “best-practice” literature tries to feed us is just
one side of the truth. An often-used example was dynamic vs static and
strict vs lose typing. Lisp would come up in the discussions habitually.</p>
<p>Lisp is one of those languages that may be regarded as a dinosaur one
but people with more insight know it is too important to simply
disregard or ignore.</p>
<p>There is a wonderful review of Common Lisp by Peter Seibel, given at
Google, that gives some insight in Lisp, but more importantly - in
software architecture generally and how patterns in different
programming languages relate.</p>
<p>I think it is a great video. Highly recommended.</p>
<p> </p>
Drupal and Eclipse PDT
2007-01-15T00:00:00-05:00
http://www.freshblurbs.com/blog/2007/01/15/drupal-and-eclipse-pdt.html
<p>Drupal files have .module and .install extensions. Eclipse PHP
Development Toolkit (PDT) does not recognize those extensions as PHP
files so you have to tweak couple of settings to make PDT be more
helpful when you develop with Drupal.</p>
<ol>
<li>In Preferences - General - Editors- File Associations, associate
*.module and *.install with PHP Editor.</li>
<li>In Preferences - General - Content Types, add *.module and
*.install to Text -> PHP Content Type</li>
</ol>
<p>And, of course, make a habit of using PHP Explorer, it’s much better
than Navigator, for PHP projects!</p>
<p>cheers.</p>
No Fight - Just a Slice [of the Cake]
2007-01-12T00:00:00-05:00
http://www.freshblurbs.com/blog/2007/01/12/no-fight-just-slice-cake.html
<p>So,
<a href="http://www.engadget.com/2007/01/10/cisco-svp-mark-chandler-weighs-in-on-iphone-debacle/">apparently</a>
the main intention of Cisco, in regard with the controversy surrounding
Apple\’s use of Cisco brand - iPhone, is <strong>not</strong> cash.</p>
<p>According to Chandler, the SVP of Cisco they want interoperability in
exchange. Interoperability in exchange of brand sharing? Wow. Have you
ever even heard something like that?</p>
<p>I think it says a lot about the potential of [Apple] iPhone and the
recognition/respect everybody in the industry has for it.</p>
<p>Again - wow!</p>
A Little Bit of Pre-MacWorld Spirit :)
2007-01-09T00:00:00-05:00
http://www.freshblurbs.com/blog/2007/01/09/little-bit-pre-macworld-spirit.html
Sony LF-B20
2007-01-08T00:00:00-05:00
http://www.freshblurbs.com/blog/2007/01/08/sony-lf-b20.html
<p>Sony\’s new <a href="http://www.sonystyle.com/is-bin/INTERSHOP.enfinity/eCS/Store/en/-/USD/SY_DisplayProductInformation-Start?ProductSKU=LFB20KIT&CP=sony_12_25_heroimage_Location_Free&ref=http%3A//www.sony.com/index.php">LocationFree Wireless Base
Station</a>
looks like the sexiest gadget of the new year.</p>
<p>Finally, something original and nice in the mobile home entertainment :)
Well done, Sony!</p>
Boss
2007-01-02T00:00:00-05:00
http://www.freshblurbs.com/blog/2007/01/02/boss.html
<p>“A boss isn’t paid more than a subordinate because he or she is better.
A boss is paid more than a subordinate because the boss has greater
responsibilities. One of those responsibilities is to stand up for
people when it’s necessary and to shield them from things they shouldn’t
have to deal with.”</p>
<p>Fiorina, Carley, <em>Tough Choices: A Memoir</em>, New York: Portfolio, 2006, p
54.</p>
Was Your Santa Good to You? :)
2006-12-28T00:00:00-05:00
http://www.freshblurbs.com/blog/2006/12/28/was-your-santa-good-you.html
<p>I hope everybody had a good Santa this year and if it was not what you
haped - just remember, it can always be worse :)</p>
<p>A little smile from the past to you, from me\</p>
A Geek's Guide To File Sharing in OS X
2006-12-28T00:00:00-05:00
http://www.freshblurbs.com/blog/2006/12/28/geeks-guide-file-sharing-os-x.html
<p>If you want full control and flexibility over sharing folders from OS X
to Windows:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> sudo vi /etc/smb.conf
</code></pre></div></div>
<p>Add new section:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> [Hawaii]comment = Hawaii Photospath = /Volumes/Smth/subfolderbrowseable = yesread only = nocreate mode = 0750
</code></pre></div></div>
<p>Uncheck/check Windows File Sharing in System Preferences->Sharing,
Services tab to restart it.</p>
JSCalendar Bug in Drupal/IE
2006-12-19T00:00:00-05:00
http://www.freshblurbs.com/blog/2006/12/19/jscalendar-bug-drupal-ie.html
<p>Internet Explorer is the worst browser ever, no doubt about that, yet,
alas, it is still the most used one.</p>
<p>If you use <a href="http://www.drupal.org">Drupal</a> you probably want to use the
neat <a href="http://drupal.org/project/jstools">JSCalendar</a> plugin, since it
creates a nice date-picker for date fields. Unfortunately, the
out-of-the-box version of it does not show datepicker icon in IE (it
works just fine in Firefox/Safari etc.).</p>
<p>Apparently, the <a href="http://drupal.org/node/83662">solution</a> is to remove
the following from jscalendar.css:</p>
<p><strong>text-indent: -1000em;</strong></p>
<p> </p>
Round Cube - Amazing Web2.0Mail
2006-12-17T00:00:00-05:00
http://www.freshblurbs.com/blog/2006/12/17/round-cube-amazing-web2-0mail.html
<p>I was looking for a small, nice, light, PHP-based IMAP webmail, today.
Open-source, of course. I have been using
<a href="http://www.squirrelmail.org/">SquirrelMail</a> for the past couple of
years and it was doing a decent job, more or less. For some completely
unknown reason it stopped functioning, last week, though. We could still
check e-mail but Compose screen would never open anything more than a
blank page.</p>
<p>Too lazy to debug 2-years old code, I decided to either upgrade
SquirrelMail or find an alternative. That\’s when I got fortunate
enough to stumble upon: <a href="http://roundcube.net/">Round Cube</a></p>
<p>THIS THING IS AMAZING. Not just as far as webmails go, but it\’s an
amazing example of Web 2.0 design and user-friendliness at its best!
It\’s one of the most clean, professional code I have ever seen; And
the amazingly well-thought through, rich set of features, that the code
implements.</p>
<p>Even if you do not need a webmail, you have to see this toy, to once
again re-affirm how beautiful, simple, elegant and comfortabel a web 2.0
app can be (there is a <a href="http://roundcube.net/?p=demo">demo</a> on the
website).</p>
<p>I have no doubt that Round Cube will make a lot of buzz and will soon
(give it a year?) become de-facto standard, role-model for webmails.</p>
<p>Two thumbs up!</p>
Firefox Hashing
2006-12-15T00:00:00-05:00
http://www.freshblurbs.com/blog/2006/12/15/firefox-hashing.html
<p>One of the most useful Firefox plugins for a developer: \</p>
<p><a href="https://addons.mozilla.org/firefox/3208/">https://addons.mozilla.org/firefox/3208/</a></p>
Thank You, Marc
2006-12-11T00:00:00-05:00
http://www.freshblurbs.com/blog/2006/12/11/thank-you-marc.html
<p>I was messing with some more sophisticated
<a href="http://www.drupal.org">Drupal</a> modules, today, on my Mac.</p>
<p>Usually, I try to have minimalistic configuration of PHP on my computer
to make sure whatever i write is fairly portable. The PHP4 installation
that comes with OS X Tiger falls under such classification. So I had the
default. But I had to make the aforementioned module work. It was not
for hobby - it was work, so I had to upgrade my PHP, ASAP. Most
importantly I needed some PHP modules like mhash and GD that do not come
with the base installation.</p>
<p>Recompiling PHP is a pain. No offense but especially so on a Mac (at
least for me) since Mac has non-standard Unix layout and it is not an
orthodox Unix system, anyway.</p>
<p>That\’s where Marc Liyanage\’s wonderful package saved my day -
<a href="http://www.entropy.ch/software/macosx/php/">Enthropy</a> installer
upgraded my PHP to ver 5 with a wealth of modules installed (all that I
needed) and did so in Universal binary. Furthermore, it did not ruine my
existing Apache installation (I had to back up config and restore but
that\’s it).</p>
<p>Thanks, Marc - you really made my day! Your package rocks.</p>
Lose That Buggy Browser, Yo!
2006-12-08T00:00:00-05:00
http://www.freshblurbs.com/blog/2006/12/08/lose-buggy-browser-yo.html
<p>This appeared on my Google home-page this morning, when i tried to open
it in IE:</p>
<p>“Google recommends upgrading to the new, safer Firefox 2.0”</p>
<p><img src="http://files.motime.com/d37b279cae0c6684fe9c2c14f6956f7d.jpeg" alt="google" /></p>
<p>Cheers, Google! Not bad, not bad, at all :)</p>
Spreading the Message of (Red)
2006-11-25T00:00:00-05:00
http://www.freshblurbs.com/blog/2006/11/25/spreading-message-red.html
<p>We are humans because we care. Please, spread the message:\</p>
Quick Comment on MySQL Clustering - master.info
2006-11-23T00:00:00-05:00
http://www.freshblurbs.com/blog/2006/11/23/quick-comment-mysql-clustering-master-info.html
<p>Let\’s consider a relatively typical scenario: MySQL with clustering,
Master instance and Slave instance. The master processes day-to-day
operations and Slave is in standby to kick-in if something happens to
the master.</p>
<p>Let\’s now imagine a stormy, cold Monday that Master decided to die on.
Sysadmin quickly re-configures slave to kick-in as Master. Another
sysadmin figures-out the problem with ex-master and reincarnates it.
However, Manager decides that the swap-back can not be allowed until the
weekend (4 days left, huh?). Sysadmin decides that to minimize the
risks, it\’s the best to setup ex-master as the slave of the now-master
(ex-slave). Who knows if the current master decides to die, too? What
will we fail-over to, in that case?</p>
<p>Pretty reasonable assumption and come weekend the sysadmin re-configures
my.cnf files, once again - restarts servers + some magic that goes with
it and proud of himself goes home…</p>
<p><strong>Alert:</strong> bad move. It may be too late but eventually the sysadmin will
find out that even though he re-configured ex-slave to be master now, it
still continues to be slave, as well. He will be very surprised because
he definitely edited my.cnf and made sure that it removes all slave
properties makes the server purely master. So - what the heck?</p>
<p>MySQL creates <strong>master.info</strong> file for a slave database. Even if you
edit my.cnf and remove all traces of the instance being slave, it will
still remain to be slave unless you delete the master.info file.</p>
<p>Do not forget to remove master.info if you do not want a MySQL instance
to be a slave, anymore.</p>
Data-Bound GUI Components
2006-11-21T00:00:00-05:00
http://www.freshblurbs.com/blog/2006/11/21/data-bound-gui-components.html
<p>In almost any GUI framework (and hence accompanying visual IDE) you will
most certainly find a set of visual components that work with an RDBMS.
Furthermore, most “regular” components (like edit-field or listbox) have
the ability to bind to the database fields, as well. I think such
components are referred to as “data-bound” components. It may have been
championed by Visual Basic, but I am not sure.</p>
<p>It’s nothing new, of course. The reason i remembered about them is - I
stumbled upon them, once again, today when I was playing with one of
such framework/IDEs.</p>
<p>I really never understood why people bother to create such things.
Except the marketing buzz (or bull) about Rapid Development - I see
exactly zero sense.</p>
<p>Firstly, such components are in direct conflict with well-adopted and
recognized principle of Model-View-Controller separation. Then, even if
you do not care about MVC (why?) I honestly have never seen an
application that had a logic so simple that such components made its
development any more rapid, than it would be without them.</p>
<p>So, why do IDE/framework designers bother? Who are they trying to fool?
Are they just waisting their time?</p>
Drupal 5.0 beta - First Impressions
2006-11-18T00:00:00-05:00
http://www.freshblurbs.com/blog/2006/11/18/drupal-5-0-beta-first-impressions.html
<p>I finally got to install the new <a href="http://drupal.org/drupal-5.0-beta1">5.0
beta1</a> of
<a href="http://www.drupal.org">Drupal</a>, today.</p>
<p>I have not played with it enough to get a full impression but there are
several nice things that strike immediately:</p>
<ul>
<li>Smart and nice, web-based installation script.</li>
<li>New, beautiful, highly ergonomic and very clean, amazingly appealing
default theme - <a href="http://istyledthis.nl/">Themetastic</a>. AND IT IS
LIQUID!
I can not help admiring how good this theme is. Especially since I
have, myself, participated in the creation of default themes for
several portal and other content-management systems and I know very
well what a tough job it is.</li>
<li>Revamped Admin panel looks much better than in previous version. In
addition, it\’s separate from main site\’s template which is very
good - no need to fit to into one.
I still like Google control panel (as featured in Gmail, for
example) approach more but I can not ignore the fact that not only
Drupal\’s new panel looks better it\’s much more intelligent, as
well. I was pleasantly surprised by a collection of guiding alerts
and messages. These messages look pretty, too, by the way.</li>
</ul>
<p>Overall - great job! I am very excited with Drupal 5, personally and
look forward to using it in production.</p>
Microsoft Zune on CNN
2006-11-17T00:00:00-05:00
http://www.freshblurbs.com/blog/2006/11/17/microsoft-zune-cnn.html
<p>You should watch it to the end, even if you are an iPod fan :)\</p>
Shut Up and Sing
2006-11-12T00:00:00-05:00
http://www.freshblurbs.com/blog/2006/11/12/shut-and-sing.html
<p>I was never Dixie Chick\’s fan because I am not fan of Country music,
but I AM HUGE FAN OF FREEDOM OF SPEECH, so after what happened to Dixie
Chicks and after even the promo trailer for a documentary about it <a href="http://www.washingtonpost.com/wp-dyn/content/article/2006/10/27/AR2006102701746_2.html">was
banned from several TV
networks</a>,
I am going and buying their albums - for the sole reason of supporting
those who are opressed for expressing their beliefs.</p>
<p>Do the same or copy this clip on your blog\</p>
Web 2.0 - Cubism of the Web
2006-11-09T00:00:00-05:00
http://www.freshblurbs.com/blog/2006/11/09/web-2-0-cubism-web.html
<p>I can not help the feeling of tremendous similarity between
<a href="http://en.wikipedia.org/wiki/Cubism">Cubism</a> (as in art) and the Web
2.0 culture.</p>
<p>Apart from the similarity in the aesthetics of the visual presentation
(main principles being: simplicity and clarity), the two have a lot in
common conceptually, as well.</p>
<p>Wikipedia <a href="http://en.wikipedia.org/wiki/Cubism">defines</a> cubism as: “In
cubist artworks, objects are broken up, analyzed, and re-assembled in an
abstracted form - instead of depicting objects from one viewpoint, the
artist depicts the subject from a <strong>multitude of viewpoints</strong> to present
the piece in a greater context. Often the surfaces intersect at
seemingly random angles presenting no coherent sense of depth.”</p>
<p>Sounds
<a href="http://en.wikipedia.org/wiki/Mashup_%28web_application_hybrid%29">familiar</a>?
:)</p>
It's a Beautiful Day
2006-11-09T00:00:00-05:00
http://www.freshblurbs.com/blog/2006/11/09/its-beautiful-day.html
<p>Democrats won both House and Senate.</p>
<p>This is a very nice day and I am very happy with the outcome of the
elections. Not because I believe there is huge difference between the
parties but because I believe consolidation of power within one party
(which was the case up to now) is BAD. I also happen to enjoy more
liberal ideas so I am a little bit more sympathetic to Democrats than to
Republicans.</p>
<p>Well done!</p>
How to Select Large Blocks of Text in Safari
2006-11-03T00:00:00-05:00
http://www.freshblurbs.com/blog/2006/11/03/how-select-large-blocks-text-safari.html
<p>Although you can\‘t see a cursor when you click on text in Safari, it
seems that one might be there. If you click on a position in a line of
text in Safari, and then Shift-click somewhere else in the page\’s
text, it will select all of the text from the first place you clicked to
the place you Shift-clicked, despite the lack of a visible cursor.</p>
<p>This makes selecting really big clumps of text a lot easier, as you can
drag your scroll bar to get from one end of the selection to the other,
rather than dragging the cursor and waiting for it to autoscroll. Just
be sure not to click anywhere on the page between your first click and
the Shift-click!</p>
<p>source: <a href="http://www.macosxhints.com/">http://www.macosxhints.com/</a></p>
Apple :(
2006-11-01T00:00:00-05:00
http://www.freshblurbs.com/blog/2006/11/01/apple.html
<p>Just installed latest iTunes update and my interface became German all
of the sudden</p>
<p>WTF? :(</p>
Null values in Mysql Not-In Queries Cause Trouble
2006-10-29T00:00:00-04:00
http://www.freshblurbs.com/blog/2006/10/29/null-values-mysql-not-queries-cause-trouble.html
<p>I was debugging a piece of code today and stumbled upon a non-trivial
problem, that IMHO is worth a post about.</p>
<p>Let’s take a “simple” example where you want to find records in one
table that are not present in another table. “Present” or “Non-present”
is determined by comparision against a single column, in both tables.</p>
<p>Sounds like a query as simple as they come, right? Well, not really.
Let’s look at a sample query:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> select * from TMP_USER where UID not in (select EXT_ID from USER )
</code></pre></div></div>
<p>What does it return? The correct answer is: in MySQL, depends whether
there are any null values in EXT_ID. If there are - it returns an empty
set!!!</p>
<p>Not too easy to believe, huh? But running the same query with a slight
modification:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> select * from TMP_USER where UID not in (select EXT_ID from USER where EXT_ID is not null)
</code></pre></div></div>
<p>you empirically get 116 results, none of which have UID null.
Furthermore:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> select * from HV_TMP_USER where CUID is null
</code></pre></div></div>
<p>returns empty set. so - believe it or not - that\’s how “select .. not
in” works in MYSQL.</p>
<p><strong>Conclusion:</strong> watch-out for “not in” queries in MYSQL on a column that
may contain null-values. The resul may be empty set, when you least
expect it.</p>
MySpace & YouTube
2006-10-28T00:00:00-04:00
http://www.freshblurbs.com/blog/2006/10/28/myspace-youtube.html
<p>The two are, probably, the most talked-about Web 2.0 wannabes. They
have, obviously, been very lucrative for the respective creators, too -
considering how much money they got for them.</p>
<p>But, seriously - will they really make it? Are their business models
valid? Or will they continue to suck out the profits off the generous
sponsors like Google?</p>
<p>Ok, I do understand the whole social network/high traffic/online
marketing speculation/blah-blah but it does not bring money by some
magic. Seriously, there is more than that to it. More traffic also means
much higher operaitonal costs (especially for high-bandwidth YouTube) -
so, come on, wake up!</p>
<p>I like YouTube in the sense that it allows anybody to post large media
files - that’s cool but would I want to own it? Hell no. Just one
fact, ok? When something as ridiculously nonsensical as
<a href="http://www.youtube.com/profile?user=lonelygirl15">lonelygirl15</a> series
tops the charts of YouTube - that makes me sick to my stomach.</p>
<p>MySpace is much more complex and sophisticated. Yet, it’s still too
juvenile and cheesy for my taste. Whatever they say - their age group is
really, really limited and I suspect it’s quite localized - mostly US
users. I think, Google played a dumb curd, when they cut
such huge check for MySpace ads.</p>
<p>Conclusion: both of them are highly overrated and Google made huge
mistake to throw so much money at them. These guys (Google) are really
trying to diversify their portfolio, but, sorry, so far they are mostly
just wasting profits from their core business.</p>
<p>P.S. Don’t get me wrong - I do find a lot of value in several other
Google services, but owning YouTube,
investing so much in MySpace and that wannabe Checkout are definitely
not at the top of my list.</p>
Humanism
2006-10-24T00:00:00-04:00
http://www.freshblurbs.com/blog/2006/10/24/humanism.html
<p>“God is so clear, so close, so obvious and so simple - when you see God,
you do not realize it is God. That’s why people do not believe in God.
If God was somewhere else, far away, separate and high above, if God was
not inside us - everybody would believe in God.” - N. Dumbadze</p>
Subversion Change Log Report
2006-10-19T00:00:00-04:00
http://www.freshblurbs.com/blog/2006/10/19/subversion-change-log-report.html
<p>Subversion Change Log Report</p>
<p>Depending on your perspective, you may call it paranoia or staying on
top of the software development process, but, in my experience
architects/senior developers need to track changes to the version
control. If you are a team lead, you HAVE to know what your developers
are putting in the version control.</p>
<p>Back in old days (several years ago), when we were still on CVS, Doug
wrote a nice perl script, tied it to a cron job and we were recieving
list of daily commits to CVS regularily.</p>
<p>Now, of course SVN makes everything that was hard in CVS easy. You don’t
need to write perl scripts, any more. A colleague of mine has recently
asked me how to do the same in SVN, since they are just moving to
Subversion.</p>
<p>This is how:</p>
<p>svn -v -r “HEAD”:{20061015} log svn+ssh://user@example.com/svn/module<br />
Which for a crontab-usable script would make a source like:</p>
<p>#!/bin/sh</p>
<p>distList=”bill@microsoft.com, steve@microsoft.com, vista@microsoft.com”</p>
<p>yest=`date –date=yesterday +%Y%m%d`</p>
<p>/usr/local/bin/svn -v -r “HEAD”:{$yest} log file:///reproot/module |<br />
mail -s “Daily Commits to Module” “$distList”</p>
<p>where file:///reproot/module is your SVN URL, of course. The last two
lines should be on the same line (we just can’t do it here due to space
constraints) and you have to indicate full path to svn binary, otherwise
it will not work from cron (even if it works from just shell).<br />
I like to recieve updates twice a day, so my crontab looks like:</p>
<p>0 1,18 * * * /home/irakli/bin/dailysvnchangelog.sh >
/tmp/dailysvnchangelog.log</p>
Exception Handling and the Chain of Responsibility Design Pattern
2006-10-18T00:00:00-04:00
http://www.freshblurbs.com/blog/2006/10/18/exception-handling-and-chain-responsibility-design-pattern.html
<p>Developers often compain about explicit Exceptions, especially in a
strongly typed language like Java, and how much real estate handling
those takes up in source code.</p>
<p>I have seen approaches when people try to avoid java.lang.Exception and
fall back to java.lang.RuntimeException for most cases. Is that a good
thing to do? RuntimeException is a valid choice for certain cases but
overusing it beats the whole idea of exception-handling, really.</p>
<p>As part of my responsibilites as a software architect, I get to review
code of many developers. I think the problem, in most cases, is
incorrect usage of exception-handling. More specificly, developers
overdo with catching exceptions at the lowest level - at the same spot
they expect exception to be fired. Passing it up the class hierarchy is
often needed but not done. It is especially true in the case of more
junior developers (however, you quickly find out that many “senior”
developers are vulnarable, as well).</p>
<p>If you look at a software system, especially a web-application and more
so a well-design one, it is, basically, an implementation of the Chain
of Responsibility pattern for different use-cases. Developer immidiately
catching an exception wherever it is fired is often a bad thing to do.
In many cases, a much more correct (and elegant) approach is to pass it
up the chain of responsibility. Unfortunately, if you look at a common
code, you rarely see a method declared with “throws” keyword. So, a lot
of times, developers try to handle exception in the lowest methods and
do not pass it up the chain. That’s bad. Many errors can/should be
grouped and handled uniformally.</p>
<p>For instance, when you have a database transaction that spans across
several methods, do not try to handle JDBC/Hibernate/EJB exceptions in
each method - declare a sensible exception subclass and pass it up, at
least to the class that is handling the entire transaction. Then the
upper-level class can handle all these exceptions and make a decision of
rolling back the entire transaction, which in most cases is what should
happen, indeed.</p>
<p>Bottomline: “throws” is just as useful as try/catch - use it!</p>
DC Panorama
2006-10-14T00:00:00-04:00
http://www.freshblurbs.com/blog/2006/10/14/dc-panorama.html
<p>I was jailed into my computer for the entire last week (and then some
more) so I decided to take a long walk this morning. I dropped my car
off in Courthouse, for oil change and walked back home.</p>
<p>It is a beautiful, sunny day. As I was crossing the K bridge I could not
help admire the view of DC, so I grabbed my cell out and took a photo.
Here it is:</p>
<p><a href="http://www.ajafsandali.com/wp-content/uploads/2006/10/dc-panorama.jpg"><img src="http://www.ajafsandali.com/wp-content/uploads/2006/10/picture-7.png" alt="" /></a>
<br />
(click on the photo to view larger version)</p>
Apple iPhone
2006-10-11T00:00:00-04:00
http://www.freshblurbs.com/blog/2006/10/11/apple-iphone.html
<p>So,
<a href="http://www.t3.co.uk/news/247/entertainment/mp3_player/t-mobile_to_partner_apple_iphone">T-Mobile</a>
or
<a href="http://www.t3.co.uk/news/247/communications/mobile_phone/evidence_mounts_for_january_iphone">Cingular</a>?</p>
<p>I was about to switch to Cingular and now they leave me wondering,
again. I still think Cingular is MUCH more solid of a partner than
T-Mobile. I guess, the real question for Apple, right now, is - which
one of them will be able to roll-out wider, better 3G coverage? Clearly,
that\’s what iPhone will be all about, not just a lame-ass let\’s talk
phone.</p>
<p>Can\‘t wait</p>
Widgets You Have to Have
2006-10-01T00:00:00-04:00
http://www.freshblurbs.com/blog/2006/10/01/widgets-you-have-have.html
<p>This is a list of third-party widgets that are way too useful/necessary
(at least, for geeks) to miss out on them:</p>
<ul>
<li><a href="http://www.apple.com/downloads/dashboard/calculate_convert/pemdas.html">http://www.apple.com/downloads/dashboard/calculate_convert/pemdas.html</a>
The original Apple dashboard calc just plain sucks. This one is
awesome.</li>
<li><a href="http://www.apple.com/downloads/dashboard/status/istatnano.html">A truly wonderful system monitor
tool</a>
LOVE IT</li>
<li><a href="http://www.apple.com/downloads/dashboard/developer/cruisecontrolwidget.html">Cruise
Control</a></li>
<li><a href="http://www.apple.com/downloads/dashboard/developer/regexwidget.html">Regexes</a></li>
<li><a href="http://www.apple.com/downloads/dashboard/developer/phpfunctionreference.html">PHP
Reference</a></li>
<li><a href="http://www.apple.com/downloads/dashboard/developer/javadoc.html">Quick Javadoc
access</a></li>
<li>Timer should be the best friend of any geek. We are too absent
minded when we concenrtate on something so a friendly help in
time-management is VERY much appreciatet. that\’s what this little
widget:
<a href="http://www.apple.com/downloads/dashboard/calculate_convert/321.html">http://www.apple.com/downloads/dashboard/calculate_convert/321.html</a>
helps with in a very friendly and nice-looking way</li>
</ul>
Stoned Professor
2006-10-01T00:00:00-04:00
http://www.freshblurbs.com/blog/2006/10/01/stoned-professor.html
<p>Dude, I want a professor like this :)\</p>
<p>Courtesy of
<a href="http://www.break.com/index/stoned_professor.html">break.com</a></p>
Face Recognition Revisited
2006-09-25T00:00:00-04:00
http://www.freshblurbs.com/blog/2006/09/25/face-recognition-revisited.html
<p>New cool Web 2.0 service - face recognition techniques in motion to
identify which celebrity looks like you: <br />
<br />
<a href="http://www.myheritage.com/">http://www.myheritage.com/</a> <br />
<br />
Not bad :)</p>
Are you Web 2.0?
2006-09-24T00:00:00-04:00
http://www.freshblurbs.com/blog/2006/09/24/are-you-web-2-0.html
<p>Due to the buzz, many companies claim/pretend to be “Web 2.0”. Are they?
Tim O\‘Reilly describes the history of Web 2.0 and the main
characteristics of a Web 2.0 service in his <a href="http://www.oreillynet.com/pub/a/oreilly/tim/news/2005/09/30/what-is-web-20.html?page=1">thoughtful
article</a>,
summarizing the features of a Web 2.0 service in a nice list:\</p>
<h3 id="core-competencies-of-web-20-companies">“Core Competencies of Web 2.0 Companies</h3>
<p>In exploring the seven principles above, we\‘ve highlighted some of the
principal features of Web 2.0. Each of the examples we\‘ve explored
demonstrates one or more of those key principles, but may miss others.
Let\’s close, therefore, by summarizing what we believe to be the core
competencies of Web 2.0 companies:</p>
<ul>
<li>Services, not packaged software, with cost-effective scalability</li>
<li>Control over unique, hard-to-recreate data sources that get richer
as more people use them</li>
<li>Trusting users as co-developers</li>
<li>Harnessing collective intelligence</li>
<li>Leveraging the long tail through customer self-service</li>
<li>Software above the level of a single device</li>
<li>Lightweight user interfaces, development models, AND business models</li>
</ul>
<p>The next time a company claims that it\’s “Web 2.0,” test their
features against the list above. The more points they score, the more
they are worthy of the name. Remember, though, that excellence in one
area may be more telling than some small steps in all seven.”</p>
New iTunes
2006-09-13T00:00:00-04:00
http://www.freshblurbs.com/blog/2006/09/13/new-itunes.html
<p>New iTunes was just realeased. I installed the update - it does look
great and all but…</p>
<p>I have two iPods (nano and a video one) and an iMac as well as a macBook
(let’s forget Sony Vaio for a bit). So my question is - when the H…
will it be possible to seamlessly share my iTunes library across all of
these 4 devices? It is PAIN right now.</p>
<p>Come on, Apple!</p>
JDBC: Get Last Insert's ID
2006-09-10T00:00:00-04:00
http://www.freshblurbs.com/blog/2006/09/10/jdbc-get-last-inserts-id.html
<p>OK, so I need this frequently enough to care (when I do direct JDBC for
some data-mining, data-migration or any other mass-db operations) but
not frequently enough to memorize (as I use Hibernate normally).
Therefore, it seems like a good idea to post it here and be able to find
it later, if I need it again :)</p>
<p>Oh, and maybe somebody else may benefit from it too. Heh</p>
<p>So, if, in JDBC, you need to get the IDs of the last inserts when using
auto_generated primary keys on the database side (e.g. sequences) you
should use getGeneratedKeys() method of java.sql.PreparedStatement</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>resultSet = pstmt.getGeneratedKeys();
if ( resultSet != null && resultSet.next() )
{
newid = resultSet.getInt(1);
}
</code></pre></div></div>
<p>The example shows how to get one ID but you can get all IDs of a
mass-insert, as well. Pretty cool.</p>
GTalk Update
2006-08-17T00:00:00-04:00
http://www.freshblurbs.com/blog/2006/08/17/gtalk-update.html
<p>Google Talk <a href="http://www.google.com/talk/whatsnew.html">now has</a> file
transfer, FINALLY! Voice Mail and “View Past Chats” directly from the
context menu are two more nice, new features.</p>
No Public Smoking
2006-08-11T00:00:00-04:00
http://www.freshblurbs.com/blog/2006/08/11/no-public-smoking.html
<p>Ok, granted, this makes sense :)</p>
<p><img src="http://static.flickr.com/79/212527136_590b0197c0.jpg?v=0" alt="" /></p>
Sun, Tube and Butts
2006-07-30T00:00:00-04:00
http://www.freshblurbs.com/blog/2006/07/30/sun-tube-and-butts.html
<p>We went <a href="http://www.buttstubes.com/">tubing</a> yesterday with some
friends.</p>
<p>Of course, I was late to get my butt off home and ended up being an hour
late to pick up Olga. She was <strong>pissed</strong> since other folks had left and
supposedly were already at the destination .</p>
<p>Yet, everything happens for a reason. To my luck, these guys managed to
somehow get lost., even though they had been there at least 5 times
before. They ended up spending more than an hour cruising around and
sounded quite confused on the phone. All in all, we arrived first and
Olga was off my back.</p>
<p>The highlight of the drive was some crazy biker who passed me at the
speed I have never seen before anybody driving bike at. I checked my
speedometer - it showed 120mph. Yet, this dude just flew beside me. He
must have been doing 130 or 140 <strong>on a bike</strong>! Incredible. How do crazy
kids like this live to grow up and manage to remain in one piece? It
probably has to do with statistics. Enough die, some remain. It\’s all
about math, goddammit!</p>
<p>A piece of advice: if you go to <a href="http://www.buttstubes.com/">Butts
Tubes</a>, do yourself a favor and show up
early in the morning! When we arrived, we found ourselves in the tail of
two incredibly long lines (one to get tickets, another - to get on the
bus). Spending 2 hours under blazing sun may be fun for somebody but
that definitely ain\‘t me.</p>
<p>Between me and Olga, one could make a very organized person. Separately,
both of us forget things all the time. I forgot sun-screen. Fortunately
she did not. Considering how much time we spent under the sun it was
good thing. I paid her back with a towel, later. I knew she\‘d forget
it so took two with me.</p>
<p>The river was way slow. We had to raw too much and considering I am a
lazy bum, in general, I had less fun in the tube. Fortunately, there
were a whole bunch of cool rock-islands. We camped on those and enjoyed
the wealthy supply of beer we took along in two coolers. It was not that
bad, after all. Water, sun and beer is always good. Also, some rocks had
deep water and you could jump. That\’s when Marcus lost his cap. I
fished it out down the river, later, though</p>
<p>The day did not pass without an accident. Olga lost her sun-glasses
under a waterfall and I forgot to put sun-screen on my legs. Boy, it
was burning when I got home! Sun-burn is no joke. I was moaning whole
night and barely managed to go to sleep. Still feels itchy but I do not
have a feeling of wanting to die to avoid the pain, any more.</p>
<p>In the evening we ended up in some nearby bar. At 9, some local band was
supposed to perform. The bar-tender told us, the lead singer was
bringing his wife to sing together. Bar-tender thought it was pretty
cool but we wisely decided to depart, especially since we were done with
foods and drink.</p>
<p>The waitress was kinda cute…</p>
<p> </p>
<p>\x00</p>
Google Launches Open Source Code Hosting
2006-07-28T00:00:00-04:00
http://www.freshblurbs.com/blog/2006/07/28/google-launches-open-source-code-hosting.html
<p>Google launched open-source projects <a href="http://code.google.com/hosting/">hosting
site</a>. It looks pretty good. I guess I
will have to register something and try it out :)</p>
Safari Theme for Firefox
2006-07-26T00:00:00-04:00
http://www.freshblurbs.com/blog/2006/07/26/safari-theme-firefox.html
<p>I really do not like default Firefox theme. It look like a 5 years old
kid\’s toy. Unfortunately, up until now alternatives were even worse.
Most of them feel like lunatics were creating these terrible
greeon-on-black-and-some-red nightmares. <br />
<br />
Fortunately, there is a solution now. Somebody had common sense enough
to “steal” Safari skin. Oh, well - at least it looks much more pleasant
:) <br />
\</p>
<p><a href="https://addons.mozilla.org/firefox/1322/">https://addons.mozilla.org/firefox/1322/</a></p>
Google = Silver Bullet?
2006-07-25T00:00:00-04:00
http://www.freshblurbs.com/blog/2006/07/25/google-silver-bullet.html
<p>Since the rise of Google a whole cast of people emerged who do not get a
simple fact:</p>
<p><strong>Wisdom of the universe is not contained simply in top 10 results of
Google searches.</strong></p>
<p>It is annoying. Folks, you can not just google some crap and think you
know everything about anything. Most of the time, it takes much deeper
understanding of things.</p>
<p>Sigh</p>
IntelliJ TeamCity
2006-07-18T00:00:00-04:00
http://www.freshblurbs.com/blog/2006/07/18/intellij-teamcity.html
<p>JetBrains announced a new product for Java developers - TeamCity.
According to the announcement, it is an intelligent team environment,
extending upon the intelligent IDE from the same vendor (IntelliJ IDEA
of course). Feature set looks really promising and knowing JetBrains\’
implementation excellence, expectationa are real high.</p>
<p>Read more at:
<a href="http://www.jetbrains.com/teamcity/">http://www.jetbrains.com/teamcity/</a></p>
Google, Competition and Good Marketing.
2006-07-05T00:00:00-04:00
http://www.freshblurbs.com/blog/2006/07/05/google-competition-and-good-marketing.html
<p>This happened to me today and I thought it was funny enough to share.</p>
<p>So, I am doing a little research on cheap IP Telephony solutions. I know
Vonage because they have so much advertising - it just sunk in my mind.
But what I also know from the word-of-mouth, anecdotal evidence is that
their service is not too reliable or cheap. At least, my impression from
what I heard is that they grew so fast, they lacked quality in the
process.</p>
<p>I also remember that some of my friends are using a smaller-shop
alternative to Vonage that they are very happy with. Unfortunately, I do
not remember the name of the service and these friends of mine are not
online. So I fall back to Google, of course.</p>
<p>Now, I need to type something sensible. I try “ip telephony” but it
returns all the big shots and nothing like what I need.</p>
<p>And then I have this idea - if these guys are good, they must have
bought “vonage” as a keyword on Google, eh? So, excited with the thought
I type “vonage” in Google and sure \‘nough, <a href="http://www.sunrocket.com/">the company I was looking
for</a> shows up as #2 hit.</p>
<p>nice :)</p>
Windows Vista Beta 2
2006-06-26T00:00:00-04:00
http://www.freshblurbs.com/blog/2006/06/26/windows-vista-beta-2.html
<p>Windows Vista Beta 2 Screenshot (Click to enlarge):</p>
<p><a href="http://static.flickr.com/60/175257883_f58b9b449d_b.jpg" title="Photo Sharing"><img src="http://static.flickr.com/60/175257883_f58b9b449d_b.jpg" alt="vista" /></a></p>
<p>Pros: <br />
Huge progress in user-interface design compared to Windows XP. More
user friendly - I could not help a chuckle to find C:\\Users folder,
but it\’s still good. Much richer functionality.</p>
<p>Cons: <br />
I installed 64 bit version Vista (from my MSND subscription) on my
AMD64 dual-core HP m7334n. Vista was unable to detect my wi-fi ethernet
card, or audio or TV Tuner. I indicated the “Recovery” folder where all
the drivers should reside - still no luck. After I went through the pain
of hooking the pc up be a network cable, it was able to install TV-Tuner
but still no luck with the audio or wi-fi. THAT REALLY PISSED ME OFF.</p>
<p>Apparently, Microsoft was watching Mac closely and trying to lern stuff.
They definitely have made some progress in stealing ideas and Vista
looks way better than XP (and way more like OS X) but it\’s still MS
and it\’s still shit.</p>
<p>Operating system unable to find all drivers for a new, brand HP desktop?
Idiots.</p>
Webby Awards
2006-06-22T00:00:00-04:00
http://www.freshblurbs.com/blog/2006/06/22/webby-awards.html
<p>Webby awards is considered “the Oscars of the Web”. Now, not that I have
much (or any) respect for Oscars but it still makes me sad to look at
the latest Webby Awards:
<a href="http://www.webbyawards.com/webbys/current.php?season=10">http://www.webbyawards.com/webbys/current.php?season=10</a></p>
<p>I mean - come on, guys. The whole world just can\‘t stop talking about
Web 2.0 aesthetics of simplicity and most of the winners of Webby are
Flash-based sites? Are we in 1995?</p>
<p>Funny.</p>
<p>Anyways, the 5-word speech thing is still kinda cool :)</p>
New Mac Ads Ready To Watch
2006-06-13T00:00:00-04:00
http://www.freshblurbs.com/blog/2006/06/13/new-mac-ads-ready-watch.html
<p>Dont miss them
<a href="http://www.apple.com/getamac">http://www.apple.com/getamac</a></p>
Where Did the Common Sense Go?
2006-06-12T00:00:00-04:00
http://www.freshblurbs.com/blog/2006/06/12/where-did-common-sense-go.html
<p>This has been going on for a long time, now, and is becoming really
worrying. There is a whole bunch of people, in the IT industry, whose
sole goal is to be “recognized” as a “thought-leader”.</p>
<p>When I think about a thought-leader, the first face that comes to my
mind is Einstein, even if with that famous tongue of his out :) That was
a thought-leader. Hell, probably the greatest one. Do you really think,
he ever cared how high his recognition rate was? All he cared about was
his own curiosity and the desire to figure things out. That’s what real
thinkers do, not - watch number of hits on his/her blog.</p>
<p>The problem with this “wanna be a thought-leader” craziness is greater
than we may realize. Soon enough we will hardly have anybody who bothers
to think. We will only have three groups: people who try to make buzz
off of trivial stuff; people who were too late to get on that train and
hence try to retaliate by criticizing; and finally the largest and most
disgusting group of penguins who are too lazy to think for themselves
and just blindly join one or the other group. That way, they won’t have
to justify their poor decisions to the management - just mention some
buzz words, some “legendary” names and - you are off the hook, if your
manager is stupid nough, which of course, they usually are.</p>
<p>If you think this is an exaggeration, look around more tentatively and
put some effort to notice all the heat around Spring, SOA, Agile
practices - whatever else the buzzword of the day happens to be.</p>
<p>PEOPLE, it does not freaking matter whether you do agile or whatever, as
far as you do your job well. And if you dont - you could as well get
lost in a very agile way.</p>
<p>How hard is that to get?</p>
<p>*sigh* and cheers to all people who still have some common sense left.</p>
Google Video Player
2006-06-12T00:00:00-04:00
http://www.freshblurbs.com/blog/2006/06/12/google-video-player.html
<p>Google Video Player has come to OS X, too. Downlowd it from
<a href="http://video.google.com/playerdownload_mac.html">here</a></p>
BEA Weblogic on OS X
2006-06-08T00:00:00-04:00
http://www.freshblurbs.com/blog/2006/06/08/bea-weblogic-os-x.html
<p>Following are detailed instructions for installing Weblogic 9.1 on OS X
Panther.</p>
<p>Download AIX version of Weblogic 9.1 (AIX as that’s the generic version
of WebLogic, in fact). You can download it
from:http://commerce.bea.com/showproduct.jsp?family=WLS&major;=9.1&minor;=0</p>
<p>Run the installation with the following command: <br />
java -Dos.name=unix -jar server910_generic.jar</p>
<p>it’s crucial to indicate os.name parameter. Otherwise, installer will
complain about insufficient disk space.</p>
<p>At the end of installation you will be asked whether to run QuickStart.
I recommend not to, as it hung on me.</p>
<p>In any case, you need to create a new weblogic domain, first by running:
<br />
~/bea/weblogic91/common/bin/config.sh</p>
<p>Domain creator will ask about JDK. It actually manages to find Apple’s
one but in case that fails, indicate the following path: <br />
/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home</p>
<p>To run the server, go to the following directory from Terminal: <br />
~/bea/user_projects/domains/<domain_name> <br />
e.g. if your domain name is “base_domain” then go to: <br />
~/bea/user_projects/domains/base_domain</p>
<p>and then run: <br />
./startWebLogic.sh</p>
<p>Server will try to run on port 7001.</p>
<p>Note: when I first started the server it complained about 7001 being
unavailable and ketp shutting down. Later I found a runaway java process
listening on 7001. I suspect it was a leftover from the frozen
Quickstart crap. I killed all java processes, then tryed started
Weblogic and it worked like charm.</p>
<p>When the server starts up, you can access admin console
from:http://localhost:7001/console/</p>
<p>enjoy</p>
Constraint Your Data
2006-06-07T00:00:00-04:00
http://www.freshblurbs.com/blog/2006/06/07/constraint-your-data.html
<p>Sometimes we do not know the size of the data or information that will
be displayed on a page, or worse - we know it will be too large.
Examples of such cases are: large data tables or code listing. Having
page strech is not the best thing to happen obviously. Using IFrames is
even worse.</p>
<p>This is where <div> tag and css style overflow come in handy. <br />
<br />
Put your troublesome area in a div like:</p>
<p><div style=”width:420px; height:200px; overflow:auto”> <br />
DATA OF ANY SIZE <br />
</div></p>
<p>and you can rest assured that this area will have exactly 420x200 size,
with nice vertical and/or horizontal scrollbars appearing if needed.</p>
<p>enjoy</p>
Awesome EDS Commercial
2006-06-03T00:00:00-04:00
http://www.freshblurbs.com/blog/2006/06/03/awesome-eds-commercial.html
<p>Very nice commercial from EDS:
<a href="http://video.google.com/videoplay?docid=4057591681481453187">http://video.google.com/videoplay?docid=4057591681481453187</a></p>
CSS Box Model
2006-05-31T00:00:00-04:00
http://www.freshblurbs.com/blog/2006/05/31/css-box-model.html
<p>As you know, in CSS box model, you can indicate all 4 arguments
together.</p>
<p>e.g. <strong>margin: 0px 0px 0px 0px;</strong></p>
<p>But then, it is not easy to remember which argument stands for which
side. Which one is top or right or left? They go around the clock but
then - where does it start? I used to forget it all the time, despite
many efforts to memoize.</p>
<p>When that happens you gotta use a trick :) And the trick was quickly
found with some help of a good friend of mine -
<a href="http://wemmick.blogspot.com/">Doug</a></p>
<p><strong>TRICK</strong></p>
<p>The sequence in CSS goes like this: Top, Right, Bottom, Left or - TRBL.
You can easily see what it stands for, now, don\‘t you? <strong>TR</strong>OU
<strong>BL</strong>E</p>
<p>You will never forget trouble, if you don\‘t want CSS trouble ;)</p>
<p> </p>
MacBook Runs Windows XP SP2 Flawlessly
2006-05-19T00:00:00-04:00
http://www.freshblurbs.com/blog/2006/05/19/macbook-runs-windows-xp-sp2-flawlessly.html
<p>I installed Windows XP SP2 on my brand-new MacBook yesterday. The
installation was a breeze (except it took REALLY LONG, for some reason)
and after installing Windows has superb performance. Quite honestly I
have never had such fast Windows before (even though one of my desktop
computers is Athlon X2).</p>
<p>Very impressive. The only downsides are: there is no way to right-click
on touchpad when in Windows. Which means - mouse is a must in Windows.
Camera does not work either :( Which is no surprise since Bootcamp
instructions do mention there is no driver, nevertheless - it is sad :(</p>
<p>But in any case, I can now use my MacBook for ANYTHING I need and I can
hardly express how awesome that is!</p>
<p>Below are couple of screenshots for your entertainment:</p>
<p><img src="http://www.iveria.eu/uploads/post-4-1148040376_thumb.jpg" alt="" /></p>
<p><img src="http://www.iveria.eu/uploads/post-4-1148040389_thumb.jpg" alt="" /></p>
Great Tune To Start Your Day With
2006-05-18T00:00:00-04:00
http://www.freshblurbs.com/blog/2006/05/18/great-tune-start-your-day.html
<p>Here it is:
<a href="http://de.fishki.net/pics9/tyts.swf">http://de.fishki.net/pics9/tyts.swf</a>.
Put your headphones on, if you are in the office and enjoy :)</p>
<p>If somebody knows the name of the song and can comment here - it will be
greatly appreciated. cheers.</p>
Second Level Cache Size on Windows
2006-05-15T00:00:00-04:00
http://www.freshblurbs.com/blog/2006/05/15/second-level-cache-size-windows.html
<p>Do you have a nice, new computer with large L2 cache? Probably, you
payed extra to get 2MB L2 instead of a lesser alternative. Well, here is
the news - Windows is not using all that extra goods of your CPU. By
default Windows only uses 256KB of your second-level (L2) cache. Ouch!</p>
<p>Here is how to make the bastard stop wasting your valuable resources (L2
cache has significant impact on the performance):</p>
<ol>
<li>fire up registry editor (Start-Run-regedit)</li>
<li>Edit the key:
[HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Session
Manager\\MemoryManagement\\SecondLevelDataCache]</li>
<li>Enter appropriate amount of L2 cache size. Options are: 0 - 256KB
(default), 200 - 512KB, 400 - 1024KB (1MB), 800 - 2048KB (2MB)</li>
</ol>
<p>enjoy!</p>
Free and Open-Source Software (FOSS)
2006-05-14T00:00:00-04:00
http://www.freshblurbs.com/blog/2006/05/14/free-and-open-source-software-foss.html
<p>Julie Inlow of the University of Maryland has recently interviewed me
about FOSS, for her research. I decided to publish this interview in the
hope that somebody else may find it interesting, as well. I strongly
believe in the open-source. If this posting helps at least one person to
consider FOSS more seriosuly, I will feel mission is accomplished.</p>
<p><strong>Why is open source important to you? AKA - why do you care about
FOSS?</strong></p>
<p>For me the benefits of FOSS have three equally important facets:
business, technological and social.</p>
<p>At the business side, employing FOSS allows organizations to avoid
<a href="http://en.wikipedia.org/wiki/Vendor_lock-in"><em>vendor lock-in</em></a>. Using
FOSS, managers substantially decrease dependencies on third parties, and
mitigate a sizable risk. Unfortunately, not many executives understand a
simple reality - when you build your technology on top of proprietary
components you inherently tie project’s future to what happens in the
vendor companies.</p>
<p>Managers usually comfort themselves with the thought that large vendors
like IBM, Oracle, SAP, Microsoft and others are “reliable�. True as
it may be, that does not matter! In reality, the interests of clients
and vendors are not aligned. It is wrong to assume that all decisions
made by a vendor will be favorable for a client. Dependency on a vendor
is a risk. Whether this risk will materialize or not is a matter of a
chance but gambling is better left for a weekend in Las-Vegas.</p>
<p>Technological benefits of FOSS include: flexibility, control and
transparency. The source codes of FOSS programs are available for
viewing and modification. Theoretically, there are no limits in using a
FOSS component. An important consequence of the transparency is that
often mature FOSS products are more bug-free than their proprietary
alternatives. The reason is simple: more eyeballs looking at the source
code, less the chance for a bug to slip through.</p>
<p>Another important impact of FOSS is the social one. Free and open-source
model brings people together that would have little chance to work
together, otherwise. In what other model does a young programmer from a
“third-world� country get a chance to be a peer to a seasoned
professional from, say, IBM? FOSS projects give unprecedented
opportunities to talented people all over the world, no matter where
they are and what their native language is.</p>
<p>I think we are only starting to understand just how revolutionary the
social impact of FOSS is.</p>
<p><strong>When did you become interested?</strong></p>
<p>I have been interested in FOSS for a long time, now but probably it
became a much larger part of my professional life when I joined the
World Bank in 2001. I was lucky to work with a group there that was one
of the first, in the Bank, to champion the usage and development of the
FOSS software.</p>
<p><strong>What roles have you played / actions taken in the open source
community? In what activities have you participated?</strong></p>
<p>I have helped organizations adopt FOSS software, migrate to FOSS
software. I have contributed to and participated in several FOSS
projects.</p>
<p><strong>From your perspective, what primary factors influence or discourage
diffusion and adoption?</strong></p>
<p>It is a very complex subject that is hard to answer in several
sentences. If I had to name just several of the reasons I would say:
lack of knowledge and understanding amongst the decision-making
managers, lack of professional support for the FOSS components (there
has been significant progress in this regard, lately, though), lack of
legislature promoting FOSS as a public good, tremendous amount of
lobbing and blocking from large proprietary vendors who see FOSS as a
threat to their businesses.</p>
<p><strong>In the future, what role do you see FOSS playing? In private sector?
In the public sector? In the US? Abroad? Which countries?</strong></p>
<p>I think, just like any other strategic decision, adopting FOSS is a
business decision. We just discussed what could be incentives for
business managers to go FOSS way. These incentives are not only valid in
certain geographical location or industry segments. Where will people be
smart enough to not ignore FOSS and at least seriously consider it? I
don’t know. I hope – everywhere, eventually.</p>
<p>As far as the development of FOSS products goes, I firmly believe that
FOSS can be a viable business model. Don’t get me wrong, not all
software can or may be FOSS, but FOSS products can definitely generate
revenue, just as well as their proprietary counterparts do. There are
numerous examples of successful FOSS companies so I do not see a reason
why others should not try when appropriate.</p>
<p><strong>Do you think government should formally encourage FOSS development via
policy vehicles or let market forces drive development?</strong></p>
<p>I do think that governments must encourage FOSS. As a matter of fact,
there are governments that already do it. Governments of Brazil and
Bavaria are good examples.</p>
<p>I think the real problem is in the minds of the vendors who are
resistant and/or unable to adapt and start thinking the new way. They
are so used to capitalizing on patents and restrictive licenses that are
unable to think outside of that tiny box. They don’t notice that it is
not the only and always the best way profits can be generated. If you
think how ridiculous some patents are, you will not be too surprised
that there are people who request software patents to be abolished
entirely.</p>
<p>I am far from thinking that all software must be FOSS, but FOSS and
proprietary software must be put at equal terms. Once that is done,
market forces will determine what is the best model for each particular
case.</p>
<p>I think, this is one of the areas where governments can step up. Old
legislature related to intellectual property rights and patents must be
changed. It must be brought in consistency with the new reality.</p>
New Mac Ads
2006-05-02T00:00:00-04:00
http://www.freshblurbs.com/blog/2006/05/02/new-mac-ads.html
<p>New Mac ads are out. Check them out and have fun :)</p>
<p><a href="http://www.apple.com/getamac/ads/">http://www.apple.com/getamac/ads/</a></p>
How Many Microseconds are there in a Nanosecond?
2006-05-01T00:00:00-04:00
http://www.freshblurbs.com/blog/2006/05/01/how-many-microseconds-are-there-nanosecond.html
<p>Do you know how many microseconds are there in a nanosecond? You thought
it was 10^-3^, eh? Heh, think twice and no, I have not gone nuts. At
least, not yet. Read on.</p>
<p>More seriously, what am I ranting about, here? Time precision in Java,
is the topic.</p>
<p>Today, I needed to profile a process which takes less than a millisecond
(10^-3^ seconds). Up to and including JDK 1.4 the precision of Java time
used to be order of a millisecond and for anything more precise you were
pointed to JNI, which is a nasty place to be pointed to, let me say.
Fortunately enough JDK 5 has added
<a href="http://java.sun.com/j2se/1.5.0/docs/api/java/lang/System.html#nanoTime%28%29">System.nanoTime()</a>
method and Sun has honestly implemented it in its JDK. Thanks a lot to
Sun, for that but - hold the excitement, for a second.</p>
<p>Does this method really give the precision of a nanosecond? Let’s check
it (using a tuned version of the code from <a href="http://www.javaworld.com/javaworld/javaqa/2003-01/01-qa-0110-timing.html">Vladimir
Roubtsov</a>):</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>public class Test {
public static void main( String[] args) {
// Let JVM warm up and do whatever optimizations:
for (int i = 0; i < 10000; i++) System.nanoTime ();
long start = System.nanoTime(), end = start;
long accumulated = 0;
int iterations = 200;
for (int i = 0; i < iterations; i++) {
// Wait till the system time changes:
while ( end == start )
end = System.nanoTime ();
}
accumulated += ( end - start );
start = end = System.nanoTime ();
}
System.out.println ("delta = " + accumulated/iterations + "nanoseconds" );
}
}
</code></pre></div></div>
<p>Following are the results of running this script on different
platforms:<br />
Windows: delta = 1265 nanoseconds<br />
Linux: delta = 1015 nanoseconds</p>
<p>Let me, also, note that Windows machine was a 1.7GHz IBM ThinkPad
laptop, whereas the Linux box is a dual-Xeon server. The results are
quite close, to ignore any hardware and software differences and declare
that:</p>
<p>There are approximately 1-1.3 microseconds in a nanosecond… at least,
in Java ;-)</p>
Enable Debug Menu in Safari
2006-04-26T00:00:00-04:00
http://www.freshblurbs.com/blog/2006/04/26/enable-debug-menu-safari.html
<p>There are several GUI programs allowing different “tricks” on OS X but
one of the tricks - enabling Debug menu in Safari, is too easy to
require an extra mile of installing a GUI application.</p>
<p>Debug menu in Safari delivers a wealth of additional information,
essential for web developers, web designers and other enthusiasts. Using
it you can examine DOM, get web page metrics, change user-agent etc.</p>
<p>To enable Debug menu, open Terminal window and type: \</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> $ defaults write com.apple.Safari IncludeDebugMenu 1
</code></pre></div></div>
<p><br />
Restart Safari <br />
enjoy :)</p>
Web 2.0 In a Nutshell
2006-04-25T00:00:00-04:00
http://www.freshblurbs.com/blog/2006/04/25/web-2-0-nutshell.html
<p>Roman Mittermayr wrote an awesome
<a href="http://mittermayr.wordpress.com/2006/02/03/20-culture/">article</a> about
main trends of Web 2.0 and what makes a website design Web 2.0-ish.</p>
<p>Highly recommended reading.</p>
Duplicate User Account
2006-04-20T00:00:00-04:00
http://www.freshblurbs.com/blog/2006/04/20/duplicate-user-account.html
<p>Say you have a user account on server1 and want to create user on
server2 with the same credentials, but you do not actually know the
password of that user.</p>
<p>on server1, you can see the encoded version of the password with:<br />
> grep username /etc/shadow | awk -F: {‘print $2’}</p>
<p>and then</p>
<p>create user on the destination server (server2).<br />
paste the encrypted password in /etc/shadow, on the destination server.</p>
Where the Hell Is Omaha?
2006-04-03T00:00:00-04:00
http://www.freshblurbs.com/blog/2006/04/03/where-hell-omaha.html
<p>I was just reading <a href="http://www.amazon.com/gp/product/006050742X/102-4543820-3054505?v=glance&n=283155">Valachi
Papers</a>
and one passage was too funny not to share. I hope you will enjoy it as
well :)</p>
<p>The passage starts by describing a Senate hearings of one Valachi, the
first Cosa Nostra insider that gave informatio to FBI, the person who
actually first confirmed that the name of the organized crime
organization was Cosa Nostra, indeed. And then it continues:</p>
<p>“… Nebraska\’s senator Carl Curtis asked Valachi about the state of
organized crime in Omaha. After a moment\’s reflection Valachi
carefully cupped his hand over his mouth, turned to a Justice Department
official sitting next to him and whispered something. Those viewing the
scene could be forgiven for supposing senator Curtis had hit on a matter
of some importance which Valachi wanted to check out before answering.</p>
<p>He was in fact asking, “ <strong>Where the hell is Omaha?</strong>”</p>
<p><img src="/editor/fck/editor/images/smiley/rhymbox-1.0/cool.gif" alt="" /></p>
Great SOA Book
2006-03-25T00:00:00-05:00
http://www.freshblurbs.com/blog/2006/03/25/great-soa-book.html
<p>To be honest, good programming books are very rare. I doubt it would
take more than two digit number to count great ones. If you think about
it, with thousands of books coming out every year (or maybe even month)</p>
<ul>
<li>that is very, very few. The bookshelves are mostly bloated with
wanna-be magicians, promising all kinds of bullshit theories and
frameworks that do nothing, except making existing mess even messier.</li>
</ul>
<p>So, every time I find one of these rare great books - it brings a lot of
joy. It happened again, recently and I wanted to share.</p>
<p>Especially large portion of stupid programming books come on those
dedicated to software architecture and various frameworks,
design practices. SOA and web-services in general are very popular among
such books (great buzz words), of course. Huge majority of them are a
waste of time, both reader\’s and author\’s.</p>
<p>A wonderful exception and a terrific book about SOA; or more generally -
pragmatic, well-thought-through approach to designing enterprise systems
is a book by Dirk Krafzig, Karl Banke and Dirk Slama - <a href="http://www.amazon.com/gp/product/0131465759/sr=8-1/qid=1143317956/ref=pd_bbs_1/104-2116366-2909509?%5Fencoding=UTF8">Enterprize
SOA</a>,
published by Prentice Hall.</p>
<p>I loved the book. I think it makes complete sense. And I think the
authors really know what they are talking about. That\’s a very
pleasant change from all the shallow talk you hear in so many books. The
book ends with real-life case studies, which makes it even more
interesting.</p>
<p>Two thumbs up and very much recommended.</p>
Skype Execs Must Be Crazy
2006-03-23T00:00:00-05:00
http://www.freshblurbs.com/blog/2006/03/23/skype-execs-must-be-retarded.html
<p>Skype is pretty much the only service, I know of that denies
business to its own customers.</p>
<p>What will happen if you buy lots of SkypeOut minutes? You think, what
happens everywhere else - Skype will reward you as a loyal customer,
right? Nope! Don’t even dream about that. <strong>THEY WILL BLOCK YOU</strong>.</p>
<p>The following is Skype’s “justification” of why:</p>
<p>” <em>In order to reduce fraud we restrict the number of times you can use
a specific payment method per month. The reason for this is that the
most common method of fraud is to use a stolen credit card or Paypal
account many times in a short time span. By limiting the number of times
you can use these payment methods per month we can significantly reduce
fraud.</em>”</p>
<p>Rarely heard anything more stupid.</p>
<p>Dude, wake up! Half of world’s business is online, nobody denies
frequent customers!!!</p>
<p>#sigh</p>
Maria Bamford - Funny in a Smart Way.
2006-03-21T00:00:00-05:00
http://www.freshblurbs.com/blog/2006/03/21/maria-bamford-funny-smart-way.html
<p>I\‘ve been real busy lately and have not posted much. It is going to be
like that for a while, so meanwhile why don\‘t you check out <a href="http://phobos.apple.com/WebObjects/MZStore.woa/wa/viewVideo?id=128360168&p=119830874&s=143441">Maria
Bamford on
iTunes</a></p>
<p>She\’s real cool :) One of those rare comedians who manage to be funny
without overdoing the stupid part.</p>
iTerm and Keyboard Config
2006-03-04T00:00:00-05:00
http://www.freshblurbs.com/blog/2006/03/04/iterm-and-keyboard-config.html
<p><a href="http://iterm.sourceforge.net/">iTerm</a> is a nice, open source terminal
utility for Mac OS X which has some additional, useful features (e.g.
Tabs) over the default Terminal program.</p>
<p>However, if you use your terminal to log into Linux boxes over SSH and
then edit files there using “vi” (very typical purpose) - you have to
configure key bindings properly or you will get into a lot of pain. The
thing is - none of the pre-configured bindings work properly with “vi”.</p>
<p>This is what I do:</p>
<ul>
<li>Use “Linux” keyboard configuration as the starting point but edit it
as follows:</li>
<li>Remove all cursor bindings (e.g. num+left cursor etc.)</li>
<li>Remove bindings for “del” and “delete” and substitute them with:</li>
<li>del - bind to Hexadecimal 7f</li>
<li>delete - bind to Hexadecimal 8</li>
</ul>
<p>Enjoy, and spread the word for web 2.0 :)</p>
A Hacker Is Born Every Minute...
2006-02-21T00:00:00-05:00
http://www.freshblurbs.com/blog/2006/02/21/hacker-born-every-minute.html
<p>The banner from the <a href="http://www.rackspace.com/promo/februaryfirewall.php">promotion
campaign</a>
<a href="http://www.rackspace.com">Rackspace</a> runs for its Cisco firewall
service, is kinda neat:</p>
<p><img src="http://www.rackspace.com/html/images/home-promo-februaryfirewall.gif" alt="Hacker Is
Born" /></p>
Showtime Series - Weeds - AWESOME.
2006-02-19T00:00:00-05:00
http://www.freshblurbs.com/blog/2006/02/19/showtime-series-weeds-awesome.html
<p>I am not a big TV fan. Tell you the truth - I do not remember the last
time I turned on my TV. I should. probably, sell it or donate or smth.
but what place better would I put scented candles on? Just kidding :)</p>
<p>Anyway, since iTunes introduced downloadable TV Shows, I have watched
some of them. Good way to take a break and gives you another subject to
talk on at a bar, so you do not look totally geek :)</p>
<p>I mostly download ABC series (Lost etc.). Then I learned that 2005
Golden Globes award was given to Mary-Louise Parker, from Weeds, for the
Best Performance by an Actress in a Television Series- Musical or
Comedy. That got me interested, but I there is still no way I could
watch a series on TV and put up with all that commercials bullcrap. Then
iTunes added Weeds to downloadable series and I started watching it.</p>
<p>I’ve been watching Weeds for a while now, on iTunes. God, it’s awesome!
Don’t let your kids go anywhere near it, if you have kids, but other
than that - this series is AWESOME. The most hillarious, the most
well-done series I have seen for a loooong time. The acting is pretty
damned good, too - quite rare thing in TV series.</p>
<p>Just check it out. If this is your kind of thing - you are gonna love
it. Two bucks per show ain’t that much, honestly.P.S. Almost forgot -
Weeds soundtrack kicks ass.</p>
Opera 9 - Nice!
2006-02-16T00:00:00-05:00
http://www.freshblurbs.com/blog/2006/02/16/opera-9-nice.html
<p>I can hardly believe I am saying this, but <a href="http://snapshot.opera.com/">Opera
9</a> is REALLY NICE.</p>
<p>I\‘ve been playing around with it for several hours, only but I really
like it. The feature set is trully amazing (speech plugin is more than
decent). Surprisingly, I have not encountered any compatibility
problems, so far, either. GMail works like a charm.</p>
<p>Well, done, guys!</p>
<p>P.S. Opera is MUCH more lightweight than Firefox. This means - less
freeze-ups, crashes and less memory eaten up by/wasted on your browser.
Certain pages can open more robustly, faster, too.</p>
Jetty Beats Tomcat's Performance (Quick Non-Scientific Test)
2006-02-12T00:00:00-05:00
http://www.freshblurbs.com/blog/2006/02/12/jetty-beats-tomcats-performance-quick-non-scientific-test.html
<p>I was recently considering a servlet container to embed into a
standalone application. My choice was pretty much between Tomcat and
Jetty.</p>
<p>I like Jetty\’s compact approach. It only takes two jars:
org.mortbay.jetty.jar (664KB) and javax.servlet.jar (138KB) to get
going. In Tomcat\’s case you need much more jars total worth of 3.5MB
in size. I, also, like the simple syntax for configuring and starting a
servelt container from Jetty. Tomcat\’s system is too cumbersome, for
my taste.</p>
<p>On the other hand one can argue that Tomcat is much more supported. Even
JBoss switched to Tomcat, instead of Jetty (I suspect it was more of a
political decision, though).</p>
<p>One more thing on Jetty\’s side is that its 6.x version will handle
sockets NIO way. Even though 6.x is still beta, it\’s still much closer
than Tomcat 5.5 developers of which still refuse to use NIO. They think
they are smarter :)</p>
<p>I like, small, simple and robust solutions so, as you can guess, I was
well in favor of Jetty only if… Only if it can scale and perform at
least as well as Tomcat. Taste is important but making sure application
is fast enough is the most important thing, for me (as it should be for
every programmer).</p>
<p>Anyway, I decided to do a test and see what\’s worth what. I used
latest stable versions of Tomcat ( 5.5.15) and Jetty (5.1.10). Honestly,
my expectation was that Jetty would be slower (because Tomcat is so much
more visible and supported project) but I wanted to know - how much
slower? Significantly?</p>
<p>Let me say a few words about the test I performed. I used a tool
developed by a colleague of mine <a href="http://www.geocities.com/velmurugan_p/index.html">Velmurugan
Periasamy</a>. This tool
opens N sessions to a host using NIO sockets and measures cumulative
download time, as well as the elapsed (user-experienced) download time.
Since the tool is heavily multi-threaded cumulative time is, always,
much longer than the elapsed time, of course. I deployed a very simple
application to both Jetty and Tomcat: a WAR with Hello World index.jsp.
My interest was to compare the two servers in regards with how
efficiently they handle socket connections. I believe that\’s the
measure of servlet container\’s “speed”. Even if very simple (or
primitive), it should give a good feel.</p>
<p>I ran tests against standalone, vanilla installations of Tomcat and
Jetty. Two settings were used: 500 sessions and 5000 sessions. Number of
NIO threads in the tool: 25.</p>
<p>How surprised I was to find out that Jetty, actually, performs MUCH
better!\</p>
<p>500 sessions processed (each test setup ran 5 times and averaged): <br />
Tomcat: <br />
[ HttpClient ]:Cumulative Download Time:85033 <br />
[ HttpClient ]:Total Elapsed Time:2002 <br />
Jetty <br />
[ HttpClient ]:Cumulative Download Time:2717 <br />
[ HttpClient ]:Total Elapsed Time:1095</p>
<p>5,000 sessions processed (each test setup ran 5 times and averaged): <br />
Tomcat: <br />
[ HttpClient ]:Total Download Time:19621497 <br />
[ HttpClient ]:Total Elapsed Time:16933 <br />
Jetty: <br />
[ HttpClient ]:Total Download Time:38980 <br />
[ HttpClient ]:Total Elapsed Time:12232</p>
<p>Of course, it is not a lab-test and you should use your own judgement
(or better - tests) before you “do it yourself home”, but as far as I am
concerned these tests are a good <strong>indication</strong> that Jetty\’s
performance is, at least, as good as that of Tomcat\’s and I choose to
believe - it is even superior.</p>
<p>P.S. I chose Jetty for the my project. Elegancy and performance in one -
unbeatable combination.</p>
Glance At The Future: Multi-Input Touchscreen UI
2006-02-12T00:00:00-05:00
http://www.freshblurbs.com/blog/2006/02/12/glance-future-multi-input-touchscreen-ui.html
<p>WOW. That\’s what I call a user interface, baby :)</p>
<p><a href="http://www.youtube.com/w/Crazy-Multi-Input-Touch-Screen?v=zp-y3ZNaCqs&search=Touch%20Screen%2C%20Awsome%2C%20Multi-input">Watch the
video</a></p>
Why Am I So Tired? Statistics.
2006-02-08T00:00:00-05:00
http://www.freshblurbs.com/blog/2006/02/08/why-am-i-so-tired-statistics.html
<p>A friend of mine shared this statistics with me. I am sure it is, most
probably, an old joke that half of the world knows. Also, I do not know
where it is from originally, so I might violate some intellectual
property rights here, BUT it\’s toooo damned good not to share, so here
it goes:</p>
<p><strong>Why I Am So Tired!!!</strong></p>
<p>For a couple of years I\‘ve been blaming it on lack of sleep, not
enough sunshine, too much pressure from my job, poor blood or anything
else I could think of.</p>
<p>But now I found out the real reason: <br />
I\‘m tired because I\‘m overworked… and here’s why:</p>
<p>The population of this country is 273 million. 140 million are retired,
which leaves 133 million to do the work.</p>
<p>There are 85 million in school, which leaves 48 million to do the
work.</p>
<p>Of this, there are 29 million employed by the federal government, which
leaves 19 million to do the work.</p>
<p>2.8 million are in the armed forces, which leaves 16.2 million to do the
work.</p>
<p>Take from that total the 14,800,000 people who work for state and city
governments and that leaves 1.4 million to do the work.</p>
<p>At any given time there are 188,000 people in hospitals, which leaves
1,212,000 to do the work.</p>
<p>As of today, there are 1,211,998 people in prisons. <br />
That leaves JUST TWO PEOPLE to do the work…</p>
<p>YOU and ME!!</p>
<p><strong>And there you are sitting there, at your computer, reading jokes.
Nice, real nice…</strong></p>
<p> </p>
IntelliJ Rocks on iMac Core Duo
2006-01-30T00:00:00-05:00
http://www.freshblurbs.com/blog/2006/01/30/intellij-rocks-imac-core-duo.html
<p>One of the major reasons I got <a href="http://www.apple.com/imac/">iMac Core
Duo</a> was the <a href="http://en.wikipedia.org/wiki/Dissociative_identity_disorder">Split
Personality</a>
I was starting to develop having to chose between my most favorite
“toys”: PowerBook G4 and IntelliJ IDEA. While Mac is the only worthwhile
computer, to me, and I really enjoy the mobility of a PowerBook, I have
recently gotten addicted to IntelliJ\’s awesome Java IDE and can not
imagine developing anything in Java without it.</p>
<p>The catch is - IntelliJ IDEA does not really work on a PowerBook G4. Let
me be more specific: it is so slow, it is useless for any practical use.
Now, whoever\’s fault it is - that\’s the fact and it was really
poisoning my PowerBook experience.</p>
<p>Since I am a Java hacker, most of the time, you get an idea how serious
my clinical condition was getting.</p>
<p>Long story told short - I have been using IntelliJ on my new iMac Core
Duo, for a while now, and I am <strong>delighted.</strong> Works flawlessly and gives
an absolute best experience for Java development. And, oh, yeah - I
think I have less of Split Personality, now :)</p>
<p>P.S. I would just suggest that you be careful with what plugins you
install. There is some plugin that screws up IntelliJ on Mac. It
happened several times to me and I had to wipe out (including
preferences and application support stuff) IntelliJ to get it work,
again. I was not able to hunt this plugin down. I had a whole bunch just
installed, each time it happened. Just be careful. It\’s one of the
cool plugins, apparently since I was tempted to install it, not once but
several times. Yet, it is not one of the crucial ones, since I am very
happy with the bunch I have right now (JBoss, SVN, CVS, Groovy plugins
are all fine).</p>
iWeb - Demoing More Amazing Features.
2006-01-22T00:00:00-05:00
http://www.freshblurbs.com/blog/2006/01/22/iweb-demoing-more-amazing-features.html
<p>Here is a second page created entirely in iWeb: \</p>
<p><a href="http://web.mac.com/inadarei/iWeb/Site/Playing%20More.html">http://web.mac.com/inadarei/iWeb/Site/Playing%20More.html</a></p>
<p>I did not use ANYTHING except iWeb. Just three average photos. All photo
processing (color, reflection, border, size, shape, orientation etc) was
done in iWeb. Also, pay attention that the collage is actually three
images and iWeb <strong>did not</strong> merge them into one but preserved as three
images.</p>
<p>Dude! Forget about Intel-powered Macs. iWeb is a far more important news
:) It is a revolution in web design.</p>
<p>WoW</p>
Woohoo Intel Macs Come With JDK 5!!!
2006-01-21T00:00:00-05:00
http://www.freshblurbs.com/blog/2006/01/21/woohoo-intel-macs-come-jdk-5.html
<p>Despite what Apple Developer Network says, my Intel iMac Curo Duo does
have JDK5! Such a relief!!!</p>
<p>It came with JDK 1.4 default installation and I tried finding JDK 5
download, in vain. Just to check Apple Developer Connection site and
find this scary message: “Java 2 Platform Standard Edition (J2SE) 5.0
Release 4 is based on JDK 1.5.0_06 and improves functionality of J2SE
5.0 on PowerPC-based Mac OS X Tiger systems. This release is not
compatible with Intel-based Macintosh computers.”</p>
<p>Not quite troo. A quick look in the usual place and voila - there is JDK
5 pre-installed! Just need to move the symbolic link.</p>
<p>This is the same as you needed in PPC Macs: <br />
Go to /System/Library/Frameworks/JavaVM.framework/Versions <br />
rm CurrentJDK <br />
ln -s 1.5 CurrentJDK</p>
<p>And there we go: <br />
# java -version <br />
java version “1.5.0_05” <br />
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_05-84) <br />
Java HotSpot(TM) Client VM (build 1.5.0_05-51, mixed mode)</p>
<p>Wohooooo!</p>
iWeb - Forget about HTML Editing, Start Site Authoring
2006-01-21T00:00:00-05:00
http://www.freshblurbs.com/blog/2006/01/21/iweb-forget-about-html-editing-start-site-authoring.html
<p>iWeb did look cool at Steve\’s keynote, but I could never expect what
it turned out to be - a true Site Authoring. Forget about worrying how
to properly layout. Just drag and drop (much like in Keynote, or
something like in Powerpoint, just much better) and iWeb will figure how
to transform all that visual complexity to the simplicity of HTML.</p>
<p>HTML is layouted using divs and CSS, of course - a la Web 2.0.</p>
<p>Here is my quick attempt, for your tasting: \</p>
<p><a href="http://web.mac.com/inadarei/iWeb/Site/Welcome.html">http://web.mac.com/inadarei/iWeb/Site/Welcome.html</a></p>
<p>iWeb is truly amazing. I would never believe creating such an editor was
possible, given the limitations of HTML.</p>
<p>Apple keeps surprising. Oh my!</p>
Java Server Faces Must and Will Die
2006-01-20T00:00:00-05:00
http://www.freshblurbs.com/blog/2006/01/20/java-server-faces-must-and-will-die.html
<p>In his latest Blog/Podcast <a href="http://timshadel.com/blog/2006/01/19/jsf-the-7-layer-burrito-i-wont-eat-again/">Tim
Shadel</a>
shares his team\’s negative experience with JSF. I must admit, I NEVER
liked Java ServerFaces. And not only for the reasons mentioned by Tim.
Many complaints from Tim may be relevant to Tapestry as well. Yet, I
like Tapestry. I think it is a niche framework but I have used it on
some projects and do not regret. These projects were intranet, web-based
applications, though. I don\‘t think I would use Tapestry for web. I
would not use Java ServerFaces at all, though.</p>
<p>Here are my two cents why I hate Java ServerFaces:</p>
<p>“Rocket Scientists” who forget about simplicity and tend to build overly
“generalized” (bloated is a better word) theoretical models are doomed
for failure.</p>
<p>JSF would have <strong>never</strong> made it, if big vendors did not support it so
much. Sun went religious about JSF without any real, objective reason
to support specification that nobody ever tried in real life. Usual
problem of JSR: coming up with spec before the implementations (Oh,
God!). This zealous support will help for a while. But, in the long
run JSF <strong>has</strong> to fail and get replaced by something much
simpler/elegant, in Java. Or else - serverside Java will fail with it
and everybody will begin using RoR or whatever other crap will be out
there at that time. Sad. I really do not like Ruby, as a language (no, I
am not static typing fan, I love Python) and I think RoR is not that
good, at all. I will miss a vast wealth of open-source Java libraries
and frameworks, too.</p>
<p>So, repeat with me and memoiaze, before it is too late - <strong>Simplicity is
the key!</strong></p>
<p>Rickard Oberg (I think) once said that the value of a framework is not
in what it allows but what it does not allow to do.</p>
<p>I think RubyOnRails proved that point very well. And I think, contrary
to what Tim Shadel says in his Podcast (even though he has many valid
points) the main problem of JSF is not what it does not allow but how
much it allows and how bloated it has become because of it.</p>
<p> </p>
iMac Intel CoreDuo ROCKS!
2006-01-20T00:00:00-05:00
http://www.freshblurbs.com/blog/2006/01/20/imac-intel-coreduo-rocks.html
<p>My first post from the new Intel CoreDuo iMac 20”.One word - AWESOME!</p>
GM Cars Using Bio Fuel
2006-01-19T00:00:00-05:00
http://www.freshblurbs.com/blog/2006/01/19/gm-cars-using-bio-fuel.html
<p>Renewable, bio fuel is not a new idea. It has been in development for
long. What is new - is seeing it in mass production. GM <a href="http://www.gm.com/company/onlygm/fuel_flexible.html#">has
announced</a> the new
line of E85-based cars.</p>
<p>Important thing is that, it seems, this type of fuel has some muscle.
Pay attention that GM cars are large SUVs, not like the tiny electric
hybrid crap Toyota produces :)</p>
<p>It really looks like a breakthrough. <strong>Very excited</strong>.</p>
Jakarta FeedParser Correct SVN URL
2006-01-18T00:00:00-05:00
http://www.freshblurbs.com/blog/2006/01/18/jakarta-feedparser-correct-svn-url.html
<p>I do not know what is the problem of Jakarta Feedparser. They have
not had a binary download for a very long time and SVN URI on the site
is wrong. Neverthless, it is an awesome tool. I just wish I did not have
a headache of finding its proper SVN address each and every time I need
to compile it. <br />
<br />
Posting it here (until the next time they change it) to find easier,
next time I need it, and to share with others that might need it:</p>
<p><a href="http://svn.apache.org/repos/asf/jakarta/commons/dormant/feedparser/trunk">http://svn.apache.org/repos/asf/jakarta/commons/dormant/feedparser/trunk</a></p>
How to Tell Marketing Person From an Engineer
2006-01-10T00:00:00-05:00
http://www.freshblurbs.com/blog/2006/01/10/how-tell-marketing-person-engineer.html
<p><a href="http://www.sellsbrothers.com/fun/#Best_Exam_Answer_Ever">How do you tell a marketing person from an
engineer?</a></p>
<p><img src="http://www.sellsbrothers.com/fun/exam.gif" alt="" /></p>
<p>This is very nice and IMHO the professor was an asshole for giving no
credit :) After all, it\’s his fault that he could not formulate
question without ambiguity.</p>
Mobuzz TV
2006-01-09T00:00:00-05:00
http://www.freshblurbs.com/blog/2006/01/09/mobuzz-tv.html
<p>I have long been bitching about how slow TVs are adopting Internet. Just
scarce teasers really does not fly. And, voila, here is a Net-based TV
station: <a href="http://www.mobuzz.com">Mobuzz</a> . Honestly, it\’s more like a
video podcast, right now, but I like the fact, per se. I really want,
ideally, all TVs to move to broadcasting on the Net as their
<strong>primarily</strong>medium of delivery. It just makes sense. And to think about
what TV stations could do with your
<a href="http://www.personomies.com">personomies</a>, if they were broadcasting
online is incredible.</p>
<p>As for Mobuzz. It\’s kinda fun, nothing too serious. The anchor is
quite hot <img src="/editor/fck/editor/images/smiley/rhymbox-1.0/cool.gif" alt="" />
and cute. That\’s good. Her voice cracks periodically, though. Or
she\’s having a permanent cold with caughing
<img src="/editor/fck/editor/images/smiley/rhymbox-1.0/shocked.gif" alt="" /> She might
want to work on that a little bit.</p>
<p>All in all - fun and nice. Cheers to Mobuzz</p>
Personomies - Next Big Thing on the Web
2006-01-05T00:00:00-05:00
http://www.freshblurbs.com/blog/2006/01/05/personomies-next-big-thing-web.html
<p><a href="http://personomies.com/">Pierre Wielezynski</a> coined the term
<a href="http://personomies.com/what-are-personomies/">Personomies</a> and
<a href="http://personomies.com/what-are-personomies/">explains</a> what it means.
I am a strong believer in <a href="http://en.wikipedia.org/wiki/Social_Web">Social
Web</a> and the personomies are,
probably, were it all starts.</p>
<p>There are, already, many useful services (
<a href="http://www.bloglines.com/">Bloglines</a> and
<a href="http://del.icio.us/">del.icio.us</a> come to mind, immidiately) that touch
different sides of a personomy. Yet, we are still to see what a
full-fledged personomy looks like.</p>
<p>Exciting times it is, indeed, on the web.</p>
Windows Live - Bwahahaha
2006-01-03T00:00:00-05:00
http://www.freshblurbs.com/blog/2006/01/03/windows-live-bwahahaha.html
<p>See something familiar? <br />
<a href="http://www.live.com/">http://www.live.com/</a> and
<a href="http://local.live.com/">http://local.live.com/</a></p>
<p>If they wanted to copy Google, they should have used Google APIs. At
least, it would be more compatible.
<img src="/editor/fck/editor/images/smiley/rhymbox-1.0/lick.gif" alt="" /> <br />
<br />
LOLz, Microsoft never changes, does it?</p>
Logitech diNovo
2005-12-29T00:00:00-05:00
http://www.freshblurbs.com/blog/2005/12/29/logitech-dinovo.html
<p>If you are as picky with keyboards as I am, then there is something you
may like and the name of it is <a href="http://www.logitech.com/index.cfm?countryid=19&languageid=1&page=products/details&CRID=486&CONTENTID=7321">Logitech diNovo Media
Keyboard</a>.
Now, it\’s not just the awesomely cool numeric pad (with termomether,
clock and Smart Calculator mode) or the innovative design or the
insanely cool look.</p>
<p>You see, I am (and you should be, too) very picky about how a keyboard
feels. I guess I was spoiled by the high quality of Apple keyboards. I
really need that the keys be soft, stable and comfortable. Quite
honestly very few keyboards meet these criterias. Most of the keyboards
are clamsy and cheap (not by price, by quality). diNovo is a lucky
exception. It feels great, it drives great.</p>
<p>Two thumbs up. Great job, Logitech! Highly recommended. A must have.</p>
A Great CSS Book - Zen of CSS Design
2005-12-29T00:00:00-05:00
http://www.freshblurbs.com/blog/2005/12/29/great-css-book-zen-css-design.html
<p>Now, I am not a designer, not even a web designer but I am a web
developer. Therefore, I can not ignore the CSS revolution. It is,
definitely, no breaking news that designing with HTML tables and 1 pixel
“clear” gifs is a thing of far past. Alas, too many websites still hold
to bad old way. I decided not to be one of those old-timers about a year
ago and that\’s when my search for enlightement began.</p>
<p>Now, it was not an easy path. First, as I mentioned, I am not a designer
so it was not high on my priority list, second - I had real hard time
finding a good book that would make the learning curve less steep. I
think I tried all the CSS books available. Most of them ended up beeing
language references of some kind. None of them too useful. There was
more on the Net than in these books. Not much on the net, either,
though. At least - not easily available.</p>
<p>And then, today, while looking for something entirely different at
Borders, I ran into <a href="http://www.amazon.com/gp/product/0321303474/qid=1135900965/sr=8-1/ref=pd_bbs_1/102-7728781-3772928?n=507846&s=books&v=glance">Zen of CSS
Design</a>
book. I loved it. Well structured, well written, written by a person who
clearly knows what he is talking about. The information is very concise
and to the point. And, last but not least - the book quality is awesome.</p>
<p>If you want to learn more about semantic, CSS-based page design, you
should check this book out.</p>
<p>Two thumbs up.</p>
The Worst Manning Book - Ajax in Action
2005-12-28T00:00:00-05:00
http://www.freshblurbs.com/blog/2005/12/28/worst-manning-book-ajax-action.html
<p>I have purchased <a href="http://manning.com/books/crane">Ajax In Action</a> from
Manning a while ago and tried to read it, several times. In vain. And
not due to the lack of interest, I must say. A brief look was very
disappointing and I could not make myself to spend precious time on it.</p>
<p>Anyway, I finally managed to get to it. After all, bad or worse, I could
not ignore it, or so I thought.</p>
<p><strong>For the love of God and yourself - do not waste your money and time on
this piece of crap!</strong></p>
<p><strong>God!</strong>I have never seen worse book from Manning. Absolutely useless,
terirble writing, stupid narratives and huge. Costs a lot, too. I would
give it away but I can not remember anybody who I hate so much to give
this horror to.</p>
<p>Very dissappointed.</p>
Dynamically Build Classpath on Unix
2005-12-28T00:00:00-05:00
http://www.freshblurbs.com/blog/2005/12/28/dynamically-build-classpath-unix.html
<p>Useful code snippet for your start.sh scripts:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> for f in `ls $BASE_DIR/lib/*.jar`doCLASSPATH=$CLASSPATH:$fdoneexport $CLASSPATH
</code></pre></div></div>
Funniest Thing Ever
2005-12-27T00:00:00-05:00
http://www.freshblurbs.com/blog/2005/12/27/funniest-thing-ever.html
<p>…is when somebody does something so f..in mean, you want to cut his
(or her) throat right there, right then but instead you smile warmly and
say through your teeth “thank you. I really appreciate you doing this”
………… and they actually believe it!!!</p>
<p>There is no limit to human stupidity, indeed.</p>
What are IPs Reserved For Local Usage?
2005-12-21T00:00:00-05:00
http://www.freshblurbs.com/blog/2005/12/21/what-are-ips-reserved-local-usage.html
<p>Everybody knows about 192.168.* but it is not the only one. Actually,
there is an RFC: <a href="http://www.faqs.org/rfcs/rfc1918.html">#1918</a> that
controls this, and the winning “combinations” are:</p>
<p> 10.0.0.0 - 10.255.255.255 (10/8 prefix) <br />
172.16.0.0 - 172.31.255.255 (172.16/12 prefix) <br />
192.168.0.0 - 192.168.255.255 (192.168/16 prefix) \</p>
Who Called My Method?
2005-12-20T00:00:00-05:00
http://www.freshblurbs.com/blog/2005/12/20/who-called-my-method.html
<p>Sometimes you really want to track which other methods are
calling/invoking a particular method, at runtime. There is a quick and
dirty way of doing it that I find pretty nifty and decided to share, in
case you are not already familiar with it. In this method, you can track
the caller by analyzing the stack trace.</p>
<p>Let’s look at an example. Today I wanted to track who is opening
connections to a database in a particular scenario/flow. I created a
“proxy” class, intentionally named DriverManager (but not
java.sql.DriverManager by my.package.DriverManager) to obscure the
“REAL” one and do some monitoring.</p>
<p>Here is the class, and I hope the code is self-explanatory:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>public class DriverManager {
public static Connection getConnection( String uri ) {
try {
throw new Exception("GettingStackTrace");
} catch ( Exception ex ) {
StackTraceElement[] elements = ex.getStackTrace();
StackTraceElement element = null;
element = elements[1];
System.out.println ( "Connection requested from method:"
+ element.getClassName() +
"." + element.getMethodName() );
}
Connection con = null;
try {
con = java.sql.DriverManager.getConnection(uri);
} catch (SQLException e) {
e.printStackTrace();
}
return con;
}
}
</code></pre></div></div>
Fixing MySQL Error #1251 - Client does not support authentication protocol.
2005-12-18T00:00:00-05:00
http://www.freshblurbs.com/blog/2005/12/18/fixing-mysql-error-1251-client-does-not-support-authentication-protocol.html
<p>I ran into this problem more than enough times, during the last year and
I am tired remembering the solution, each and every time. So, I am going
to post it here, for my own sake and for the sake of those who may find
it here and bless me for being so kind (heh).</p>
<p>Anyway, here it is:</p>
<p>MySQL has changed password hashing mechanism starting from version 4.1
and if you are trying to use any “older client” (including PHP 4 or the
pre-last MySQL driver) you will get an error of the type: <strong>#1251:
Client does not support authentication protocol requested by server;
consider upgrading MySQL client.</strong></p>
<p>You thought you were screwed, did not you? :) Not entirely. Those folks
@ MySQL are definitely nuts, for changing password hashing, but they are
not THAT crazy, after all. They did leave a way out and here it is.</p>
<p>When you add a user, in MySQL 4.11 and newer, with a command like: <br />
GRANT ALL PRIVILEGES ON dbname.* TO
<a href="mailto:user@localhost">user@localhost</a> IDENTIFIED BY
\‘secretPassword\’;</p>
<p>It will create password entry with new hashing and your “old” client
will not be able to authenticate. But, if you run a command like the
following afterwards: <br />
<strong>set password for</strong>
<a href="mailto:\'user\'@\'localhost\'"><strong>\‘user\’@\‘localhost\‘</strong></a> <strong>=
OLD_PASSWORD(\‘secretPassword\’);</strong></p>
<p>it will update the appropriate entry with the old hashing and everything
will just work, even with your poor, old, “stupid” client.</p>
<p>enjoy</p>
This Is Why People Think Java Is Cumbersome
2005-12-12T00:00:00-05:00
http://www.freshblurbs.com/blog/2005/12/12/why-people-think-java-cumbersome.html
<p>Please, take a look at
<a href="http://jakarta.apache.org/commons/dbcp/apidocs/org/apache/commons/dbcp/package-summary.html#package_description">this</a>
and then
<a href="http://discuss.joelonsoftware.com/default.asp?joel.3.219431">this</a>. <br />
How many similiarities were you able to find?</p>
<p>It\’s such a shame! Especially, coming from a prominent Jakarta
project. At least, they could have written a decent tutorial, instead of
this abracadabra bullshit.</p>
<p>So much for the “general-purpose tool-building factory factory factory “
<br />
<br />
/me *SIGHS*</p>
Setting Up Subversion in 5 minutes
2005-12-11T00:00:00-05:00
http://www.freshblurbs.com/blog/2005/12/11/setting-subversion-5-minutes.html
<p>There are several books about
<a href="http://tigris.subversion.org">Subversion</a>, some small some huge. Yet,
none of them gives a 5 minute get-going guide. Most of the developers
are seasoned CVS users, so we do not really need a tirade about version
control - just get us going!</p>
<p>And (I can hardly stress this enough) we\‘d really like Subversion to
authenticate over SSH. Leave that “pasword db” (in essence - open text
file) or Apache Module bullcrap, to somebody else. Neither do we need
the WebDav for version control - thank you very much, but no.</p>
<p>The last time I set up a SVN repository (accidentally - my first time,
too) it took me looking through 4 different books and a week\’s work on
and off. Today I needed to do it, again and I found out that I did not
remember much of the last experience. Well, it did not take me a week,
but still more than I would want to spend on it. Anyway, to save myself
time, in the future and in hopes of this being useful for folks who
don\‘t want to read 4 books, here is how it is done, on Unix (Windows
can get lost, as far as I care):</p>
<p>1) Get the source or a binary from
<a href="http://subversion.tigris.org">http://subversion.tigris.org</a></p>
<p>2) If you got a binary - you know what to do. If you have a source tar,
either read the INSTALL doc that came with it or just do the usual <br />
<strong>”./configure”, “make”, “make install”</strong> <br />
that\’s what I did - I was too lazy to read and it worked, so - it may
work for you, too.</p>
<p>3) Check that it installed by running: <br />
svn –version (client) <br />
and <br />
svnadmin –version (admin)</p>
<p>4) Create a repository by typing: <br />
<strong>svnadmin create /home/svn</strong> <br />
(the path of your repository will be /home/svn)</p>
<p>5) Let\’s import a module, now: <br />
go to the source tree of whatever you want imported and type: <br />
<strong>svn import -m “Importing my module” . file:///home/svn/mymodule</strong></p>
<p>the dot after the comment is what you are importing (current folder, in
this case) <br />
and the next parameter is the svn URL of where to import your module.</p>
<p>6) Go to <strong>/home/svn/conf/svnserve.conf</strong>, enable (remove comment) the
General section and under it set: <br />
<strong>anon-access = none</strong> unless you want your repositories to be viewable
(not editable) by anonymous users.</p>
<p>7) Grant read/write rights to the developer team: <br />
Put your developer accounts under some group with a command like: <br />
usermod -G devgroup steve</p>
<p>and then issue a self-explanatory series of commands: <br />
<strong>chgrp -R devgroup /home/svn <br />
chmod -R 770 /home/svn <br />
chmod g+s /home/svn/db (or g+t for BSD)</strong></p>
<p>after that any unix user that is in the group devgroup, on the server, <br />
can checkout the code by: <br />
<strong>svn co svn+ssh://steve@antiadmin.com/home/svn/mymodule</strong></p>
<p>That\’s it. If this short guide is not clear enough for you, feel free
to read 4 or 5 books about Sunversion. I\‘d recommend to start with the
<a href="http://www.amazon.com/gp/product/0974514063/qid=1134274515/sr=8-1/ref=pd_bbs_1/104-2661173-6441545?n=507846&s=books&v=glance">Pragmatic Version Control with
Subversion</a>,
from the Agile guys. It\’s the shortest and makes more sense than the
other, larget books. Maybe you will need just one book, if you start
with this one.</p>
<p>cheers.</p>
<p>P.S. The free book on the Tigris site is a piece of crap. Don\‘t waste
your time. It\’s a classic case of “you get what you pay for”. Sorry -
just being honest.</p>
Logical, Yet Miserable
2005-12-10T00:00:00-05:00
http://www.freshblurbs.com/blog/2005/12/10/logical-yet-miserable.html
<p>If you think about it, it is pretty pathetic that as people get
increasingly estranged to each-other, in the real life, they show more
interest in Social Web (or whatever other fancy name the “celebrity”
jerk bloggers come up with to satisfy their unhealthy egos.)</p>
<p>Logical, yet very pathetic and sad.</p>
TV Shows Online - TiVo Gone?
2005-12-07T00:00:00-05:00
http://www.freshblurbs.com/blog/2005/12/07/tv-shows-online-tivo-gone.html
<p>iTunes Store launched TV Shows service several months ago. Initially it
was just four shows but today the number drastically increased. It seems
like it is becoming real thing, which is very exciting. TV has to go
online. It’s a shame how much behind TV industry is compared to
everything else.</p>
Web 2.0 Inspiring Music Industry?
2005-12-06T00:00:00-05:00
http://www.freshblurbs.com/blog/2005/12/06/web-2-0-inspiring-music-industry.html
<p>Have you seen the <a href="http://www.allamericanrejects.com/media_videos.asp">Dirty Little
Secret</a> video from
<a href="http://www.allamericanrejects.com/home.asp">The All-American Rejects</a>
band? I can\‘t help thinking that it may well be greatly inspired by
the <a href="http://confess.ning.com">Ning Confess</a></p>
Metaphors - Next Generation Programming Language?
2005-12-02T00:00:00-05:00
http://www.freshblurbs.com/blog/2005/12/02/metaphors-next-generation-programming-language.html
<p>Sun features an <a href="http://java.sun.com/developer/technicalArticles/Interviews/livschitz2_qa.html">interview with Victoria
Livschitz</a>
about the next-generation language: Metaphors.</p>
<p>To tell you the truth, IMHO, it is not going to make it. I am not an
expert of architecting new programming languages, but it looks to me as
just another artificially born, intellectually struggled, idea. It does
not feel natural. Maybe it\’s just me.</p>
<p>Anyway, I am going to give Victoria this much, if this new language ever
makes to mainstream, at least she is much cuter than our much respected
James Gosling :)</p>
Apache.org Is Down
2005-11-28T00:00:00-05:00
http://www.freshblurbs.com/blog/2005/11/28/apache-org-down.html
<p>Surprisingly enough apache.org is dead. I would not be surprised, in the
least, if it was Sourceforge, because that dude is dead more often than
alive, but this is the first time I witnessed the same with Apache, and
it sucks.</p>
<p>I am sitting here waiting for the site to come up and thinking how some
sites have become integral parts of our lives and yet we do not realize
how much we depand on them… until they die. Then we start whining and
posting on blogs…</p>
<p>*Sigh*</p>
<p>P.S. Is somebody over there even working on this? Takes a while.</p>
The Beauty of Precision
2005-11-25T00:00:00-05:00
http://www.freshblurbs.com/blog/2005/11/25/beauty-precision.html
<p>Check out Ronaldinho
<a href="http://agylen.com.nyud.net:8090/wp-content/nikefootball_ronaldinho_high.mov">video</a> and
pay attention to what he is doing with the goal :) Four times in a row.</p>
<p>Ronaldinho rocks :)</p>
To Use or Not To Use "Select * From"
2005-11-23T00:00:00-05:00
http://www.freshblurbs.com/blog/2005/11/23/use-or-not-use-quot-select-quot.html
<p>Pizza_milkshake, a PHP/MySQL celebrity from the IRC (where lots of LAMP
dudes reside) <a href="http://www.parseerror.com/sql/select*isevil.html">has
posted</a> an article
about this subject. This view seems to be growing in popularity since I
noticed it referred to several times during my today\’s visit @ MySQL
on Freenode.</p>
<p>Even though it has some valid points, I do not necessarily agree to this
oppinion and I definitely do not agree to the assertive tone of the
paper. Being spoiled with ORM tools à la Hibernate, I kinda smell that
there is more to this discussion than what is covered in the mentioned
paper.</p>
<p>Among other things, there are two things that matter in software
engineering style: resulting performance and productivity. Yes, you
always want your code to be the fastest, most efficient, yadda, yadda,
yadda, but you also want your program to be flexible, easy to maintain
and you do want to write it as fast as possible and get to more
important things in this life :-)</p>
<p>Anyway, to achieve all these good stuff, shorter the code - the better,
less code duplication - even better. I am not just whining about the
length of explicitely enumerated list of fields. That\’s a lesser
problem. Bigger problem is that you will be using these field names
somewhere later. So something is used in several places. See the threat?
You change in one place, forget to change in another - oops! On the
other side, you could have used a star in one, pretty critical, place
and there you go - one less place to worry about.</p>
<p>In addition, remembering that PHP is a dynamic language, one place may
be all you need. If you can think it through well, you can write your
data objects so that they have the same properties as whatever the table
has in the DB and then other objects dynamically find-out about these
properties via some mechanism à la Java Reflection (but for PHP) and you
end-up with a situation that for a significant number of your objects,
the only place you need to define field names - is in the database. Need
to add one more field, or remove? Do it in the database and never worry
about possible code incosistency.</p>
<p>How is that? Would you use * if it delivered so much
productivity/maintainability boost? You should.</p>
<p>I am not saying that all objects should be mapped to a DB like that and
completely loaded each time (pizza_milkshake had a valid point that
sometimes you do not want to populate recordset with all fields from a
table) but there are times when you do want and when it helps. So, it is
as much wrong to declare * as evil, as to have a habbit of using it all
the time :)</p>
<p>cheers.</p>
Listen To Your Employees - They Are Valuable!
2005-11-22T00:00:00-05:00
http://www.freshblurbs.com/blog/2005/11/22/listen-your-employees-they-are-valuable.html
<blockquote>
<p>“If you leave us our money, our buildings and our brands, but take away
our people, the Company will fail. But if you take away our money, our
buildings, and our brands, but leave us our people, we can rebuild the
whole thing in a decade.”
</p>
</blockquote>
<p>– Richard R. Deupree, Former CEO of Procter & Gamble, 1947</p>
What Do They Teach in Business Schools?
2005-11-17T00:00:00-05:00
http://www.freshblurbs.com/blog/2005/11/17/what-do-they-teach-business-schools.html
<p>Aside from the piece of paper and beer-buddies-network, what do B
schools give as the return on investment? IMHO, there is no way a B
school (any!) can teach a person how to be a good businessman. Just like
an art school can teach you something but can never teach you how to be
true artist. So, considering there are many other places (less
expensive, too) where you can build that “network”, what does B school
give you?</p>
<p>Probably, knowledge of common “language” as in - set of terms and
notions? People who did MBA understand each-other’s language. Not that
it’s going to help them in any way if they do business in a non-American
culture (e.g. Saudi Arabia), but, in some common circumstances (western
civilization) - it may.</p>
<p>Boils down to the same oooold thing - communication is the key :-)</p>
Huh? 8 Core Ready for Prime Time?
2005-11-17T00:00:00-05:00
http://www.freshblurbs.com/blog/2005/11/17/huh-8-core-ready-prime-time.html
<p>Jonathan Shwartz of Sun
<a href="http://blogs.sun.com/roller/page/jonathan?entry=a_five_year_lead">claims</a>
that Sun\’s Niagara project will be available Q1, 2006:</p>
<p>“Real soon now (we\‘ve said January, but there is that holiday rush to
think about), we\‘ll be introducing our new Niagara-based product line.
As I <a href="http://blogs.sun.com/roller/page/jonathan/20040910">discussed a while
back</a>, Niagara is
our internal code name for a radical shift in computing, and a redesign
of SPARC. Niagara systems take the concept of dual core processors (with
which most of you are familiar), and goes to an absolute extreme -
building 8 cores, each capable of running 4 jobs simultaneously (4
threads), onto a single chip. Doing the math, we\‘ll be delivering a
32-way chip, running 9.6GHz, which sips power (about 70 watts). On
performance-per-watt metrics, we believe we\‘ll be a factor of 5 better
than what IBM just announced. A factor of 5.”</p>
<p>And according to him, it is built for plain, old Solaris, so (we can
assume) - no worries to run Java apps on it flawlessly.</p>
<p>Very interesting… Let\’s see, January is not too far away :)</p>
Google - Content Authoring
2005-11-17T00:00:00-05:00
http://www.freshblurbs.com/blog/2005/11/17/google-content-authoring.html
<p>It seems, after doing most things possible with content, Google is
begining to enter content authoring market, too, with the new
initiative: <a href="http://base.google.com/base/default">Google Base</a>.</p>
<p>These guys really don\‘t waste their time :)</p>
Good Enough Ain't Good
2005-11-17T00:00:00-05:00
http://www.freshblurbs.com/blog/2005/11/17/good-enough-aint-good.html
<p>Watch Sun\’s <a href="http://mediacast.sun.com/share/jrush/goodisgood.rm">video
parody</a> on Dell
servers :)</p>
Advantages of Custom-Built, Open Source Enterprise Portals
2005-11-16T00:00:00-05:00
http://www.freshblurbs.com/blog/2005/11/16/advantages-custom-built-open-source-enterprise-portals.html
<p><a href="http://www.geercom.com/">David Geer</a> published an
<a href="http://www.geercom.com/eosj.html">article</a> in the <a href="http://eosj.com/">Enterprise
Open-Source Journal</a> titled <em><a href="http://www.geercom.com/eosj.html">Advantages of
Custom-Built, Open Source Enterprise
Portals</a>.</em>I think it is an interesting
article, but you can not trust me since part of it is based on David’s
interview with me. So, don’t trust me and read it :)</p>
<p>EOSJ has some odd publishing format (IMHO) so you may be better off
checking out the <a href="http://www.geercom.com/eosj.html">html version of the article
online</a>. All the rights to the article
belong to respective parties.</p>
<p>enjoy.</p>
TechCrunch
2005-11-14T00:00:00-05:00
http://www.freshblurbs.com/blog/2005/11/14/techcrunch.html
<p>I became a <a href="http://techcrunch.com/">techcrunch.com</a> addict!</p>
Add Google "Counter" to Your Site
2005-11-14T00:00:00-05:00
http://www.freshblurbs.com/blog/2005/11/14/add-google-quot-counter-quot-your-site.html
<p>No explanation needed:
<a href="http://www.google.com/analytics/">http://www.google.com/analytics/</a></p>
You never know...
2005-11-13T00:00:00-05:00
http://www.freshblurbs.com/blog/2005/11/13/you-never-know.html
<p>Following is a joke I heard today. No doubt it’s a variation on a very
old theme, but still quite funny, IMHO:\r <br />
\r <br />
A taxi driver picks up a nun and can’t stop staring at her. “I must
tell you something, Sister, but I am afraid to offend you,” he says. \r
<br />
\r <br />
“Go on, my dear son, you can’t offend me,” the nun replies. “I’ve seen
and heard a lot in this life.” \r <br />
\r <br />
“I’ve always fantasized about french-kissing a nun,” the cabbie
admitted. \r <br />
\r <br />
“Well, you have to be single,” the passenger replied, “and Catholic.”
\r <br />
\r <br />
Excited, the guy behind the wheel howled, “Yes, Sister, I’m single, and
I’m Catholic too!” \r <br />
\r <br />
“Okay, then,” the nun murmured. “Pull into the next alley!” \r <br />
\r <br />
The cabbie complied, and the nun slipped him her tongue. But while
pulling out of the alley, he started crying. “You got your kiss,” the
nun remarked. “What could be wrong?” \r <br />
\r <br />
“Forgive me, Sister, for I have sinned,” the taxi driver confessed. “I
lied. I’m married, and I’m Jewish.” \r <br />
\r <br />
“That’s okay,” chuckled the person in the backseat. “My name is Kevin,
and I’m on my way to a Halloween party.”</p>
Farewell to Peter Drucker
2005-11-13T00:00:00-05:00
http://www.freshblurbs.com/blog/2005/11/13/farewell-peter-drucker.html
<p>Peter Drucker, widely considered the father of modern management theory
died at the age of 95 on Nov 11th. Here is link about his life and work.
<br />
\</p>
<p><a href="http://en.wikipedia.org/wiki/Peter_Drucker">http://en.wikipedia.org/wiki/Peter_Drucker</a>
<br />
<br />
Rest in peace. \</p>
Amazon Mechanical Turk - Web 2.0?
2005-11-09T00:00:00-05:00
http://www.freshblurbs.com/blog/2005/11/09/amazon-mechanical-turk-web-2-0.html
<p><a href="http://www.mturk.com">Amazon Mechanical Turk</a> seems a kindof thing that
Web 2.0 will, probably, be all about. I admit - I did not get the full
essence of the idea. Still seems vague to me. Maybe it\’s ok - the
product is beta, or maybe it\’s because I had a really long day and
it\’s 11:40pm. Whichever of these two, or even if something entirely
different - it does sound interesting.</p>
<p>Curious to see how it develops.</p>
GPL Revisited.
2005-11-08T00:00:00-05:00
http://www.freshblurbs.com/blog/2005/11/08/gpl-revisited.html
<p>I have seen too many people, on too many occasions confusing what GPL is
about. Most common error is to think that one can not use a GPLed
product with a commercial application. More sophisticated version of the
confusion is some mumbling that involves the word “derivative” :-)</p>
<p>I think the root cause of the error is that 1) GPL License (as any legal
document) is obscure 2) GPL FAQ that is intended to remove the obscurity
is too long and it is hard to find the important piece within it. But
there is a
<a href="http://www.fsf.org/licensing/licenses/gpl-faq.html#CompanyGPLCostsMoney">piece</a>
that clarifies many things, stating:</p>
<blockquote>
<p><strong><em>Question: I just found out that a company has a copy of a GPL\‘ed
program, and it costs money to get it. Aren\‘t they violating the GPL
by not making it available on the Internet?</em></strong> \</p>
<p>Answer: No. The GPL does not require anyone to use the Internet for
distribution. It also does not require anyone in particular to
redistribute the program. And (outside of one special case), even if
someone does decide to redistribute the program sometimes, the GPL
doesn\‘t say he has to distribute a copy to you in particular, or any
other person in particular.</p>
<p>What the GPL requires is that he must have the freedom to distribute a
copy to you <em>if he wishes to</em>. Once the copyright holder does
distribute a copy program to someone, that someone can then
redistribute the program to you, or to anyone else, as he sees fit.</p>
</blockquote>
<p>What does this mean? GPL does not prohibit you to <strong>use</strong> your software,
of any license kind, with GPLed ones. Constraints only arise when you
decide to ship your software to third parties (which, if you are
developing a web application for own usage may never happen). <strong>GPL does
not require you to publish your code that you use with a GPLed
software</strong>, but it prevents you from denying others the right for
redistribution once you give them your code.</p>
<p>Bottomline: GPL prohibits you from prohibiting others, does not require
you to do anything in your own world.</p>
Komodo 3.5 Is Shipping Now
2005-11-06T00:00:00-05:00
http://www.freshblurbs.com/blog/2005/11/06/komodo-3-5-shipping-now.html
<p><a href="http://home.businesswire.com/portal/site/google/index.jsp?ndmViewId=news_view&newsId=20051103005368&newsLang=en">BusinessWire
reports</a>
that ActiveState shipped <a href="http://www.activestate.com/Products/Komodo/">Komodo
3.5</a> probably the best IDE
for scripting languages and a multi-platform one, in addition.</p>
<p>I was writing about Komodo in <a href="http://ika.motime.com/1128900395#503296">one of my recent
blogs</a>. ActiveState has decided
to include the quote in their
<a href="http://home.businesswire.com/portal/site/google/index.jsp?ndmViewId=news_view&newsId=20051103005368&newsLang=en">press-release</a>
on BusinessWire. I am glad to see it and wholeheartedly wish them the
best of luck with their great product.</p>
Count Words and Characters on Mac
2005-11-05T00:00:00-05:00
http://www.freshblurbs.com/blog/2005/11/05/count-words-and-characters-mac.html
<p><a href="http://www.paulgorman.org/">Paul Gorman</a> has written a small tool (
<a href="http://www.paulgorman.org/software/NanoCount.zip">NanoCount</a>) that I
found very nifty. It\’s as simple as it gets: shows a running word
count. It also lets you set a goal for number of words,</p>
Nifty Java Developer Toolset
2005-11-03T00:00:00-05:00
http://www.freshblurbs.com/blog/2005/11/03/nifty-java-developer-toolset.html
<p>Recently, I stumbled upon
<a href="http://www.shiftone.org/">http://www.shiftone.org/</a> They have got some
REAL nice toys in their toolbox, I must say. I was impressed. Actually,
except ExQ I quite loved all of them. I don\‘t see the value of ExQ
since I am a big believer in Hibernate but if you are still in the age
of raw SQL - maybe you will find ExQ useful, too. <br />
<br />
But other projects are real, real cool. I have been looking for an OOC
JNDI for a while, now. Arbor XML Processor is nice, too. I\‘ve begun
using JRat and find it very useful for JDK1.4 projects because of its
significantly low overhead (as opposed to OptimizeIt, JProbe et al). I
will definitely look into joCache. Just by description it looks like it
could be JBossCache done right :-)</p>
<p>All of the products are very user-friendly and comfy to use.</p>
<p>Two thumbs up to ShiftOne!</p>
Personal Note to Myself
2005-10-27T00:00:00-04:00
http://www.freshblurbs.com/blog/2005/10/27/personal-note-myself.html
<p>Yesterday was so overwhelming - forgot to make a note. So, anyways,
today is the second day. Learning from the bitter experience of
yesterday, I left home at 6:20am, today. When I got here, it was still
dark *chuckle* but traffic was way better.</p>
<p>P.S. SmartTag rulz.</p>
Web 2.0-ready Browser?
2005-10-25T00:00:00-04:00
http://www.freshblurbs.com/blog/2005/10/25/web-2-0-ready-browser.html
<p><a href="http://news.com.com/New+browser+gives+taste+of+Web+2.0/2100-1046_3-5905922.html">Flock</a></p>
<ul>
<li>a next generation browser? Have not had time to look too much into it,
yet. So far, it seems they are a little bit far from the promise :)</li>
</ul>
Oracle Buys-out InnoDB
2005-10-20T00:00:00-04:00
http://www.freshblurbs.com/blog/2005/10/20/oracle-buys-out-innodb.html
<p>Oracle <a href="http://www.oracle.com/corporate/press/2005_oct/inno.html">has acquired
InnoDB</a> which
will have some impact on MySQL as InnoDB engine is a more preferred
engine (a opposed to relatively unreliable MyISAM) supported in MySQL.</p>
<p>What will be the impact, we will know only in a year, according to the
press release from Oracle, but Oracle supporting engine to make its
direct open-source rival does not make much sense, does it?</p>
<p>It\’s an interesting timing considering what is going on in the
security arena of open-source software. As you know, Nessus has closed
its source code, by making it proprietary and Snort was bought by
CheckPoint.</p>
Shut Down Your Blogs!
2005-10-19T00:00:00-04:00
http://www.freshblurbs.com/blog/2005/10/19/shut-down-your-blogs.html
<p><a href="http://epic.makingithappen.co.uk/ols-master.html">Do it, now!</a> :-)</p>
Cross-Site Scripting in Web 2.0 Era
2005-10-14T00:00:00-04:00
http://www.freshblurbs.com/blog/2005/10/14/cross-site-scripting-web-2-0-era.html
<p>Here it goes again - the infamous Cross-Site Scripting but in Web 2.0
and <a href="http://www.betanews.com/article/CrossSite_Scripting_Worm_Hits_MySpace/1129232391">social <br />
networks context, this
time</a>.</p>
Verisign Exploring New Business Opportunities
2005-10-10T00:00:00-04:00
http://www.freshblurbs.com/blog/2005/10/10/verisign-exploring-new-business-opportunities.html
<p>It seems like Verisign is looking into some very interesting <a href="http://www.siliconvalleywatcher.com/mt/archives/2005/10/verisign_is_abo_1.php">new
business
opportunities</a>.
Considering Verisign is a large corporation (which tend to be inert)
it\’s interesting to see that it is so up to the beat of “web 2.0”</p>
<p>I have some personal reasons, too, to be excited seeing Verisign doing
so well… :-)</p>
Python is Great!
2005-10-10T00:00:00-04:00
http://www.freshblurbs.com/blog/2005/10/10/python-great.html
<p>This is official - I <strong>love</strong> Python. I think it is a beautifully
designed language that is a pleasure to program in.</p>
Komodo - the best IDE for Scripting Languages
2005-10-10T00:00:00-04:00
http://www.freshblurbs.com/blog/2005/10/10/komodo-best-ide-scripting-languages.html
<p>I played around with
<a href="http://www.activestate.com/Products/Komodo/">Komodo</a> today, and I must
say - <strong>I am impressed!</strong>. I imported one of my PHP projects in it and
messed with it. I was very, very delighted with the capabilities of
Komodo.</p>
<p>I am a Mac addict and on Macs I have tried Zend studio. It was the best
I could get on Mac but I still had so many things I hated about how it
worked that I never bought it and just decided TextWrangler was not as
much worse as to pay for Zend. I am almost sure I will buy Komodo (will
play around little more, still have some time on beta license).</p>
<p>Some major things I loved:</p>
<ol>
<li>Clean, very friendly and nicely integrated UI (not true for Zend)</li>
<li>Very compact and usable project navigation bar</li>
<li>Ability to see the code structure (methods, variables) of a PHP code</li>
<li>Support for both CVS and Subversion (Zend does not have Subversion
support and I was never able to make CVS support work either)</li>
<li>Regular Expression Toolkit is awesome!</li>
<li>I was able to create a macro for generating bean setters and
getters, 5 minutes after I installed Komodo (never could do in Zend
and it really consumes a lot of time, to create these setter/getters
manually if you try OO in PHP)</li>
<li>Ability to collapse/expand parts of code</li>
<li>Runs smoothly</li>
</ol>
<p>the only “negative” thing to be said is that - it took Komodo a while to
add PHP, TCL, Python (those I chose) analyzators after installation. But
it does that only once, so - who cares.</p>
<p>Well done! Awesome IDE!</p>
SugarCRM - Open Source CRM
2005-10-09T00:00:00-04:00
http://www.freshblurbs.com/blog/2005/10/09/sugarcrm-open-source-crm.html
<p><a href="http://www.sugarcrm.com/crm/">SugarCRM</a> is a professional-grade,
open-source CRM solution. Looks real good.</p>
PostgreSQL Made Fast?
2005-10-08T00:00:00-04:00
http://www.freshblurbs.com/blog/2005/10/08/postgresql-made-fast.html
<p><a href="http://www.enterprisedb.com/">EnterpriseDB</a> claims it is scalable and
Oracle compatible (quote: “most applications written for Oracle will run
without modification). It is based on Postgres so, I am really confused
if “scalability” should be understood as “fast enough”. Postgres and
“speed” has been antipodes for so long :)</p>
<p>OK, having poured some sarcasm, it looks interesting :) It would be
great if it can really do the job, becase - I <strong>do not</strong> like Oracle :)</p>
NING Rocks!
2005-10-06T00:00:00-04:00
http://www.freshblurbs.com/blog/2005/10/06/ning-rocks.html
<p><a href="http://personomies.com/">Pierre</a> enlightened me about a new cool thing
called <a href="http://www.ning.com">NING</a>, today. It\’s quite nifty, overall,
but there was one particular thing I could not stop enjoying (yes, I am
a sicko, get over it) -
<a href="http://confess.ning.com/">http://confess.ning.com/</a>. I think this
Confess sh.t is just AWESOME - terribly entertaining :)</p>
Safari Bug - Lost Cookies
2005-10-02T00:00:00-04:00
http://www.freshblurbs.com/blog/2005/10/02/safari-bug-lost-cookies.html
<p>I have detected an extremely annoying bug in Safari, today.</p>
<p>There is a bug in cookie management. If a page sets a persistent cookie
(expiry date is far enough in the future) this cookie must be kept at
the re-launch of the browser. This does not always happen in Safari.</p>
<p>Cookies are only persisted if you close the window/tab that set cookie
<strong>before</strong> quitting Safari. If you quit Safari without expliciutely
closing the tab that set cookie - forget about it.</p>
<p>Sample scenario: I fire-up Safari and go to http://www.motime.com, I log
in there, work for a while and then do File->Quit without closing the
tab/window where I used to work with the page. The cookie will be lost!</p>
<p>If I close the tab first, and then exit Safari - cookie will be
persisted.</p>
<p>I submitted a bug report to Apple but in my past experience their Safari
support team is not extremely responsive so, I do not have too high
hopes on quick fix, so far.</p>
What Are People More Interested In?
2005-10-01T00:00:00-04:00
http://www.freshblurbs.com/blog/2005/10/01/what-are-people-more-interested.html
<p>What do you think would gather more online attention - the world\’s
largest content database about economic development or a collection of
web-related tutorials? Well…. I was wrong, too, but the reality, as
reported by Alexa is:</p>
<p><img src="http://traffic.alexa.com/graph?w=379&h=216&r=6m&y=r&u=w3schools.com/&u=worldbank.org" alt="" /></p>
Three Brazzilions
2005-10-01T00:00:00-04:00
http://www.freshblurbs.com/blog/2005/10/01/three-brazzilions.html
<p>Donald Rumsfeld is giving the president his daily briefing.He concludes
by saying: “Yesterday, 3 Brazilian soldiers were killed.”</p>
<p>“OH NO!” the President exclaims. “That’s terrible!”</p>
<p>His staff stunned at this display of emotion, nervously watching asthe
President sits, head in hands.</p>
<p>Finally, the President looks up and asks, “How many is a brazillion?”</p>
Stone Age in 21st Century
2005-09-27T00:00:00-04:00
http://www.freshblurbs.com/blog/2005/09/27/stone-age-21st-century.html
<p>I keep being amazed how some fairly large and visible companies still
operate as if they were in 19th century. Today\’s grand-prize winner is
<a href="http://www.corel.com">Corel</a> corporation.</p>
<p><strong>FACT:</strong> You can not buy any of Corel\’s software products online!</p>
<p>The whole world is selling software online. You can buy any Jack and
Joe\’s program but - Corel? Naaah, they really need to produce these
useless boxes and put some, even more useless, paper in it and make you
wait for days while it gets delivered. What do we cut woods for? So that
Corel can send us lousy boxes? I refuse to accept this nonsense! I mean,
Corel executives must be <strong>real morons</strong> to be in such bad financial
shape when they\‘ve had such amazing products for so many years, but
the magnitude of their complete idiocy became apparent only today, to
me.</p>
<p>Rock on, dudes! Why don\‘t you get out of software business, altogether
and begin selling toilet paper?</p>
<p>Un-freaking-believable.</p>
Lucene Spell Checking
2005-09-26T00:00:00-04:00
http://www.freshblurbs.com/blog/2005/09/26/lucene-spell-checking.html
<p>Java.net has published a <a href="http://today.java.net/pub/a/today/2005/08/09/didyoumean.html">great
article</a>
about implementing Spell Checker in Lucene.</p>
Skype Widget
2005-09-25T00:00:00-04:00
http://www.freshblurbs.com/blog/2005/09/25/skype-widget.html
<p>Mac OS X user can now enjoy a Skype Dashboard widget along the Skype\’s
new updated version:
<a href="http://www.skype.com/products/skype/macosx/">http://www.skype.com/products/skype/macosx/</a></p>
.Mac Group
2005-09-20T00:00:00-04:00
http://www.freshblurbs.com/blog/2005/09/20/mac-group.html
<p>Apple launched <a href="http://www.apple.com/dotmac/groups.html">.Mac Groups</a>
initiative. Now anybody can create pretty powerful online communities.
AWESOME.</p>
Steve Jobs for Governor
2005-09-18T00:00:00-04:00
http://www.freshblurbs.com/blog/2005/09/18/steve-jobs-governor.html
<p><a href="http://www.calpatriot.org/blog/2005/08/21/steve-jobs-igov/">Rumors</a>
that <a href="http://homepage.mac.com/steve/Resume.html">Steve Jobs</a> may run for
Governor of California are increasing. I, personally, do not think he
would do it, even if he had better chances than others but it is an
interesting theory.</p>
<p>Looking at the rating of the “Terminator Governor” it is obvious that he
was a complete failure. No surprise there, for me, just a grin at people
who were b..s..ing that Arnold is not as dumb as he may look (sounds
familiar? Republicans “rock”) and that he has some nice record of
investment activities (kudos to his investment consultants, if so).</p>
<p>On the contrary, Steve Jobs is an outstandingly successful businessman
and knows a thing or two about management, too. Controversial or not -
show me how many people on this earth would mind having a record (and
fortune) like him.</p>
<p>Cheers to Steve :)</p>
JGroups - Crime Against Humanity.
2005-09-18T00:00:00-04:00
http://www.freshblurbs.com/blog/2005/09/18/jgroups-crime-against-humanity.html
<p><a href="http://jroller.com/page/fate/">BileBlog</a> is the worst blog about Java,
ever :) Mean-spiritted, hardly serious spit-offs of anger of a man who
does not hide his existential problems. If you are not already nuts,
reading this nightmare, it can definitely make you one. Yet, sometimes
it can be funny. I could not help
<a href="http://open-dictionary.com/ROFLMAO">ROFLMAO</a>ing when I read the
following nomination:</p>
<p><strong>Crimes against humanity</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> .. other nominees ...
</code></pre></div></div>
<p><br />
<strong>Bela Ban</strong>: Spending years developing the coolest sounding yet worst
performing Java multicast library in existence. \</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> ... the list continues ...
</code></pre></div></div>
<p>I guess Hani got ir right, this time :-)</p>
API Differences between JDK 1.5 and 1.4.2
2005-09-14T00:00:00-04:00
http://www.freshblurbs.com/blog/2005/09/14/api-differences-between-jdk-1-5-and-1-4-2.html
<p>Ever wondered about details of differences between JDK5 and JDK1.4?
Wonder no more, and use
<a href="http://javadiff.sourceforge.net/jdiff/reports/j2se142_j2se150b1/changes.html">JDiff</a>.</p>
<p>One word - AWESOME.</p>
Breakthrough Keyboard for Geeks
2005-09-11T00:00:00-04:00
http://www.freshblurbs.com/blog/2005/09/11/breakthrough-keyboard-geeks.html
<p><a href="http://www.design.ru">Lebedev Studio</a>, the leading Russian design
studio, has come up with a very innovative approach to keyboards:
<a href="http://www.artlebedev.com/portfolio/optimus/">http://www.artlebedev.com/portfolio/optimus/</a></p>
Mambo Splits.
2005-09-08T00:00:00-04:00
http://www.freshblurbs.com/blog/2005/09/08/mambo-splits.html
<p>Mambo is one of the most distinguished OSS CMS systems. Seems like lead
developers left the project and started a new venture. Find more about
this in a Cnet article:
<a href="http://news.com.com/Open-source+split+of+Mambo+software+begins/2100-7344_3-5846006.html">http://news.com.com/Open-source+split+of+Mambo+software+begins/2100-7344_3-5846006.html</a></p>
The first and only Java podcast - Javacast
2005-09-08T00:00:00-04:00
http://www.freshblurbs.com/blog/2005/09/08/first-and-only-java-podcast-javacast.html
<p>This is so cool! Wonderful casts and yea, it is podcast, baby :) \</p>
<p><a href="http://javacast.thepostmodern.net/">http://javacast.thepostmodern.net/</a>
<br />
Awesome</p>
Joda Time - Worth Paying Attention
2005-09-06T00:00:00-04:00
http://www.freshblurbs.com/blog/2005/09/06/joda-time-worth-paying-attention.html
<p><a href="http://joda-time.sourceforge.net/index.html">Joda Time</a> is an
interesting and important class library. It tries/claims to improve on
Java\’s Calendar and Date support.</p>
GMail Notifier
2005-09-02T00:00:00-04:00
http://www.freshblurbs.com/blog/2005/09/02/gmail-notifier.html
<p>Google seems to have developed Mac OS X version of <a href="http://toolbar.google.com/gmail-helper/index?promo=gdl-en">Gmail
Notifier</a>,
too. That\’s nice and good but I do not see it having any additional
features compared to the <a href="http://homepage.mac.com/carsten.guenther/GmailStatus/">GMail
Status</a> that I
have been using for a long time, now. Actually it looks so similiar, I
would get pissed off, if I was the developer of GMail Status (unless
Google paid him, which I do not know if they did).</p>
<p>However, one thing that both of this apps are lacking is the ability to
indicate the browser they will open GMail in. Now, why do I need it?
Because my browser if choice is Safari, without any doubt but, alas, it
has issues (yea, even after last update :-( ) with GMail. So I would
like GMail to open in Firefox, but I have no desire to make Firefox my
default browser.</p>
<p>Something very simple but is not present in either of those nice tools.
I wonder if people use programs they wrote, themselves and if they do -
how come they do not experience the same problems? :P</p>
Gas Prices Going Up.
2005-09-02T00:00:00-04:00
http://www.freshblurbs.com/blog/2005/09/02/gas-prices-going.html
<p>Are you driving a hybrid car? Maybe you should? \</p>
<p><a href="http://toccionline.kizash.com/films/1001/178/">http://toccionline.kizash.com/films/1001/178/</a></p>
Amazon.com Phone Number
2005-09-01T00:00:00-04:00
http://www.freshblurbs.com/blog/2005/09/01/amazon-com-phone-number.html
<p>Amazon is one of the companies that actually has a customer service
phone number but tries to hide it well.Following is the number I use to
look up at Google repeatedly, so I thought storing it in my blog would
bemore convenient.</p>
<p>Enjoy1-800-201-7575</p>
Compiling QT3 on POSIX
2005-08-30T00:00:00-04:00
http://www.freshblurbs.com/blog/2005/08/30/compiling-qt3-posix.html
<p>When compiling a QT3 distribution on a unix system, there are several
switches I would rather modify from their default values. For example,
by default QT compiles in shared mode. Now, now - do you really want to
send somebody an application you compiled and get cursed because that
user does not have libraries your application requires? I am all for
static compilation, hell with shared libraries! Then, I think GIF
support is nice and thread support is a must. No idea why Trolltech guys
have them disabled in the default.</p>
<p>All-in-all, here is the configure I use on my Mac: \</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> ./configure -static -qt-gif -thread
</code></pre></div></div>
<p>P.S. Please, note that this still does not enable database (sql) support
and since you are compiling statically if youwill need to work with a
database, you will have to recompile.</p>
Safari Update
2005-08-29T00:00:00-04:00
http://www.freshblurbs.com/blog/2005/08/29/safari-update.html
<p>Apple Inc. has released a Safari update today.</p>
<p>Safari is an extremely nice, fast and efficient browser on Mac OS X. The
only big problem it had was with GMail. I guess it was due to the AJAX
implementaion in Safari that made using gmail from Safari quite bulky.
It seems like the latest update has fixed the issues, though. I have
just installed the update and Gmail works pretty smoothly, so far.</p>
<p>Rock on, Apple!</p>
Gmail Rocks - once more.
2005-08-29T00:00:00-04:00
http://www.freshblurbs.com/blog/2005/08/29/gmail-rocks-once-more.html
<p>GMail is my most beloved email service. Not only because I get 1GB space
for free but because it is extremely user-friendly. It is so nice that I
do not even use POP access and always use it from the web. <br />
<br />
Recently I have discovered one more very cool feature. I don\‘t know
how long this feature has been around, maybe for a very long time, but I
must admit I only now discovered it and loved it. What I mean is hidden
in the Settings under Accounts/Send E-Mail As and allows to send email
as if it was sent from your another account… e.g. - your work email
account? <br />
<br />
This is quite important. Before, if I would forward some email to
gmail, for the convenience of recieving it in one (and niceest) place,
if then I wanted to reply to the message I had to go to the interface of
the email address the message was recieved for. Otherwise, sender would
be easily confused to recieve an answer to the email he sent to @umd.edu
address, from address that is @gmail.com - not something to do. <br />
<br />
Now that you got reasonably excited with me, I have to warn that gmail
does not send emails in a totally transparent way. Clients at the
receiving end have more than enough information to understand that email
was sent from this-and-this@foo.com but on behalf of gmail.com. Some
clients (I tested Outlook\’s web interface and Yahoo!) even warn about
this. <br />
<br />
I looked at the headers GMail generates and, indeed, it leaves a clear
trail in the following header sections: <br />
Return-Path: <whateveruser@gmail.com> <br />
…. <br />
Sender: whateveruser@gmail.com <br />
<br />
That\’s too sad. They really did not need to do such crap, because
they validate the email account belongs to you, before activating it and
I do not think there were any security issues. Yet, apparently, Google
tries to play safe… too bad :( <br />
<br />
But, whatever inconvenience, it is hard to deny that this service is
still pretty handy and nice and since it is free, we should not be
complaining too much, anyway :) <br />
<br />
<br />
\</p>
Cute Photo
2005-07-25T00:00:00-04:00
http://www.freshblurbs.com/blog/2005/07/25/cute-photo.html
<p>I was shown the cuttiest photo of a kitten today. I mean, I have seen
lots of cats and kitten in my life (just as everybody esle, I gues) but
Tessie is one of a kind. See yourself:</p>
<p><img src="http://www.ika.ge/img/Tessie.jpg" alt="" /></p>
Regarding Schedules
2005-07-23T00:00:00-04:00
http://www.freshblurbs.com/blog/2005/07/23/regarding-schedules.html
<p>Empire State building construction took 14 months. From ground zero to
opening - just 14 months, and with the technology (or lack of it) that
they had back then!</p>
<p>One word - INCREDIBLE.</p>
Just a note
2005-07-19T00:00:00-04:00
http://www.freshblurbs.com/blog/2005/07/19/just-note.html
<p>One of the best moments of my life - I got admitted to the Smith School
of Business at UMD. \</p>
Regarding Customers
2005-07-14T00:00:00-04:00
http://www.freshblurbs.com/blog/2005/07/14/regarding-customers.html
<p>What\’s the most annoying creation in the entire universe? Right,
customers. <br />
<br />
Three Dead Trolls <a href="http://www.deadtroll.com/index2.html?/video/helldeskcable.html~content">have posted a
video</a>
which is very representative and funny as hell. Check out and begin your
day with a healthy lough, maybe you will survive a day of dealing with
your customers. <br />
<br />
Enjoy \</p>
Complete Lack of Taste
2005-07-11T00:00:00-04:00
http://www.freshblurbs.com/blog/2005/07/11/complete-lack-taste.html
<p><a href="http://xerocool.innereyes.com/general/longhorn_5203_screenshots.php">Longhorn
Screenshots</a>
were leaked, once again. It looks like those are close to the final
version, this time.</p>
<p>What can you say about them? It\’s sad when people have no taste and no
feel for good user-interface design.</p>
<p>Could not they hire, at least, somebody normal? How can one be so
tasteless? For so long?</p>
<p>Gross.</p>
Begin Podcasting Today
2005-07-07T00:00:00-04:00
http://www.freshblurbs.com/blog/2005/07/07/begin-podcasting-today.html
<p>If you are a <a href="http://www.blogger.com">Blogger</a> subscriber you can get a
free podcast via an affiliated service:
<a href="http://www.audioblogger.com">AudioBlogger</a>. <br />
<br />
It\’s pretty cool and generous, if you ask me, but one thing that
really sucks is - you can only post your podcasts via some phone number
(1 - 6 6 1- 7 1 6 - B L O G). As far as I know, calling that number does
not involve a fee (disregarding long-distance charges) so I don\‘t know</p>
<ul>
<li>why such an awkward approach? Voice quality is gonna be sucky and I
thought we were past the telephony era, anyway. <br />
<br />
Why not just allow users to upload audio files? <br />
<br />
Weird. There must be something about it. I just have no idea what, yet.
\</li>
</ul>
Maybe Richard Stallman Is Right After All?
2005-07-06T00:00:00-04:00
http://www.freshblurbs.com/blog/2005/07/06/maybe-richard-stallman-right-after-all.html
<p>It makes me sick to stomach to see what is happening with the Java Web
Frameworks. Sun and other vendors shamelessly push JSF down the
customers throats and they swallaw it without as much as a word of a
protest. JavaServer Faces is a piece of crap! It has its rotten roots so
deep in Struts - saying Struts is the history and JSF is the future -
ain’t even funny! There is no community spirit, really. It’s all about
vendors and their buddy CTOs in corporate world, who buy from their
buddies.</p>
<p>This just <strong>sucks</strong>. I so much hope Howard will be able to pull it off,
like Gavin did with Hibernate, but I just don’t see it happening yet.
Such a shame! Tapestry is soooo much better than the joke of all
frameworks - JSF! I am very dissapointed with JBoss, too - standing
behind JSF. It is becoming just another corporate vendor - that’s what
is going on. Too bad!</p>
Long Tail in business
2005-06-22T00:00:00-04:00
http://www.freshblurbs.com/blog/2005/06/22/long-tail-business.html
<p><a href="http://www.personomies.com/">Pierre</a> has pointed me to a <a href="http://bnoopy.typepad.com/bnoopy/2005/03/the_long_tail_o.html">very
interesting
article</a>
about how infrequent (in quantity) but large number (in distribution) of
items can be a significant contributor (or missed opportunity) of your
sales.</p>
<p>The author, Joe Kraus, is the the co-founder of the
<a href="http://www.excite.com">Excite</a> and the founder of
<a href="http://www.jotspot.com">JotSpot</a>, so no surprise - he knows what he is
talking about :)</p>
Steve Jobs Speech at Stanford
2005-06-19T00:00:00-04:00
http://www.freshblurbs.com/blog/2005/06/19/steve-jobs-speech-stanford.html
<p><a href="http://news-service.stanford.edu/news/2005/june15/jobs-061505">http://news-service.stanford.edu/news/2005/june15/jobs-061505</a>I
find it very interesting. Not so much that it\’s a deep philosophy or
anything, but it is interesting in the sense - it shows a piece of Steve
Jobs, probably one of the most remarkable persons of our and the end of
previous centuries.</p>
Installing JDK5 on Mac OS X
2005-06-14T00:00:00-04:00
http://www.freshblurbs.com/blog/2005/06/14/installing-jdk5-mac-os-x.html
<p>Apple released JDK5 implementation quite some time ago. The installer
does not overwrite the default 1.4 installation but rather installs
paralelly (good!). It also comes with a tool for switching between 1.4
and 5 JDKs. However that tool does not do crap (bad). We discussed this
at TheServerSide when JDK was released and I posted a solution but today
I was setting up my new Powerbook and, of course, I did not remember the
solution and had no desire to figure it out again.</p>
<p>So, I am posting the solution here, in case I will need it again and
maybe it will, also, be useful for folks who do not read TSS but read my
blog (LOL), and are interested in Java.</p>
<p>Solution: <br />
1) Install JDK5 from Apple <br />
2) Follow these steps: <br />
> cd /System/Library/Frameworks/JavaVM.framework/Versions <br />
> sudo mv CurrentJDK CurrentJDK-old <br />
> sudo ln -s 1.5 CurrentJDK</p>
Steve Jobs Did It Again
2005-06-07T00:00:00-04:00
http://www.freshblurbs.com/blog/2005/06/07/steve-jobs-did-it-again.html
<p>Steve Jobs made a Keynote
<a href="http://stream.apple.akadns.net/">presentation</a> at WWDC today.
Regardless whether I like that Apple is switching to Intel processors
vs. Power line or not is a different story but the thing that has been
proven, once again, for me is - Steve is a genius! Absolute, complete,
incredibe.</p>
<p>Having been developing Mac OS X for Intel, too, “just in case”, all this
time? Being apple to screw IBM up and deep like that? When IBM tried to
screw around with them (possibly, not without the help of the Redmond
company) turning around and telling Big Blue to go … themselves? And
not just saying that bu having everything ready to jump to a completely
different architecture? I like that!</p>
<p>I hate Vendor Loc-In (well, maybe only when it\’s not me a vendor, but
anyway). That\’s where all the evil was born from and if somebody has
any common sense - that\’s the first thing to avoid. Makes sense? And
how many, out there, do avoid? Steve did. I bet he may have SPARC
version of Mac OS X hidden somewhere, too :)</p>
<p>Kudos, Steve! You are my role-model!</p>
Reality Distortion
2005-06-05T00:00:00-04:00
http://www.freshblurbs.com/blog/2005/06/05/reality-distortion.html
<p>Even though I do get a satisfaction close to physical, seeing a clever
Object-Oriented design, it never stops to amaze me that, as OO purists
are ready to cut each-others throats over certain design decisions, the
most important and sophisticated piece of software we use - operating
systems - are almost entirely written in a non-OO language like C and
some of it - even in Assembler, for that matter. This is quite ironic
but shows the most important point that is,
unfortunately, often forgotten - it’s not the “best practice” techniques
or “design patterns” that matter!</p>
About Smartess Pains in the ...
2005-06-01T00:00:00-04:00
http://www.freshblurbs.com/blog/2005/06/01/about-smartess-pains.html
<p>Sometimes people try too hard and end-up doing plain stupid things. One
of such things ruined my day, today.</p>
<p>XMLHttpRequest is very cool and AJAX is cool and it is awesome that all
four major browsers (IE, Mozilla/Firefox, Opera, Safari) have support
for it, in their latest versions. That’s unusually good, but Safari and
Opera teams still managed to screw up.</p>
<p>XMLHttpRequest has getResponseHeader() method defined in its API. Neat!
But look, now, what Safari and Opera developers did: they restricted any
headers except those that are pre-defined in the HTTP Protocol. For what
f…in reason, if I may ask? Headers carry for meta-information. The
goddamned web-servers allow me to set arbitrary header labels, so who
asks lousy browser developers to restrict the list? What am I supposed
to do now - transfer meta information in the body of the response? This
is completely INSANE! I mean - if there was any security issue involved</p>
<ul>
<li>so be it, but there is none! It is just plain stupid and trying to be
a smartass, ending up being just a huge pain in the ass.</li>
</ul>
<p>I AM SO PISSED OFF. It sucks so much - I am ready to forget about
supporting Opera (I do not like it anyway), but what beats me is that
Safari has the same crap :’( I would hate my AJAX implementation to be
incompatible with Safari - not that they do not deserve it tho.</p>
<p>Sooooooooo stupid!!!!!!!!!! <br />
WHYYYYYYYyyyyyyyyyyyyyyyyyy?</p>
Longhorn - will it ever?
2005-05-31T00:00:00-04:00
http://www.freshblurbs.com/blog/2005/05/31/longhorn-will-it-ever.html
<p>Latest joke I liked:</p>
<p>“Microsoft Corporation has announced that it is looking for beta-testers
for its upcoming operating-system - Longhorn. Applicable candidates must
be natural-blond females.”</p>
Zend Platform
2005-05-28T00:00:00-04:00
http://www.freshblurbs.com/blog/2005/05/28/zend-platform.html
<p>The following video demonstrated the integrated capabilities of the
<a href="http://www.zend.com/platform">Zend Platform</a>:
<a href="http://www.zend.com/support/user_docs/ZendPlatform/video/demo/index.php">http://www.zend.com/support/user_docs/ZendPlatform/video/demo/index.php</a>.</p>
<p>Granted that this is a commercial, one has to still admit that - THIS IS
IMPRESSIVE!</p>
<p>Let\’s be honest - this is one very cool integrated, intelligent
system. The problem detection/debugging system looked absolutely
awesome. Not many, even Java, platforms have cool system like that and -
yes, it is a life-saver.</p>
Norwegian soliers have sense of humour
2005-05-21T00:00:00-04:00
http://www.freshblurbs.com/blog/2005/05/21/norwegian-soliers-have-sense-humour.html
<p>Ooops :) \</p>
<p><a href="http://www.big-boys.com/articles/kosovo.html">http://www.big-boys.com/articles/kosovo.html</a></p>
Link-in, dude!
2005-05-20T00:00:00-04:00
http://www.freshblurbs.com/blog/2005/05/20/link-dude.html
<p>Shortly put: <br />
1) Read <a href="http://wemmick.blogspot.com/2005/05/im-linked-in.html">Doug\’s Blog
Post</a> <br />
2) Followed some links from there on <br />
3) Thought for 5 secs <br />
4) <a href="http://www.linkedin.com/">Linked-in</a> <br />
5) Continued thinking… \</p>
IBM - Jobs - Fleury
2005-05-20T00:00:00-04:00
http://www.freshblurbs.com/blog/2005/05/20/ibm-jobs-fleury.html
<p>Marc Fleury, of JBoss, has recently posted quite a nervous
<a href="http://jboss.org/jbossBlog/blog/mfleury/?permalink=IBM_Turns_the_Guns_on_Professional_Open_Source.txt">post</a>
on JBoss Blog. The post is interesting, no surprise, but I especially
enjoyed the tone. Such a familiar tone of a young cock (as in bird,
swear <img src="/editor/fck/editor/images/smiley/rhymbox-1.0/cool.gif" alt="" /> )
stepping up. Heh. There was a famous another one, <a href="http://www.uiowa.edu/~commstud/adclass/1984_mac_ad.html">11 years
ago</a>, and look
today - new Macs are proudly running IBM processors :) <br />
<br />
That said, it is in no way to diminish what Marc and JBoss are doing.
All the respect to them. It just brings some funny memories and raises
curiosity - who will have longer …. (not the bird, this time)…. <br />
\</p>
Explaining java.lang.OutOfMemoryError: PermGen space
2005-05-19T00:00:00-04:00
http://www.freshblurbs.com/blog/2005/05/19/explaining-java-lang-outofmemoryerror-permgen-space.html
<p>Most probably, a lot of Java developers have seen OutOfMemory error one
time or other. However these errors come in different forms and shapes.
The more common is: “Exception in thread “main”
java.lang.OutOfMemoryError: Java heap space” and indicates that the Heap
utilization has exceeded the value set by -Xmx. This is not the only
error message, of this type, however.</p>
<p>One more interesting flavor of the same error message, less common but
hence even more troublesome is: “java.lang.OutOfMemoryError: PermGen
space”. Most of the memory profiler tools are unable to detect this
problem, so it is<br />
even more troublesome and therefor - interesting.</p>
<p>To understand this error message and fix it, we have to remember that,
for optimized, more efficient garbage-collecting Java Heap is managed in
generations - memory segments holding objects of different ages. Garbage
collection algorithms in each generation are different. Objects are
allocated in a generation for younger objects - the Young Generation,
and because of infant mortality most objects die there. When the young
generation fills up it causes a Minor Collection. Assuming high infant
mortality, minor collections are garbage-collected frequently. Some
surviving objects are moved to a Tenured Generation. When the Tenured
Generation needs to be collected there is a Major Collection that is
often much slower because it involves all live objects. Each generation
contains variables of different length of life and different GC policies
are applied to them.</p>
<p>There is a third generation too - Permanent Generation. The permanent
generation is special because it holds meta-data describing user classes
(classes that are not part of the Java language). Examples of such
meta-data are objects describing<br />
classes and methods and they are stored in the Permanent Generation.
Applications with large code-base can quickly fill up this segment of
the heap which will cause java.lang.OutOfMemoryError: PermGen no matter
how high your -Xmx and how much memory you have on the machine.</p>
<p>Sun JVMs allow you to resize the different generations of the heap,
including the permanent generation. On a Sun JVM (1.3.1 and above) you
can configure the initial permanent generation size and the maximum
permanent generation size.<br />
<br />
To set a new initial size on Sun JVM use the <strong>-XX:PermSize=64m</strong> option
when starting the virtual machine. To set the maximum permanent
generation size use <strong>-XX:MaxPermSize=128m</strong> option. If you set the
initial size and maximum size to equal values you may be able to avoid
some full garbage collections that may occur if/when the permanent
generation needs to be resized. The default values differ from among
different versions but for Sun JVMs upper limit is typically 64MB.</p>
<p>Some of the default values for Sun JVMs are listed below.</p>
<table border="1">
<tbody><tr><th> JDK 1.3.1_06 </th><th> Initial Size </th><th> Maximum Size</th></tr>
<tr><td class="black"> Client JVM </td><td> 1MB </td><td> 32MB</td></tr>
<tr><td> Server JVM </td><td> 1MB </td><td> 64MB</td></tr>
</tbody></table>
<p></p><p>
</p><table style="color: black;" border="1"></p>
<tbody><tr><th> JDK 1.4.1_01 </th><th> Initial Size </th><th> Maximum Size</th></tr>
<tr><td> Client JVM </td><td> 4MB </td><td> 64MB</td></tr>
<tr><td> Server JVM </td><td> 4MB </td><td> 64MB</td></tr>
</tbody>
<p></table></p>
<p>
</p>
<table style="color: black;" border="1">
<tbody><tr><th> JDK 1.4.2 </th><th> Initial Size </th><th> Maximum Size</th></tr>
<tr><td> Client JVM </td><td> 4MB </td><td> 64MB</td></tr>
<tr><td> Server JVM </td><td> 16MB </td><td> 64MB</td></tr>
</tbody></table>
<p></p>
<table style="color: black;" border="1">
<tbody><tr><th> JDK 1.5.0 </th><th> Initial Size </th><th> Maximum Size</th></tr>
<tr><td> Client JVM </td><td> 8MB </td><td> 64MB</td></tr>
<tr><td> Server JVM </td><td> 16MB </td><td> 64MB</td></tr>
</tbody></table>
<p><br /></p>
<p>Following is a JSP code you can use to monitor memory utilization in
different generations (including PermGen):</p>
<script src="https://gist.github.com/893843.js?file=report.jsp"></script>
<script type="text/html" id="hiddencommentedout">
<table style="font-size: 8pt; color: rgb(0, 0, 128); font-family: Courier; background-color: rgb(206, 206, 206);" cellpadding="2" cellspacing="1">
<tbody><tr><td>
<%@ page import="java.lang.management.*" %><br><%@ page import="java.util.*" %><br><html><br><head><br> <title>JVM Memory Monitor</title><br></head><br><br><%<br> Iterator iter = ManagementFactory.getMemoryPoolMXBeans().iterator();<br> while (iter.hasNext()) {<br> MemoryPoolMXBean item = (MemoryPoolMXBean) iter.next();<br>%><br><br><table border="0" width="100%"><br><tr><td colspan="2" align="center"><h3>Memory MXBean</h3></td></tr><br><tr><td
width="200">Heap Memory Usage</td><td><%=
ManagementFactory.getMemoryMXBean().getHeapMemoryUsage()
%></td></tr><br><tr><td>Non-Heap Memory
Usage</td><td><%=
ManagementFactory.getMemoryMXBean().getNonHeapMemoryUsage()
%></td></tr></body><br><tr><td colspan="2">&nbsp;</td></tr><br><tr><td colspan="2" align="center"><h3>Memory Pool MXBeans</h3></td></tr><br><%<br> Iterator iter = ManagementFactory.getMemoryPoolMXBeans().iterator();<br> while (iter.hasNext()) {<br> MemoryPoolMXBean item = (MemoryPoolMXBean) iter.next();<br>%><br><tr><td colspan="2"><br><table border="0" width="100%" style="border: 1px #98AAB1 solid;"><br><tr><td colspan="2" align="center"><b><%= item.getName() %></b></td></tr><br><tr><td width="200">Type</td><td><%= item.getType() %></td></tr><br><tr><td>Usage</td><td><%= item.getUsage() %></td></tr><br><tr><td>Peak Usage</td><td><%= item.getPeakUsage() %></td></tr><br><tr><td>Collection Usage</td><td><%= item.getCollectionUsage() %></td></tr><br></table><br></td></tr><br><tr><td colspan="2">&nbsp;</td></tr><br><%<br>}<br>%><br><br></table>
</td></tr></tbody></table>
</script>
<p>As of JBoss v3.2.8/4.0.2, the ServerInfo MBean registered under the
name <code class="language-plaintext highlighter-rouge">jboss.system:type=ServerInfo</code> has been enhanced with a new operation
<code class="language-plaintext highlighter-rouge">listMemoryPools(boolean fancy)</code> that presents information about the memory pools managed by the JVM.</p>
Fly With Oracle
2005-05-17T00:00:00-04:00
http://www.freshblurbs.com/blog/2005/05/17/fly-oracle.html
<p>What do environmentalists think about Oracle?</p>
<p><a href="http://www.oracle.com/space/">http://www.oracle.com/space/</a></p>
Microsoft "Sees" the Future of Your Kid?
2005-04-28T00:00:00-04:00
http://www.freshblurbs.com/blog/2005/04/28/microsoft-quot-sees-quot-future-your-kid.html
<p> <img src="http://homepage.mac.com/inadarei/.Pictures/art/antimskid.jpg" alt="Microsoft
sucks." /></p>
Closer - Movie
2005-04-25T00:00:00-04:00
http://www.freshblurbs.com/blog/2005/04/25/closer-movie.html
<p>Doug <a href="http://wemmick.blogspot.com/2005/04/screenitcom-review-echoes-reality.html">has
blogged</a>
about the new movie -
<a href="http://www.imdb.com/title/tt0376541/?fr=c2l0ZT1kZnxteD0yMHxsbT01MDB8dHQ9b258ZmI9dXxwbj0wfHE9Y2xvc2VyfGh0bWw9MXxubT1vbg__;fc=1;ft=38;fm=1">Closer</a>,
recently.</p>
<p>I guess, he did not like it much, and since I trust his movie taste (and
since I was REAL busy), I did not get it. Today, I was shopping at
Costco and ran into Closer\’s DVD. Well, I really love Natalie Portman
and respect Julia a lot, so curious to see what was so, quote,
“badly-tasting” in this well-awarded (2 Golden Globes, 2 Oscar
nominations) film, I grabbed it, immediately.</p>
<p>The movie is very well done. That, by the way, was in the quote Doug
posted, too: “while his work, the script and especially the work from
the four leads is solid to terrific, I just wish that their characters
and the overall film didn\‘t leave such a bad taste in your mouth
and/or lead to the urge to shower after watching it due to all of the
ugliness that\’s present.” I can not agree to the “ugliness”, part
though. I would not expect SreenIt! to look only for bright colors in a
movie. That would be too stupid. So what did they find so “ugly”?</p>
<p>I guess, it is a matter of - whether you can relate to the story, in the
movie, or not.</p>
<p>If you married your college sweetheart, and lived happily ever after -
it may seem “dirty”, but not everybody is that lucky :) Things happen in
life. Hey, life _is_ dirty itself. So, why should cinematograph try to
brighten-up the reality? I do not like phony movies, much. \</p>
<p>So, my final verdict - two thumbs up. Very well done, and did not seem
like a movie, you need to shower afterwards, to me :)</p>
Quick Java IDE Comparision.
2005-04-24T00:00:00-04:00
http://www.freshblurbs.com/blog/2005/04/24/quick-java-ide-comparision.html
<hr />
<p>IDE Like Dislike</p>
<p>IntelliJ IDEA Real intellijent. Outstanding refactoring features. Significant number of plugins. Very heavy. Each installed plugin slows it down significantly and it is quite slow itself, too. Also, it is heavy both on RAM and CPU. Even with 1GB RAM, because of the CPU overhead I could not afford having IntelliJ on my Mac Mini.</p>
<p>Borland JBuilder By far - the most good-looking IDE. Borland skin rocks and everything is way intuitive/comfortable. Very friendly. Decent refactoring features abd quite intelligent, overall, especially the 2005 edition. Not many plugins. Expensive, expensive, expensive! Yes, there is a free Foundation version but after trying the Enterprise version, only insane would suffice with the Foundation. Enterprise version is way over what I or even my organization can afford. With recent <a href="http://www.theserverside.com/news/thread.tss?thread_id=33488">rumors</a>, one might hope, though. From the other hand - will Eclipse be able to adopt fully, what is good in JBuilder?</p>
<p>Eclipse Unmatched community support. Eclipse is _the_ editor, if you want de-facto standard. The most number of plugins is just a by-product of that :) I especially like Hibernate plugins, JBoss IDE, CVS Browser (!!!) and web-browser plugin (comes real handy for keeping nicely HTML-formatted unit-test results within the sight). Far from being pretty, to say the least. Not very friendly or intuitive. Weak refactoring support. Initial set up of a project from CVS was a pain. Forces its “style” real hard. If you want to work in Eclipse - you better wear their hat. Other IDEs are not so “conservative”, or I would say - such pain in the … For example, it did not like how I had test source folders separated into three and JUnit functionality does not work, keeps complaining every now and then. And let me repear - when you spend most of your day in one program - you really wish it looked better</p>
<p>NetBeans. Integrated profiler. Very advanced Ant integration - Ant is how NetBeans configures/compiles project natively. Wonderful JSF support (even though I hate JSF). Not many plugins. Most of the available ones are not free, e.g. <a href="http://www.siptech.com/download.jsp">JBoss plugin</a> is available but costs 15$ - 50$ \</p>
<hr />
Rss and atOM utilitiEs (ROME)
2005-04-20T00:00:00-04:00
http://www.freshblurbs.com/blog/2005/04/20/rss-and-atom-utilities-rome.html
<p>” <a href="http://wiki.java.net/bin/view/Javawsxml/Rome">ROME</a> is a set of
Atom/RSS Java utilities that make it easy to work in Java with most
syndication formats.</p>
<p>Today it accepts all flavors of RSS (0.90, 0.91 Netscape, 0.91 Userland,
0.92, 0.93, 0.94, 1.0 and 2.0) and Atom 0.3 feeds.</p>
<p>ROME includes a set of parsers and generators for the various flavors of
syndication feeds, as well as converters to convert from one format to
another. The parsers can give you back Java objects that are either
specific for the format you want to work with, or a generic normalized
SyndFeed class that lets you work on with the data without bothering
about the incoming or outgoing feed type.”</p>
Persistent Domain Objects Pattern.
2005-04-18T00:00:00-04:00
http://www.freshblurbs.com/blog/2005/04/18/persistent-domain-objects-pattern.html
<h2 id="abstract">Abstract</h2>
<p>Persisting domain objects is one of the most challenging aspects of
designing a flexible and testable enterprise application. There are lots
of examples, in the industry, when developers get it wrong and end-up
either with an effectively procedural, non-object-oriented structure
and/or a highly complicated, tightly coupled design which is hard to
unit-test.</p>
<p>Persistent Domain Objects Pattern gives a solution to resolve
tight-coupling of the persistence and application logic code. PDOP
decouples those by extracting the details of the persistence
implementation and hiding it behind an interface, employing Dependency
Injection techniques. As a result, domain objects do not need to know or
worry about the details of the persistence code and can concentrate on
their main task - delivering encapsulated data and behavior that models
the domain under question. It, also, makes domain objects, much easier
to unit-test in isolation from its dependency - persistent storage (e.g.
database). Effective unit-testing increases the quality of a programming
code and its extensibility.</p>
<h2 id="scope">Scope</h2>
<p>Domain Model, Persisting Domain Objects.</p>
<h2 id="problem-definition">Problem Definition</h2>
<p>The core of most applications is their Domain Model. A Domain Model
defines business rules (behavior) and the data that the business rules
apply to. The behavior and the data are encapsulated into objects that
form a hierarchy and can interact with each-other, thus effectively
modeling the domain reality. For a wide-range of applications this
Object-Oriented way of modeling the real-life scenarios works with the
best, most effective approximation possible.</p>
<p>Usually, humans desire to interact with the model, in one way or
another: influence the system or get a glimpse of what is going on. This
is achieved via a View layer. Since the business rules (Model) change
far less frequently than the user interface to the system (View), there
is, often, a requirement of being able to change View without disturbing
the Model. The requirement can be satisfied by decoupling Model and View
through the introduction of a Controller. This brings us to the infamous
Model-View-Controller (MVC) pattern.</p>
<p>If we could just start-up an application in-memory and guarantee that it
always stays there, the above would be as much as we would have to worry
about. Alas, that’s not the case. We have to periodically (or
constantly) backup a snapshot of the system’s state into some kind of
persistent storage. This way we can restore the state from the backup,
if needed, or share it with others. The motivation and mechanisms, for
the persistence, can be numerous and different but it is, almost, always
necessary.</p>
<p>In fact, the persistence is so important that some people begin with the
design of the persistent storage (e.g. DB tables) and end-up with an
Anemic Domain Model and a separate “Service Layer” consisting of queries
to the persistent storage. Martin Fowler et al. have identified it as an
anti-pattern. Such tight coupling of the application code and the
persistence one, makes it very hard to unit-test your application -
makes application code less reliable and extensible.</p>
<h2 id="solution">Solution</h2>
<p>One solution to the defined problem is to abstractly extract the
concrete implementation of the persistence code out of the Domain Model.
Basically: decouple the persistence from the application code. By
decoupling, besides making our application much easier to unit-test, we
will, also, make it more flexible - different persistent storage
mechanisms (LDAP, DB, plain files, XML etc.) can be swapped-in
on-demand, without affecting the application code and logic.</p>
<p>While we do this, we have a supplemental goal: we want to keep the
implementation simple. One way of achieving the goal is to declare
persistence as a dependency of a domain object. We can introduce a
Manager interface that our domain object depends on for all its
persistence needs.</p>
<p>Concrete implementations of Manager can be registered with the
appropriate entities using Dependency Injection; so that the entity
itself never needs to know the specific implementation used.</p>
<h2 id="sample-code">Sample Code</h2>
<p>In this sample, we will look at a Blog entity. For the purpose of this
demo, we will use the Context IoC introduced by Sony Matthew. The reason
why we choose it over the Constructor or Setter Dependency Injection is
to make example code simpler.</p>
<p>Let’s look at the Blog interface. Please, note that the only addition to
the interface, that would not be present in a “pure” domain object, is
the declaration of the interface for the persistence dependency:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">interface</span> <span class="nc">Blog</span> <span class="o">{</span>
<span class="kd">public</span> <span class="kd">interface</span> <span class="nc">Manager</span> <span class="o">{</span>
<span class="c1">//-- The argument to the load() method is entity's PK\</span>
<span class="kd">public</span> <span class="nc">Blog</span> <span class="nf">load</span><span class="o">(</span> <span class="nc">String</span> <span class="n">name</span> <span class="o">);</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">save</span><span class="o">(</span> <span class="nc">Blog</span> <span class="n">blog</span> <span class="o">);</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">remove</span><span class="o">(</span> <span class="nc">Blog</span> <span class="n">blog</span><span class="o">);</span>
<span class="o">}</span>
<span class="c1">//-- The rest of the Blog interface goes below\</span>
<span class="c1">// .....</span>
<span class="o">}</span>
</code></pre></div></div>
<p>Implementation:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">BlogImpl</span> <span class="kd">implements</span> <span class="nc">Blog</span> <span class="o">{</span>
<span class="kd">private</span> <span class="kd">static</span> <span class="nc">Blog</span><span class="o">.</span><span class="na">Manager</span> <span class="n">manager</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="nc">Blog</span><span class="o">.</span><span class="na">Manager</span> <span class="nf">getManager</span> <span class="o">()</span> <span class="o">{</span>
<span class="k">return</span> <span class="nc">BlogImpl</span><span class="o">.</span><span class="na">manager</span><span class="o">;</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">setManager</span> <span class="o">(</span> <span class="nc">Blog</span><span class="o">.</span><span class="na">Manager</span> <span class="n">manager</span> <span class="o">)</span> <span class="o">{</span>
<span class="nc">BlogImpl</span><span class="o">.</span><span class="na">manager</span> <span class="o">=</span> <span class="n">manager</span><span class="o">;</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="nf">BlogImpl</span><span class="o">()</span> <span class="o">{</span>
<span class="c1">// ..</span>
<span class="o">}</span>
<span class="kd">private</span> <span class="nc">String</span> <span class="n">name</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span>
<span class="kd">public</span> <span class="nc">String</span> <span class="nf">getName</span><span class="o">()</span> <span class="o">{</span>
<span class="k">return</span> <span class="k">this</span><span class="o">.</span><span class="na">name</span><span class="o">;</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">setName</span><span class="o">(</span> <span class="nc">String</span> <span class="n">name</span> <span class="o">)</span> <span class="o">{</span>
<span class="k">this</span><span class="o">.</span><span class="na">name</span> <span class="o">=</span> <span class="n">name</span><span class="o">;</span>
<span class="o">}</span>
<span class="c1">//-- Below go any other properties and methods relevant\</span>
<span class="c1">//-- to the Blog entity as a purely Domain Object.\</span>
<span class="c1">//.....\</span>
<span class="o">}</span>
</code></pre></div></div>
<p>In the above example, the primary key of the Blog entity is the name
property. One of the manager implementations can have an implementation that
looks like the following:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">BlogManagerImpl</span> <span class="kd">implements</span> <span class="nc">Blog</span><span class="o">.</span><span class="na">Manager</span> <span class="o">{</span>
<span class="kd">public</span> <span class="nf">BlogManagerImpl</span><span class="o">()</span> <span class="o">{}</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">save</span><span class="o">(</span> <span class="nc">Blog</span> <span class="n">blog</span><span class="o">)</span> <span class="o">{</span>
<span class="c1">//-- Save the state of the Blog object, into a database</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="nc">Blog</span> <span class="nf">load</span><span class="o">(</span> <span class="nc">String</span> <span class="n">name</span><span class="o">)</span> <span class="o">{</span>
<span class="c1">//-- Load the Blog instance from a database.</span>
<span class="c1">//-- e.g. using hibernate:</span>
<span class="c1">//-- return (BlogImpl) session.load( BlogImpl.class, name );</span>
<span class="c1">//-- this is just for the demonstration purposes</span>
<span class="nc">BlogImpl</span> <span class="n">blog</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">BlogImpl</span><span class="o">();</span>
<span class="n">blog</span><span class="o">.</span><span class="na">setName</span> <span class="o">(</span> <span class="n">name</span> <span class="o">);</span>
<span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span> <span class="o">(</span> <span class="s">"Loaded blog: "</span> <span class="o">+</span> <span class="n">blog</span><span class="o">.</span><span class="na">getName</span><span class="o">()</span> <span class="o">);</span>
<span class="k">return</span> <span class="n">blog</span><span class="o">;</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">remove</span><span class="o">(</span> <span class="nc">Blog</span> <span class="n">blog</span><span class="o">)</span> <span class="o">{</span><span class="err">\</span>
<span class="c1">//-- Remove the persisted state of the object from the</span>
<span class="c1">//-- database..</span>
<span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>
<p>and, finally, the following is how your application may use all of the
above to load two blogs:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">Main</span> <span class="o">{</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">main</span><span class="o">(</span><span class="nc">String</span><span class="o">[]</span> <span class="n">args</span><span class="o">)</span> <span class="o">{</span>
<span class="nc">Blog</span> <span class="n">blog</span><span class="o">,</span> <span class="n">blog2</span><span class="o">;</span>
<span class="nc">Blog</span><span class="o">.</span><span class="na">Manager</span> <span class="n">blogManager</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">BlogManagerImpl</span><span class="o">();</span>
<span class="nc">BlogImpl</span><span class="o">.</span><span class="na">setManager</span><span class="o">(</span> <span class="n">blogManager</span> <span class="o">);</span>
<span class="n">blog</span> <span class="o">=</span> <span class="o">(</span><span class="nc">BlogImpl</span><span class="o">)</span> <span class="nc">BlogImpl</span><span class="o">.</span><span class="na">getManager</span><span class="o">().</span><span class="na">load</span> <span class="o">(</span> <span class="s">"John"</span> <span class="o">);</span>
<span class="n">blog2</span> <span class="o">=</span> <span class="o">(</span><span class="nc">BlogImpl</span><span class="o">)</span> <span class="nc">BlogImpl</span><span class="o">.</span><span class="na">getManager</span><span class="o">().</span><span class="na">load</span> <span class="o">(</span> <span class="s">"Joanna"</span> <span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>
<p>each call to the <code class="language-plaintext highlighter-rouge">getManager().load()</code> will load an entity from a
database. For the purposes of this demo, it, also, displays a message.</p>
<h2 id="conclusion">Conclusion</h2>
<p>Using the PDO pattern, we have extracted the persistence code details
out of the Blog entity. This made Blog entity more object-oriented. By
decoupling its dependency (a database, in this case) from the entity, we
made unit-testing the entity much easier. Better unit-testing delivers
more reliable, extensible code and significantly improves the overall
design.</p>
Adobe Acquires Macromedia
2005-04-18T00:00:00-04:00
http://www.freshblurbs.com/blog/2005/04/18/adobe-acquires-macromedia.html
<p>WooooW\r <br />
\r \</p>
<p><a href="http://www.adobe.com/aboutadobe/invrelations/adobeandmacromedia.html">http://www.adobe.com/aboutadobe/invrelations/adobeandmacromedia.html</a></p>
Find 10 differences
2005-04-13T00:00:00-04:00
http://www.freshblurbs.com/blog/2005/04/13/find-10-differences.html
<p><img src="http://homepage.mac.com/inadarei/.Pictures/misc/frenchbrothers.jpg" alt="" />
\r \</p>
<p>On the left - Emmanuel Cecchet - Chief Architect for ObjectWeb, on the
right - Jean-Francois Arcand - Tomcat 5 Developer.\r \</p>
Tiger Countdown.
2005-04-12T00:00:00-04:00
http://www.freshblurbs.com/blog/2005/04/12/tiger-countdown.html
<p>17 days left…\r <br />
http://www.apple.com/\r <br />
\r <br />
Mac OS X Tiger will be released on April 29 - now official.</p>
Crashing Computer Programs
2005-04-12T00:00:00-04:00
http://www.freshblurbs.com/blog/2005/04/12/crashing-computer-programs.html
<p>“A crash is when your competitor’s program dies. When your program dies,
it is an ‘idiosyncrasy’. Frequently, crashes are followed with a message
like ‘ID 02’, ID is an abbreviation for idiosyncrasy and the number that
follows indicates how many more months of testing the product should
have had” - Guy Kawasaki</p>
White House Duck
2005-04-11T00:00:00-04:00
http://www.freshblurbs.com/blog/2005/04/11/white-house-duck.html
<p>Media (even international) has been covering that a duck made a nest in
front (actually at the back entrance) of the White House and WH security
built a fence for it, so that tourists do not bother the duck. <br />
<br />
One good thing about living in D.C. - you can walk down there and see
for yourself
<img src="/editor/fck/editor/images/smiley/rhymbox-1.0/smoker.gif" alt="" /> Which I
did. Actually, I went for the Cherry Blossom but since I was parked
nearby gave a visit to the duck, too, on my way back. Here\’s a photo
(sorry the duck was away at that time but I saw her on my way to the
Cherry Blossom - so the duck does exist
<img src="/editor/fck/editor/images/smiley/rhymbox-1.0/smile.gif" alt="" /> ): <br />
<br />
<img src="http://homepage.mac.com/inadarei/.Pictures/misc/BushDuck.jpg" alt="" /> \</p>
Cherry Blossom in Wash, DC 2005
2005-04-11T00:00:00-04:00
http://www.freshblurbs.com/blog/2005/04/11/cherry-blossom-wash-dc-2005.html
<p>Just couple of photos, for those of you who could not make to it: \</p>
<p><img src="http://homepage.mac.com/inadarei/.Pictures/misc/CherryBlossom05-01.jpg" alt="" />
<br />
\</p>
<p><img src="http://homepage.mac.com/inadarei/.Pictures/misc/CherryBlossomn05-02.jpg" alt="" /></p>
Clustered JDBC and interoperability on the JDBC level?
2005-04-08T00:00:00-04:00
http://www.freshblurbs.com/blog/2005/04/08/clustered-jdbc-and-interoperability-jdbc-level.html
<p>TSS has recently <a href="http://www.theserverside.com/talks/videos/EmmanuelCecchet/interview.tss?bandwidth=dsl">interviewed Emmanuel
Cechet </a></p>
<ul>
<li>the chief architect of ObjectWeb project. What seemed especially
interesting to me is the part where he talked about C-JDBC project: \</li>
</ul>
<p><a href="http://www.theserverside.com/talks/videos/EmmanuelCecchet/dsl/q10.html" title="click to load the video clip for this question">What is the clustered JDBC
project?</a></p>
<p>Clustered JDBC is a middleware to transparently cluster databases. It
means that you take your existing application running in whatever
application server you like and it\’s kind of a smart proxy at the JDBC
level that takes the query coming into the JDBC pipe and balances them
on a set of back ends, database back ends and replicates those databases
and providing high availability and scalability features by load
balancing those queries and providing check pointing, backing up, JMX
administration so that it can integrate within any application server
environment or Java environment in general.</p>
<p><a href="http://www.theserverside.com/talks/videos/EmmanuelCecchet/dsl/q11.html" title="click to load the video clip for this question">Why and when would an enterprise developer use this in their
architecture?</a></p>
<p>Either they start from scratch and they just want to provide more
reliability to their database and instead of having a single backend,
especially for small solutions who are using open source products you
just want to cluster the database and have a second replicate in case
one fails, you have maintenance to do on the backend and each time you
just want to scale the application then you have to add new backends to
this cluster. Usages, if you have a main Oracle database and you want to
make this database scalable, but you don\‘t have the money to buy new
Oracle license or a larger SMP machine, you can put a bunch of small
open source databases on the site and make a heterogenous cluster of a
main Oracle database and set up a virtual database to offload this main
Oracle database. That can make a lot of sense to make the existing
infrastructure to evolve and move smoothly to open source not by just
replacing existing legacy databases by a cluster of open source
databases but having a mix of heterogenous things and moving smoothly to
open source.</p>
<p><a href="http://www.theserverside.com/talks/videos/EmmanuelCecchet/dsl/q12.html" title="click to load the video clip for this question">Could you take Hibernate data application written using the
Oracle dialect and plug in clustered JDBC, how would that
work?</a></p>
<p>We use JDBCs to both Hibernate and we have demos available on the web
site running with Hibernate and to handle the value SQL dialect, C-JDBC
comes with rewriting that allows you to rewrite, for example Oracle
specific queries into new queries that would run and execute on MySQL
orPostgres or whatever databases you are on and we are also working on
extensions to rewrite tools, which will talk to us and which are much
more complex, not just single queries so that we can redefine work flow
of queries that you would like to execute and also backend those.</p>
Which FM Transmitter for your iPod?
2005-04-04T00:00:00-04:00
http://www.freshblurbs.com/blog/2005/04/04/which-fm-transmitter-your-ipod.html
<p>I have an iPod Mini and my car only has a CD-Player, no mp3 player.
Also, a lot of my music is in AAC format, nowdays, as I became a regular
on the iTunes music store. So, the obvious choice was to hook-up my iPod
Mini to my car stereo. Since I do not have a cassette stereo (the car is
too new for that archaism), I need an FM transmitter.\r <br />
\r <br />
I first tried Griffin iTrip Mini, because it was soooo advertised. IT
SUCKED. To set a channel, you need to install some stupid beeping
“audio” files on your iPod. Changing a channel (which you may need often
as almost all frequencies are used-up in modern cities) is a pain and
that “audio” channel files get in your way all the time, causing stupid
beeping in the middle of listening to your music. And yes - it managed
to block the HOLD switch, so I could not use it any more while iTrip was
plugged in. Overall - I HATED IT. I hated it so much - I gave up using
my iPod as my car stereo.\r <br />
\r <br />
Then, today, I got <a href="http://www.xtrememac.com/adapters/airplay.shtml">MacAddict
AirPlay</a> and I loved
it! That\’s the way it is supposed to be! It does not block my Hold
button, it does not need any installation (leave alone stupid audio
frequency files), it has a screen which shows me current frequency used
and if I will so - there are two buttons clicking which I can switch a
frequency in just a snap! And the same model works with all iPods
(regular, mini and even shuffle) - not true for the idiotic iTrip.\r <br />
\r <br />
Awesome! Highly recommended.\r \</p>
Tungsten T5 rocks.
2005-04-04T00:00:00-04:00
http://www.freshblurbs.com/blog/2005/04/04/tungsten-t5-rocks.html
<p>I\‘ve been wondering which handheld to get, for a couple of months,
now. Windows-based crap is out of question, of course. I got rid of the
Redmond parasites on desktop, why would I want it in my pocket?
Unfortunately, Apple does not produce handhelds, any more. Neither do
they show any sign to do so.\r <br />
\r <br />
So I was wondering, mostly, about the choice between different PalmOne
products: Zire, Tungsten and Treo. Treo has a huge advantage of being a
smartphone - you can plug you SIM card in and no need for a cell phone!
Both Zire and Treo have a built-in camera. Tungsten, on the other side,
has the largest, the best screen, higher CPU and is very slick and sexy
:)\r <br />
\r <br />
Being an aesthetics freak, I went for Tungsten T5. Could not resist its
cool look, Well, and, also - I do have a Nokia 6230 (which I have no
intention to get rid of), so that, kindof, makes up for what Tungsen
misses - I can connect Tungsen with my Nokia via bluetooth. I am using
Nokia 6210 driver, though. Hope to find the proper one for 6230.\r <br />
\r <br />
There are Wi-Fi extension slot for Tungsen and you can by a GPS package</p>
<ul>
<li>GPS Unit, windshield-holder, car-charger and TomTom software.
Considering that I already use TomTom (as a standalone car GPS system)
and totally love its software - that sounds very good to me. I guess I
am gonna buy the kit and get rid of the car GPS.\r <br />
\r <br />
Almost forgot: Tungsen T5 is fully compatible with Macs, comes with the
installation CD for Mac and lots of goodies on it. Well, not
surprisingly - Apple store is where I bought it :P :)\r <br />
\r <br />
P.S. There\’s IBM J2ME for Tungsten T5:
<a href="http://www.palmone.com/us/support/jvm/%20">http://www.palmone.com/us/support/jvm/</a>
(it also runs on the latest ZIre and Treo, tho)</li>
</ul>
Apple Sales People
2005-04-04T00:00:00-04:00
http://www.freshblurbs.com/blog/2005/04/04/apple-sales-people.html
<p>As much as I love everything Apple (yes, it is an addiction and a lethal
one) I can not stop “admiring” the level of stupidity of sales people at
the Apple Stores. Well, as usual - most of them, of course - it is
always unfair to trash people as a whole group, even if you are talking
about Apple Store sales guys :D One good thing I can say about them -
they still do not manage to suck as much as the Online Store morons, do
:)\r <br />
\r <br />
Anyways, yesterday I got fortunate to observe a very interesting
conversation between a store employee and a customer. The customer was a
hard-core PC guy, who, apparently, got interested in Macs and was
wondering if it made sense for him. Well, if you have ever been to an
Apple store, you know that it is hard to leave it untouched and if you
run into a really motivated person who can bullshit you (heh) for 20
minutes - you are done. Now, the Apple Store employee girl was none of
those (neither motivated, nor knowlegable) so the conversation was not
going as well as it should have and I kept watching it (yes, it is
unpolite) getting annoyed.\r <br />
\r <br />
At one moment the customer asked if there was a popup-blocker
available. The answer he got was “no, we do not need it because popups
come from spyware and there is no spyware on Macs”. Oh, God! First,
popups do not come from spyware, second - both Safari and
Mozilla/Firefox have popup blockers, OF COURSE! When the girl went on
and suggested the poor guy that he should buy .Mac account <strong>because it
comes with a free antivirus</strong> (well, THAT is really unnecessary) - my
heart could not take that much and I left…\r <br />
\r <br />
Duuuuuuuuuude, just because you have real cool sh..t does not mean that
people who sell them can suck badly!\r <br />
\r <br />
P.S. A friend of mine, recently, bought a new Powebook 15” and it
appeared to be defect. When she took it to the service store, they told
her - they are very surprised because, such thing has never happened in
their experience. Give me a f…in break! :D Never? So, how long have
they been there? Like one week? Ahhhhhhhhhhh\r <br />
\r <br />
\r \</p>
Interview with Jean-Francois Arcand
2005-04-03T00:00:00-05:00
http://www.freshblurbs.com/blog/2005/04/03/interview-jean-francois-arcand.html
<p>Jean-Francois Arcand, a Tomcat 5 developer has recently been
<a href="http://www.theserverside.com/news/thread.tss?thread_id=33041">interviewed by
TheServerSide.</a>.
It is very interesting, overall, but there were several things that
seemed strange to me.\r <br />
\r <br />
I have not used “embedded” feature of Tomcat but the impression, from
the interview, is that this just means there is an interface which
allows you to control Tomcat from your application.\r <br />
\r <br />
“Embedded” in the case of Jetty means much more - embedded Jetty is
just one JAR and you can use it as one JAR; it is very small, in size,
so you can really embed it into your application, without much
overhead.\r <br />
\r <br />
So, unless I misunderstood something, for the embedding (e.g. for
testing purposes, using as a Stub) Jetty, still, seems much more
convenient.\r <br />
\r <br />
On the same subject, for me personally, it was alerting to hear that
Jean-Francois has no idea about the embedding features in Jetty. That
may not mean much but is odd. People who have tendency towards the
re-invention of the wheel, do not usually invent good wheels. If you
begin work on embedding feature and there is a product that has that
figured-out, why would not you go and see how they did it? Maybe you
won\‘t do it the same way (most probably not) but at least - you should
look into it, should not you?\r <br />
\r <br />
Also:\r <br />
\r <br />
I was really surprised by one comment from the interview. The question
was if people should use Apache in front of Tomcat or run it as-is.
Jean-Francois made it sound like it is just a matter of performance and
almost suggested that Tomcat without Apache is just as good.\r <br />
\r <br />
NOT TRUE.\r <br />
\r <br />
Yes, Tomcat has gone long way in performance but that just proves the
point that: putting Apache in front of Tomcat is not a matter of
performance (performance may be the same) but _security_.\r <br />
\r <br />
To make Tomcat listen to port 80 you will need to launch it under root
user, which means your application code will also run under root.
That\’s _evil_. User applications should never run with root
privileges.\r <br />
\r <br />
When you put Apache in front of Tomcat (or any other servlet
engine/J2EE container, for that matter) your application can run under
an non-privileged user. That\’s much more secure.</p>
Velocity - A J2EE Developer's Dream Template Engine
2005-03-30T00:00:00-05:00
http://www.freshblurbs.com/blog/2005/03/30/velocity-j2ee-developers-dream-template-engine.html
<p>I do not know any developers that have created more than a couple web
applications in Java/J2EE and has not gotten frustrated by JSP. JSP
sucks - on all fronts! JSP is created to decouple presentation from the
program code but nobody except a programmer can handle JSP!!! It is
presentation for … programmers. Who wants it? It is ugly and limitted.
Just to name a few: tag can not be an attribute of another tag, you can
not easily load JSP from a JAR, JSPs need to be compiled, it is too
verbose and designers HATE it, is not friendly to any WYSIWYG HTML
editors.</p>
<p>Being frustrated, I was, naturally, looking to alternatives. First I
looked at Tapestry. As far as templating goes - it is nice, and smart.
But it is a full-blown MVC framework too. General rule - more
functionality tools take on them, more limitting they are, because
they enforce their “best practices” and that may not be the best way
always. Also, my current application is, already, written in Struts and
moving to or integrating with Tapestry, while possible, is going to
suck.</p>
<p>Going around and around, I finally, decided to take a deeper look at the
Jakarta Velocity. After all - I have heard too much of it and two tools
I use all the time - Confluence and Jira, both use Velocity - so WTH?</p>
<p>And….</p>
<p>Well, to put it short: writing templates with JSP and Velocity is like
writing your persistence with raw JDBC or using Hibernate. YES! That\’s
the kind of difference! Just like Hibernate, Velocity brings a huuuge
simplification, is highly extensible, flexible and leaves you space to
using alternatives, if you will so. Last but not least - it does
integrate with Struts, too.</p>
<p>I am very, very happy. I think my journey, in search for a good
templating engine has come to end and I found it - Velocity is the way
to go!</p>
<p>I can not, possibly, blog in more detail about a rich engine like
Velocity, but it\’s not necessary, either. There\’s a wonderful,
brilliant book about Velocity written by Rob Harrop - <a href="http://www.amazon.com/exec/obidos/tg/detail/-/159059410X/qid=1112185300/sr=8-1/ref=sr_8_xs_ap_i1_xgl14/103-2575119-8822262?v=glance&s=books&n=507846">Pro jakarta
Velocity</a>.This
book is how I learnt Velocity and there is nothing I could add to it.
Highly recommended</p>
<p> </p>
Major Political Figure Podcasting.
2005-03-29T00:00:00-05:00
http://www.freshblurbs.com/blog/2005/03/29/major-political-figure-podcasting.html
<p><a href="http://www.grumet.net/weblog/"> Andrew</a> has been working on PodCasting
(audio RSS feeds for iPod) for a while now. He
<a href="http://grumet.net/weblog/archives/2005_03.html">blogs</a> that John
Edwards <a href="http://www.oneamericacommittee.com/podcast.xml">has done a
podcast</a>. Yes, this is
the same Edwards that was running for vice-presidency under Kerry, just
several months back. <br />
<br />
This is MAJOR! Both for the Internet community+iPod community and the
US/World politics. <br />
<br />
WOW! Hope this is not the first and last (don\‘t think so). <br />
<br />
I am very excited to see how this thing goes. \</p>
ErraticTestFail?
2005-03-29T00:00:00-05:00
http://www.freshblurbs.com/blog/2005/03/29/erratictestfail.html
<p>Martin Fowler blogged about
<a href="http://martinfowler.com/bliki/">ErraticTestFail</a>. I can not say the
name is very descriptive :) but the problem is interesting. Such buggy
tests arise, mostly, from static mocks or stubs shared by several test
methods or cases. Now, ideally, your tests should be independent but
there is a performance tradeoff - sometimes initalization takes too much
time. The last thing you want - your test suite to take too much time
to run. That can lead to productivity degradation and the temptation of
running test suite less often or (oh, God!) - not at all. <br />
<br />
I think logic unit tests should be mocked enough not to need costly
initializations, so if it is true - the problem would arise, mostly, in
functional and integration tests. <br />
<br />
JUnit allows to reload the run of each test. You would, usually, have
it turned off for the performance reasons. But because of the
ErraticTestFail possibility, it is may be a good practice to: <br />
1) Run daily tests on an integration server where JUnit reloads for
each test run. Test may be fine-tuned to share setUp() and be faster but
they must be written so that if each test is ran in a new classloader -
they still work (even if slower). <br />
2) When and if you notice something suspicious (like Martin\’s case)
turn on reloading and see what happens, before you go on blaming your
IDE, compiler or whatever is easier to blame :) \</p>
The Problem with the Dependency Injection
2005-03-27T00:00:00-05:00
http://www.freshblurbs.com/blog/2005/03/27/problem-dependency-injection.html
<p>Sony Mathew has
<a href="http://www.theserverside.com/articles/article.tss?l=IOCandEJB">described</a>
the best my concern with the Dependency Injection (e.g. in Spring
Framework). I like it so much, that I think it is well worth quoting
here:</p>
<blockquote>
<p>“… externalizing an entire object graph seems over ambitious and
counter productive. This type of glue work is considered core
functionality and may be subject to business requirements and testing
procedures and exposing it as an untyped descriptor file can make the
application very brittle. Finally, this core functionality type glue
work should be reusable and extensible just like any other part of the
application that represents the business domain.”</p>
</blockquote>
CSS: Highlight Active Text Control
2005-03-27T00:00:00-05:00
http://www.freshblurbs.com/blog/2005/03/27/css-highlight-active-text-control.html
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><style type="text/css">
input:focus { background-color: #FFFF99 }
textarea:focus { background-color: #FFFF99 }
</style>
</code></pre></div></div>
How much RAM does your sneaker have?
2005-03-23T00:00:00-05:00
http://www.freshblurbs.com/blog/2005/03/23/how-much-ram-does-your-sneaker-have.html
<p>Whoa! Here goes the prize for the <a href="http://www.adidas.com/campaigns/adidas_1/content/usindex.asp?strCountry_adidascom=us&strBrand_adidascom=performance">dumbest shit of the
year</a>!
<br />
I never liked Adidas, anyway, but they have really, really outperformed
theirselves… but, not the way they think.</p>
<p>Listen, idiot, I DO NOT WANT MY SHOE TO HAVE A CPU, get it?</p>
<p>As a side comment: their promo-site SUCKS. It is one of the most
user-unfriendly and obscure sites, I have seen in a while. It gives
almost zero information about the benefits of their “innovation”…
well, which I kinda understand - I doubt there are any.</p>
<p>Mighty God, is the whole world going nuts, or (hopefully) is it just
the CEO of Adid <strong>ass</strong>?</p>
Kill Bill - which Bill?
2005-03-21T00:00:00-05:00
http://www.freshblurbs.com/blog/2005/03/21/kill-bill-which-bill.html
<p><a href="http://www.linuxos.sk/downloads/wallpapers/Kill%20Bill%201024.jpg">http://www.linuxos.sk/downloads/wallpapers/Kill%20Bill%201024.jpg</a></p>
Existentialism
2005-03-19T00:00:00-05:00
http://www.freshblurbs.com/blog/2005/03/19/existentialism.html
<p>“Life is what happens to you while you’re busy making other plans” -
John Lennon</p>
Protect yourself!
2005-03-15T00:00:00-05:00
http://www.freshblurbs.com/blog/2005/03/15/protect-yourself.html
<p>The Redmond company (a.k.a M$) has begun a new campaign, represented by
<a href="http://www.microsoft.com/h/en-us/i/ts_1024_5_SP2.jpg">this image
banner</a> on their
website.\r <br />
\r <br />
The truth is, in reality, you should read that banner, in a slightly
changed manner:\r <br />
\r <br />
<img src="http://ika.ge/img/MSswitch.jpg" alt="" /></p>
Cannabis formula.
2005-03-15T00:00:00-05:00
http://www.freshblurbs.com/blog/2005/03/15/cannabis-formula.html
<p>It seems that the formula of the cannabis has been <a href="http://www.livejournal.com/community/ru_drugs/732318.html?nc=22">figured
out</a>:\r
<br />
R:=(1+sin(t))(1+.9cos(8t))(1+.1cos(24t))\r <br />
\r <br />
Graphic of the function in polar coordinates:\r <br />
<img src="http://supman.rinet.ru/pics/cannabis_plot.gif" alt="" /> \r <br />
\r \</p>
Monitor, Control, Win
2005-03-07T00:00:00-05:00
http://www.freshblurbs.com/blog/2005/03/07/monitor-control-win.html
<p>Do not allow developers to sneak-in untested code:\r <br />
<a href="http://www.cenqua.com/clover/">http://www.cenqua.com/clover/</a></p>
Is the legendary Lines of Code - an objective measurement?
2005-03-07T00:00:00-05:00
http://www.freshblurbs.com/blog/2005/03/07/legendary-lines-code-objective-measurement.html
<p>Since I became a Mac-addict, I seem to be sturving to anything Apple.
Today, while wondering around the <a href="http://www.bordersstores.com/">Borders
bookstore</a> in Pentagon City, I ran into a
wonderful <a href="http://www.bordersstores.com/search/title_detail.jsp?id=54663949&srchTerms=revolution+in+the+valley&mediaType=1&srchType=Keyword">book about Mac
history</a>,
by Andy Hertzfeld, one of the “fathers” of the Mac. It is a great book,
with a great print quality for an amazing price, so I advice to get it
even to non Mac fans.\r <br />
\r <br />
Anyway, the book is about the software engineering, too, so I found
some interesting stuff in it, not directly related to Apple, so I
thought mentioning it. This particular one demonstrates that the Lines
of Code is a bullshit measurement. I know some may not need
demonstrations of that, and I, myself, think it is so obvious - I might
not bother to quote this large story, if not being a witness, couple of
weeks ago, how three of our team were seriously trying to measure effort
by “Lines of Code” and using some stupid “calculator” software. Seems
like, not everybody gets it, so here goes the real-life story:\r <br />
\r <br />
Page 65 of the book:\r <br />
\r <br />
“In early 1982, the Lisa software team was trying to buckle down the
big push to ship the software within the next six months. SOme of the
managers decided it would be a good idea to track the progres of each
individual engineer in terms of code they wrote from week to week. They
devised a form that each engineer was required to submit every Friday,
which included a field for the number of lines of code written that
week.\r <br />
\r <br />
Bill Atkinson, the author of QuickDraw and the main user interface
designer, who was by far the most important Lisa implementer, thought
lines of code was a silly measure of software productivity. He thought
his goal was to write a small and fast a program as possible, and the
lines of code metric only encouraged writing sloppy, bloated, broken
code.\r <br />
\r <br />
He had recently worked on optimizing QuickDraw\’s region calculation
machinery, and had completely rewritten the region engine using a
simpler, more general algorithm - which, after some tweaking, made
region operations almost six times faster. As a byproduct, the rewrite
also saved around 2,000 lines of code.\r <br />
\r <br />
He was just putting the finishing touches on the optimization when it
was time to fill out the management form for the first time. When he got
to the lines of code part, he thought about it for a second, and then
wrote in the number: -2,000\r <br />
\r <br />
I\‘m not sure how the managers reacted, but I do know that after a
couple more weeks they stopped asking Bill to fill out the form, and he
gladly complied.”</p>
Digi v2 - Simplify!
2005-03-07T00:00:00-05:00
http://www.freshblurbs.com/blog/2005/03/07/digi-v2-simplify.html
<p>The version 2 of Digi is going to be all about simplification and the
productivity of code-creation. Personally, I think, we have achieved
quite rich feature-support in version 1 and left place for bigger
enhancements to be possible. What we have come short (and I am not
surprised or disappointed as it\’s just version 1) is the
ease-of-development. So, now it\’s time to Simplify.\r <br />
\r <br />
As the simplifications go, there are two obvious things, in my mind:\r
<br />
\r <br />
1) Struts coding is too verbous. I would like to see more defaults
implemented in Digi, so that if you follow naming conventions (roughly:
your view file has the same name as your action class and form bean
etc.), in 80% of standard cases you would not need to write anything in
a struts-config.xml. For the rest 20% (or a large part of it) it would
be nice to have something simpler than a bloated XML config. For
example, <a href="http://incubator.apache.org/beehive/">Apache Beehive</a> looks
quite interesting for this task.\r <br />
\r <br />
2) JSP is a pain. We\‘ve had enough of it. I like Tapestry UI approach
much more. Let\’s see if we can painlessly swap it in.\r <br />
\r <br />
and I, also, want:\r <br />
3) Simplified module customization capabilities. Let\’s prove Oracle
dudes, that modules can be customized beyond the UI layer, and it is not
such a rocket-science.* The Proof of Concept code, we have, makes me
quite optimistic. Let\’s see…\r <br />
\r <br />
——————–\r <br />
*This is in regard with an Oracle session, held in Wash, DC, where
<a href="http://www.oracle.com/corporate/pressroom/html/tkurian.html">Thomas
Kurian</a>,
the SVP of Development, Oracle, told me that when they talk about
flexible customization features in Oracle portal suite, they just mean
the UI layer, by far, and beyond that - it is too complicated. This
reply has disappointed me as much as he seemed to have hated my question
:-)</p>
Functionality Test Tool from ThoughtWorks
2005-03-06T00:00:00-05:00
http://www.freshblurbs.com/blog/2005/03/06/functionality-test-tool-thoughtworks.html
<p><a href="http://www.thoughtworks.com/us/">ThoughtWorks</a> has been known for two
things: First, that\’s where the modern maestro and guru of Java -
Martin Fowler works at. Second, that\’s the creator of the
<a href="http://cruisecontrol.sourceforge.net/">CruiseControl</a> continuous
integration suite.\r <br />
\r <br />
Thoughtworks has delivered the third member of the trinity:
<a href="http://selenium.thoughtworks.com/index.html">Selenium</a> - an automated
functionality-testing engine for web-applications.\r <br />
\r <br />
Having such tool for a web-development greoup is priceless. I have been
pushing <a href="http://wemmick.blogspot.com">Doug</a> to buy a
<a href="http://www.segue.com/products/functional-regressional-testing/silktest.asp">SilkTest</a>
license, for quite some time, now. SilkTest has been one of the leaders
in the area. Unfortunately, Doug is being, for what seems to me, overly
cautious (I am not gonna say, “greedy” as he may read this post LOL.
Just kidding) sometimes so it never happened.\r <br />
\r <br />
Selenium is open-source. That\’s good news. I think it is, probabely
far from SilkTest, yet (just a guess, did not have a chance to look at
it, yet) but knowing ThoughtWorks, I guess it will not take them too
long to make it a nice tool.\r <br />
\r <br />
Wonderful! Considering that our QA-to-be guy will, probably, not know
neither SilkTest, here is a chance to adopt something for free (yeah, I
know it\’s not like “in beer”, but it usually is).\r <br />
\r <br />
Kudos to ThoughtWorks.</p>
Browsers supported by Ajax?
2005-03-06T00:00:00-05:00
http://www.freshblurbs.com/blog/2005/03/06/browsers-supported-ajax.html
<p>The new buzzword (well, not THAT new but…) on the Net is
<a href="http://www.adaptivepath.com/publications/essays/archives/000385.php">Ajax</a>.
It\’s like a web-developer\’s dream: “richer” client but with the
standard technologies. No plugin to install, just POS (Plain Old Stuff)
like: standards-based XHTML, CSS; XML, DOM and some XMLHttpRequest with
some Javascript. That\’s promising to deliver almost the same kind of
interactivity as <a href="http://www.macromedia.com/software/flex/">Macromedia
Flex</a>, for example, but with
the nice POS approach, rather than ad-hoc plugin from a single vendor.
Way better!\r <br />
\r <br />
Anyway, what is the list of the browsers supported? Well, Ajax is not a
technology, itself - it\’s a collection of them (see up) used in a
smart way, so it depends a lot on - how you use them, how smart you use
them. And yet, considering that Google Maps and Google Suggest are two
shining example of the “Ajax-way”, we can guess the answer, and here is
how:\r <br />
\r <br />
MS IE on Mac is the worst browser ever :) The reason why people use IE
on Windows is: it supports more “features” (all of them - non-standard,
the M$ way, of course) than other browsers so pages created in Windows
IE deliver “richer” experience. This is not quite true for Mac version
of IE. It does not have the same featureset on Mac that it has on
Windows. Actually it is quite poor and, IMHO, plain sucks. So, if we
open maps.google.com in Mac IE, we will get a Google response, saying
this browser is not yet supported, with the list of the browsers (Google
has always been polite enough!) that it does.\r <br />
\r <br />
And here is the list:\r <br />
\r <br />
*\tIE 5.5+ (Windows)\r <br />
*\tFirefox 0.8+ (Windows, Mac, Linux)\r <br />
*\tSafari 1.2.4+ (Mac)\r <br />
*\tNetscape 7.1+ (Windows, Mac, Linux)\r <br />
*\tMozilla 1.4+ (Windows, Mac, Linux)\r <br />
*\tOpera 7+ (Windows, Mac, Linux)\r <br />
\r <br />
This, IMHO, is a good approximation of the current compliance state of
so-called Ajax.\r <br />
\r <br />
Not bad, by the way, eh?</p>
Bookmars - shared
2005-03-06T00:00:00-05:00
http://www.freshblurbs.com/blog/2005/03/06/bookmars-shared.html
<p>I assume this thing has been around for a long while and I was living on
the moon for the last X months or years, but I suspect I may not be the
only one, and anyway, I often use my blog to mark interesting stuff, so
if I forget - I can come back and find quickly, so….\r <br />
\r <br />
Forget about that silly bookmark importer/exporter/whatevers :)\r <br />
\r <br />
http://del.icio.us/\r <br />
\r <br />
You can put your bookmarks online, easily so you can access them,
categorized, \r <br />
from anywhere. And you can, also, see what sites other people like
(that can\r <br />
possibly lead you to interesting ones, you never heard of) - can come
quite handy.</p>
Personal note to self about Security
2005-03-03T00:00:00-05:00
http://www.freshblurbs.com/blog/2005/03/03/personal-note-self-about-security.html
<p>While, in my never-ending arrogance (heh), I find the current Digi
security system quite robust and extensible, as well as, well-integrated
with the main JAAS principles, it is not enough.\r <br />
\r <br />
There are two things that were purposefully disregarded, in the rush of
providing the solution to those who needed it, and that should be
revisited. \r <br />
\r <br />
First is the Security API from the JSR-168. As much as I am sceptical
about the version 1.0 of any specification, JSR-168, in particular
(arrogance, again), for things like the security it may be beneficial
to, at least, consider being compliant. Well, if that does not harm,
more valuable assets.\r <br />
\r <br />
Second is the fact that if anything, security is the component/service
that would benefit from being as pluggable, extensible and de-coupled as
possible. While, it would be hard to clain that the current
implementation is rigid, Digi Security is still using only the plain-old
approach of coding to interfaces. There is space for more flexibility,
widely known as the introduction of the Dependency Injection techniques.
This could make things more de-coupled, with less code. \r <br />
\r <br />
From a quick glance and research, it seems that <a href="http://acegisecurity.sourceforge.net/">Acegi Security System
for Spring</a> is a good example of
employing DI techniques for a Security System implementation.\r <br />
\r <br />
As I do not have time for all these, right now, I am posting this as a
note (reminder) to myself here. Somebody thinking about improving
his/her own security system may, also, find this information useful.</p>
switch2mac
2005-03-01T00:00:00-05:00
http://www.freshblurbs.com/blog/2005/03/01/switch2mac.html
<p>After annoying <a href="http://wemmick.blogspot.com">Doug</a> for several weeks to
convince him get a Macintosh, he came up with a <a href="http://wemmick.blogspot.com/2005/02/can-i-switch-marketing-application.html">great
idea</a>
for how to allow current Windows users objectively assess if switch to
Mac is going to be a pain for them.\r <br />
\r <br />
\r <br />
\r <br />
The idea seemed very attractive, so in the best traditions of the Rule
of Thumb of Programming (“if you do not like something - write it
yourself”), we opened <a href="http://sourceforge.net/projects/switch2mac/">a sourceforge
project</a> to write a program
like that. I am really curious to see how it goes.</p>
Error-free code from thedailyWTF
2005-03-01T00:00:00-05:00
http://www.freshblurbs.com/blog/2005/03/01/error-free-code-thedailywtf.html
<p>One of my recent assignments has been to come up with a presentation for
our software engineers about the benefits of using unit-testing in their
code and demonstrating how it should be done properly. Easier said than
done. How can you explain, to inherently, professionally lazy people, in
an hour and 20-30 pages of Powerpoint (or Apple Keynote :P) things that
are mostly intuitive and come only with <strong>experience</strong>, as well as from
reading a whole bunch of books + examples and then doing it every day,
for each piece of code?\r <br />
\r <br />
It\’s been a real challenge and I was still thinking if I should give
up, when I ran into this wonderful piece of code on
<a href="http://thedailywtf.com/ShowPost.aspx?PostID=22954">TheDailyWTF</a>: \r <br />
\r <br />
<img src="http://www.thedailywtf.com/images/10/o_TryTrim.gif" alt="" /> \r <br />
\r <br />
and everything became clear! Hell with JUnit, forget about Cactus, who
cares about Mock Objects? God bless try-catch.\r <br />
\r <br />
My presentation is going to be just one page with the screenshot of
this code and a large, stupid smile to go with it.\r <br />
\r <br />
Seriously, you can not write more error-proof code, can you? ;)\r <br />
\r <br />
:)</p>
Eclipse + JBoss IDE rulez!
2005-03-01T00:00:00-05:00
http://www.freshblurbs.com/blog/2005/03/01/eclipse-jboss-ide-rulez.html
<p>I have first tried Eclipse 2 years ago, and totally hated it :) Since
JBoss released its integrated JBoss IDE package, based on Eclipse, it
has become interesting, again and I installed them on my Mac. It has
become especially important as my Mac Mini, as much as I love it, does
not have much resources and an IDE that goes easy on resources is
good.\r <br />
\r <br />
I was very impressed with JBoss features. You can smoothly launch and
debug your web application inside the IDE itself. Yes, I have used
similiar features in both JBuilder and InteliiJ IDEA (this one is
definitely not for a limited-resources machine like Mini, if you are
working on a large server application) but the truth is - they are
nowhere close to what JBoss IDE can provide. Just change a line of code
in your java files, you do not even need to explicitely rebuild if
everything is set up correctly, refresh page - and you will see your
changes. No server restart, no hussle!\r <br />
\r <br />
rulzzzzzzzzzzzzzzzzzzzzzzz\r <br />
\r <br />
I guess I am gonna stick with JBoss IDE/Eclipse from now on (and until
something better appears -if, heh).</p>
SSO in Java
2005-02-28T00:00:00-05:00
http://www.freshblurbs.com/blog/2005/02/28/sso-java.html
<p><a href="http://java.net">java.net</a> has recently published an article by
Gianluca Brigandi about Single Sing-On integration in Apache\’s Pluto
Portlet container. He shows how to provide Single Sign-On functionallity
in Pluto using <a href="http://www.josso.org/">JOSSO</a>. You can read the article
<a href="http://today.java.net/pub/a/today/2005/02/18/josso.html">here</a>\r <br />
\r <br />
One significant feature that brings JOSSO out, shining with glory, of
the several alternatives is that it is “Cross-platform: It allows for
the integration of Java and non-Java applications, such as PHP or
Microsoft ASP applications. It uses the standard SOAP over HTTP as the
standard communication layer to deliver this cross-platform feature.”\r
<br />
\r <br />
The only remaining questions are: performance and security. To my
inexperienced eyes, this looks like an MS Passport-alike solution and,
if I am not wrong, MS Passport service is being abandonned by Microsoft
for the lack of security. If that is true, will JOSSO share the same
fate, in the future?</p>
Interview with the self.
2005-02-17T00:00:00-05:00
http://www.freshblurbs.com/blog/2005/02/17/interview-self.html
<ul>
<li>Hi \</li>
<li>Hey \</li>
<li>So, you have had a Macintosh for some time now. How do you feel about
it? \</li>
<li>I think it is very sexy. \</li>
<li>Yeah? \</li>
<li>Absolutely. The one I have is a Mac Mini. It gets so much attention,
from everybody who sees it, if it was your wife, you should get jealous
or she should divorce you. \</li>
<li>Well, that’s just a slick-looking box. How big deal is it? \</li>
<li>Huge. This “box” is lighter than my Compaq laptop used to be. It is,
definitely, quiter and cooler. I put it in my backpack and carry to
work, so I do not need to deal with M$ crap, at work, either. That’s a
big deal once you get used to a Mac… \</li>
<li>Speaking of that. What’s this addiction you guys have with Macs? Lack
of apples when you were kids? \</li>
<li>Well, we touched the coolness of the hardware a bit, but mostly - it
is the software. Mac OS X is great. \</li>
<li>Why? \</li>
<li>To begin with - it is beautiful. Some people may enjoy the simplicity
of black screens with green letters (and you do not even get much of
that on Windows) but I want the interface, that I spend a huge part of
my day with, to be attractive, nice and kind on my eyes. Call me an
aesthete. \</li>
<li>Well, beauty is a relative term… \</li>
<li>Yes, but most of the people do agree on what UGLY means. Also, Mac OS
X is very, very intuitive and easy to use. It takes me much less time to
do the same on Mac, compared to Windows, leave alone Linux. I like when
things are done the way I would want them to be, not the way some
bighead wanted somewhere up in the state of Washington. \</li>
<li>Fair enough… \</li>
<li>Well, also, I find it very convenient not to be afraid of “spyware”,
“viruses”, “trojans” and all kind of dirt like that. I do not want to
spend my time haunting them, neither do I want my top-notch computer to
suddenly become a slowly crawling, half-dead beast. \</li>
<li>You mentioned Linux… It is quite resistent to the “dirt”, too, no?
\</li>
<li>You know… If anybody is a supporter of open-source, that’s me. If
anybody admires Linus Torvalds and the whole community behind Linux - I
do. But, seriously - Linux is not a desktop OS, yet and I do not see
when will it become one. I tried switching to Linux several times. Even
managed to stay there whole of 3 weeks. It sucks. And not so much that
you almost have nothing there - OpenOffice is nowhere near a decent
office, media support is less than good etc, etc, etc - you may get away
with that, if you try real hard. The point is very simple - every minute
that I spent on Linux, as my desktop, I was missing Windows UI, and when
I finally gave up and returned to Windows - I was literally experiencing
pleasure of working as a normal human, not some shadow-headed geek. It
is a shame how crappy X11 is, considering how long it has been around.
Neither KDE or Gnome add anything valuable to it - just more bugs and
uglier design.</li>
</ul>
<p>On the contrary - every minute I spend with Mac OS X, I feel literal
pleasure to be working with a responsive, intuitive, beautiful, smart
system. I never, even for a second, had a desire to go back to Windows
and at several occasions that I had to work with Windows, on other
people’s computers, it really felt unpleasant and wrong. Once you go
Mac, you do not want to go back.</p>
<p>And Mac OS X has wayyyyyyyy better support than Linux, for sure.
Consider drivers, programs - anything, the situation is much better than
for Linux. I also find it very amazing that a Mac feels much more
comfortable in Windows networks than even Windows computers :) You gotta
admit - most of us have to deal with WinNet at work and this
compatibility is a big deal.</p>
<ul>
<li>Well, that was some speech :) Don’t even know what to ask next. \</li>
<li>Don’t, get a Mac and get a life. Gotta go now. Take care. \</li>
<li>Hm, thanks… <br />
:-)</li>
</ul>
Democracy?!
2005-01-18T00:00:00-05:00
http://www.freshblurbs.com/blog/2005/01/18/democracy.html
<p>Democracy is the worst kind of government. Except for all the others. -
Winston Churchill</p>
The real "Bioinformatics"
2005-01-15T00:00:00-05:00
http://www.freshblurbs.com/blog/2005/01/15/real-quot-bioinformatics-quot.html
<p> DNA for decryption:
<a href="http://www.baselineresearch.net/PI/">http://www.baselineresearch.net/PI/</a></p>
Layers to decrease the complexity?
2004-12-15T00:00:00-05:00
http://www.freshblurbs.com/blog/2004/12/15/layers-decrease-complexity.html
<p>First off, take a look at <a href="http://groovy.codehaus.org/">Groovy</a>, if you
have not done so, yet. <br />
It is real nice. <br />
<br />
Then, what I am thinking these days is - should I even mention using it
to our development team? I mean, for God\’s sake we already have so
many layers, I am sure, half of our programmers do not even know how to
properly use what we already have. So, how can adding a new layer help
that? Can it?</p>
<p>Which leads me to the thought that - sometimes we add layers to add
simplicity to other layers, instead of making the initial ones simpler,
which would make everybody\’s life simpler. No?</p>
Language List in all languages
2004-11-21T00:00:00-05:00
http://www.freshblurbs.com/blog/2004/11/21/language-list-all-languages.html
<p>Got the link from <a href="http://grumet.net/weblog/">Andrew</a> :\r <br />
<a href="http://people.w3.org/rishida/names/languages.html">List at w3c</a>\r <br />
\r <br />
Pretty useful.</p>
Bad smell for Gates
2004-11-16T00:00:00-05:00
http://www.freshblurbs.com/blog/2004/11/16/bad-smell-gates.html
<p>Former Microsoft exec Nat Brown joins open-source company\r <br />
\r \</p>
<p><a href="http://www.zdnet.com.au/news/software/0,2000061733,39166791,00.htm">http://www.zdnet.com.au/news/software/0,2000061733,39166791,00.htm</a></p>
List of Bluetooth Profiles
2004-11-11T00:00:00-05:00
http://www.freshblurbs.com/blog/2004/11/11/list-bluetooth-profiles.html
<p>Personal memo: <br />
dial-up networking for connecting to the internet and email (DUN),
file transfer (FTP), Fax (FAX), personal area network (PAN), hard copy
replacement for printing (HCRP), LAN Access (LAP), object push for
uploading to your phone (OPP), personal area networking (PAN), serial
port (SP), audio for headsets (HSP) and human interface device for
wireless keyboards and mice (HID)</p>
Going bluetooth wireless
2004-11-11T00:00:00-05:00
http://www.freshblurbs.com/blog/2004/11/11/going-bluetooth-wireless.html
<p>It is possible to use a Bluetooth headset with your
non-bluetooth-enabled phone and it is cheaper than getting a new,
expensive cellphone. You will have to connect a-quite-large adapter to
your phone, though but if you need the wireless headset for car-use,
that should work: \</p>
<p><a href="http://ai.pricegrabber.com/product_images/3295000-3295999/3295915_125.jpg">http://ai.pricegrabber.com/product_images/3295000-3295999/3295915_125.jpg</a></p>
Analyze memory leaks in Java:
2004-11-09T00:00:00-05:00
http://www.freshblurbs.com/blog/2004/11/09/analyze-memory-leaks-java.html
<p>Analyze memory leaks in Java:\r <br />
http://www.mernst.org/ariadna/</p>
Quad processor Xserve?
2004-11-06T00:00:00-05:00
http://www.freshblurbs.com/blog/2004/11/06/quad-processor-xserve.html
<p>Powerpage: “The PowerPage has received word that Apple is prepping a
quad-processor Xserve for announcement in the January-March 2005 time
frame. We are working to confirm details but sources say that the the
Quad Xserve will be powered by dual-core IBM 970 processors. More as we
find out…” <br />
<br />
Source:
<a href="http://www.powerpage.org/cgi-bin/WebObjects/powerpage.woa/wa/story?newsID=12539">http://www.powerpage.org/cgi-bin/WebObjects/powerpage.woa/wa/story?newsID=12539</a>
<br />
<br />
See more about XServes at: \</p>
<p><a href="http://www.apple.com/xserve/performance.html">http://www.apple.com/xserve/performance.html</a>
<br />
and \</p>
<p><a href="http://www.apple.com/xserve/cluster/">http://www.apple.com/xserve/cluster/</a></p>
Pseudo Capitalism vs Open Spirit
2004-11-05T00:00:00-05:00
http://www.freshblurbs.com/blog/2004/11/05/capitalistm-vs-open-spirit.html
<p>Found this quote kinda late, but I still love it :)</p>
<blockquote>
<p>“If Darl McBride was in charge, he’d probably make marriage
unconstitutional too, since clearly it de-emphasizes the commercial
nature of normal human interaction, and probably is a major impediment
to the commercial growth of prostitution.”</p>
<p>– Linus Torvalds, December 5th 2003.</p>
</blockquote>
<p>P.S. Darl McBride is the CEO of SCO :)</p>
Spring Web Flows
2004-11-01T00:00:00-05:00
http://www.freshblurbs.com/blog/2004/11/01/spring-web-flows.html
<p>Loved the Spring Web Flows: \</p>
<p><a href="http://www.ervacon.com/products/springwebflow/article">http://www.ervacon.com/products/springwebflow/article</a>
<br />
<br />
Here\’s another headache for me: I can not ditch Struts from Digi and
just jump on Spring MVC and Flows. Too many lines of Digi modules code
would have to be rewritten.</p>
<p>But what if we manage to marry those two? Why not? We are not that
concerned about Struts purity in Digi, anyway - as far as basic
compatibility is there and a developer feels comfortable. Anyway, it
would be interesting. Don\‘t think Struts folks would mind an idea like
that, too. To get some Struts Flow in place?</p>
<p>hm</p>
ORM or not to ORM
2004-10-31T00:00:00-04:00
http://www.freshblurbs.com/blog/2004/10/31/orm-or-not-orm.html
<p>This was also posted at:
<a href="http://www.theserverside.com/news/thread.tss?thread_id=29140#144480">http://www.theserverside.com/news/thread.tss?thread_id=29140#144480</a></p>
<p>The lengthy discussion, at that thread, itself - shows that this topic
is not a simple one and there are plenty who take one or another side.</p>
<p>The liberals say: “it is a matter of choice and depands on what are your
goals in a specific project”</p>
<p>Is it,really?</p>
<p>For me, there are two major criterias to assess the quality of a program
code <br />
1) (Almost) No code duplication <br />
2) Shortest source code providing the same result.</p>
<p>I do beleive that these are not just my personal choices. I think those
two criterias have proven to indicate to a reusable and maintainable
(!!!) code.</p>
<p>Do not forget - the life of a code begins ONLY after it is deployed to
the production environment and you have to maintain it! Until that -
it\’s all jokes and fun. That\’s when the real thing begins and when
it starts to HURT.</p>
<p>Thesis: Maintainability and Scalibility are the key!</p>
<p>So, then why do I hate SQL in my code? Because, working in Java - my
business logic is object-oriented. You can _not_ create a
well-designed Java application which is not OO. OK, my business logic is
OO but then - I need to use SQL??? But all these data-models and queries
that I need to construct separately - THEY DUPLICATE MY OO LOGIC!!!
That\’s code-duplication! Also, I do have to write all that SQL
manually, even though I already have the same in my Java code, so source
ain\‘t gonna be the shortest! And - every time I change my Java code, I
need to change SQL queries and table structure, too. Damn!</p>
<p>Who will argue that this does hurt both maintainability and scalability?</p>
<p>How do I modify my code with Hibernate? My persistence meta-information
is in XDoclet form right in my Java-code. I do not write anything extra,
outside the pure Java code. When I change something in the Java-code, I
run my nice ANT task, which goes through the changed persistence
configuration (auto-generated using XDoclet) and using Hibernate Schema
Update, does ALL the necessary changes in the database. All I do is:
type “ant database”.</p>
<p>For me, a Java architect, Database is a persistence layer. Why should I
have Business Logic (!) in a persistence layer? I don\‘t want to know
ANYTHING about my persistence layer, except that it stores data
persistently. My business logic should have NOTHING to do with it!</p>
<p>This is why I would hate to see SQL in my Java code and as far as my
thesis, above, holds - I can not be wrong.</p>
<p>But DB-centric advocates, also, have a “winning” argument, don\‘t they?
What was that - “PL/SQL provides better performance”?</p>
<p>Well, we have worked with it, ok? :) PL/SQL can be damn slow, too! So
there is no win - any DB access, via ORM, direct SQL or PL/SQL can be
slow enough (usually is) to be too slow. That\’s why we have cache
layer.</p>
<p>Well, good news - my ORM framework - Hibernate allows me to integrate
different cache frameworks (from JBossCache to the wonderful - Tangasol
Coherense) transparently. So, I do not have to worry about that, either,
do I?</p>
<p>And in addition to all these - I can get RDBMS-independance, if I am
careful enough. If my client suddently decides Oracle is too expensive,
or new client comes that needs MySQL - here we go - I just smile
slightly and say “sure, no prob!”.</p>
<p>Does not that feel great?</p>
<p>And last but not least - Nobody is trying to diminish the importance of
SQL! ORM tools are using SQL behind the scenes - that\’s what they do
and I beleive Hibernate is the most popular exactly because Gavin made
it as SQL-friendly as possible. But it needs proper usage, that\’s all!</p>
SilkTest - do not ignore!
2004-10-18T00:00:00-04:00
http://www.freshblurbs.com/blog/2004/10/18/silktest-do-not-ignore.html
<p>Just stating the obvious, here, but unfortunately it’s also something that many teams miss:</p>
<blockquote>
<p>Code Refactorings should be happening <strong>continously</strong></p>
</blockquote>
<p>Refactoring cannot be something that is scheduled or aligned
with the QA process – waiting to manually retest a system after
each change. Refactoring should happen every day, lots of times per day.
There is no other way to the quality code.</p>
<p>But how do we make sure refactoring does not change (damage) existing functionality? TESTS.</p>
<p>We are all, more or less, clear the JUnit tests are just one part of the tests
to be written, functional testing should also be automated. No
way it can happen as frequently as it is needed when doing it manually! Automating
functional testing is a big deal.</p>
<p>There are tools for that, too. Like this nice one:</p>
<p><a href="http://www.segue.com/products/functional-regressional-testing/silktest.asp">http://www.segue.com/products/functional-regressional-testing/silktest.asp</a></p>
PHP + Java integration
2004-10-03T00:00:00-04:00
http://www.freshblurbs.com/blog/2004/10/03/php-java-integration.html
<p>I am getting more and more inclined to think that an idea of successful,
pure-J2EE architecture is like Communism - too good to be true. To
implement a perfectly designed J2EE architecture (assuming it can be
designed as such) a perfect imlementation team is needed. Do we ever get
such? And if we do - does not it cost too much? <br />
<br />
I guess the point here is to simplify. Simplicity has long been known
as the best choice. Java front-end is not simple - oh, NO! We all know
what is simple and best - PHP. It\’s not so theoretically, it has been
proved by years of successful experience of the immense amount of
people. But.. PHP does not have enough muscle, Java does. So, why not
use each of them where they are at their best? PHP - Frontend, Java -
middle tier. Especially that JCP is already looking into it: \</p>
<p><a href="http://www.jcp.org/en/jsr/detail?id=223">http://www.jcp.org/en/jsr/detail?id=223</a>
<br />
<br />
The only question is - is PHP ready for this? I am not sure. <br />
<br />
Well, maybe in the next project :) \</p>
Don't bug me!
2004-10-03T00:00:00-04:00
http://www.freshblurbs.com/blog/2004/10/03/dont-bug-me.html
<p>The <a href="http://www.mailinator.com/">mailinator</a> has been making my life on
the Web more pleasant, for a long time, now. Here comes the second nice
creature: <a href="http://bugmenot.com/">http://bugmenot.com/</a>, which I\‘ve
learnt about from <a href="http://wemmick.blogspot.com/">Doug\’s Blog.</a> Thanks,
Doug!</p>
Redirect after Get
2004-09-28T00:00:00-04:00
http://www.freshblurbs.com/blog/2004/09/28/redirect-after-get.html
<p>Nice article \</p>
<p><a href="http://www.theserverside.com/articles/article.tss?l=RedirectAfterGet">http://www.theserverside.com/articles/article.tss?l=RedirectAfterGet</a></p>
Solaris going open-source.
2004-09-22T00:00:00-04:00
http://www.freshblurbs.com/blog/2004/09/22/solaris-going-open-source.html
<p>Phewwwww \</p>
<p><a href="http://www.eweek.com/article2/0,1759,1647198,00.asp?kc=EWRSS03119TX1K0000594">http://www.eweek.com/article2/0,1759,1647198,00.asp?kc=EWRSS03119TX1K0000594</a></p>
Windows Script Decoder.
2004-07-17T00:00:00-04:00
http://www.freshblurbs.com/blog/2004/07/17/windows-script-decoder.html
<p><a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=e7877f67-c447-4873-b1b0-21f0626a6329&displaylang=en">Windows Script
Encoder</a>
from Redmond is distributed as an IP-protection tool. Yet, even on the
MS site, it is clearly noted that the tool can only obfuscate a script
from a “casual viewer”, not from a hacker. I would wonder - why create a
tool like that, at all, then? But the Redmond-based company has always
been so good at producing an-actually-hacker\’s tools and presenting
them as something usefull. The way this tool is used the most, IMHO, is
by the trojan-authors, especially email-trojan specialists, obfuscating
their stupid VBscript crap.</p>
<p>Anyway, if you recieve a rubbish like that in your email box and are
curious enough to wonder what the code actually was, there is a
decryptor you can download and use (now, this one is, actually, useful
different from its counterpart from Redmond): \</p>
<p><a href="http://www.virtualconspiracy.com/scrdec.html">http://www.virtualconspiracy.com/scrdec.html</a></p>
<p>Tested - tool works just fine.</p>
<p>P.S. I wonder what qualifies as being a “hacker” for Microsoft? Finding
this tool or being able to run it?</p>
<p>P.P.S I do not care about warning you that you should not use this tool
on the copyrighted scripts and using it for reverse-engineering. First -
because it is your problem, then - because copyrighted material is
protected neverthless if it is encrypted or not, third - I am not sure
using the stupid tool from MS even qualifies as encryption, hence where
is the “reverse-engineering” in there?</p>
<p>enjoy</p>
Obscure but useful
2004-07-09T00:00:00-04:00
http://www.freshblurbs.com/blog/2004/07/09/obscure-useful.html
<p>I, personally, liked the PDF manipulation project: \</p>
<p><a href="http://www.theserverside.com/discussions/thread.tss?thread_id=27192">http://www.theserverside.com/discussions/thread.tss?thread_id=27192</a></p>
Permission to Fly.
2004-07-07T00:00:00-04:00
http://www.freshblurbs.com/blog/2004/07/07/permission-fly.html
<p> </p>
<p>“Aircraft in position. Requesting permission to fly”</p>
<ul>
<li>from the radio transmission of a flight captain with an air traffic
controller.</li>
</ul>
<p> </p>
<p>Software projects are like the airplane flights. What users see is just
the end-result of the work done by a group of professionals. Users may
have a clue but do not really care to understand the immense amount of
work put into building the airplane, training pilots, flight-attendants,
airport personnel, engineers who make sure that plane is fully ready for
each flight. The only thing that really matters begins when the aircraft
rolls out of the boxes, prepares for the flight and takes off. Anything
else is just the preparation for that important task. There are no
excuses during the flight - everything has to be perfect.</p>
<p> </p>
<p>What does a software project need to take off and have a successful
flight? We often focus on building the plane,itself; We have even got
used to calling the process - Engineering and come up with fancy names
like Software Architect, Designer yadda, yadda, yadda. But, is a good
plane enough for a successful flight? No, it is not. The actual journey
only begins after the take-off and that is something a lot of projects
forget. Alas, most of the projects, never even get into the air,
rolling, or rather crawling, on the earth like a cheap van.</p>
<p> </p>
<p>Merciless laws of Physics are very clear - in order to fly, plane must
reach enough speed and turn its nose to the high skies, at the right
moment. How many times have we seen a software project rolling on the
earth too long, reaching a dead end and crashing or having to turn
around and begin the everything from zero miles per hour? Knowing when
it is time and having enough guts to head up is the key to flying.</p>
<p> </p>
<p>But getting into the clouds is just the beginning of the journey. What
happens once we are up there? Everybody takes orders from the flight
captain. There is no democracy in the air - the captain is an absolute
dictator, the success of the whole flight depends on his decisions and
he himself relies on the capable crew. When you are up in the sky - you
really want each person to be the best of the best - any mistake is too
expensive. What do we see in most of the software projects? Average
developers, average QA, average analysts. And sometimes average is
something we wish for – a lot of the times, the people you get are the
ones you get and you need to do the best with what you’ve got.</p>
<p> </p>
<p>Would you rely on such a crew in the air? Would you entrust life of two
hundred plus people to just average personnel or even worse - whatever
you\‘ve got? How come the software that drives lives of thousands is
less important? Is it, really?</p>
<p> </p>
<p>When and how did the legendary Time to Market has become more important
than the quality? How could we allow business people dictate when the
project is ready to take off and how the plane should fly? Did we
carelessly diminish the importance of the software project lifecycle,
comparing it to building and architecting constructions that can be
half-finished, re-modeled later or sold as a cheap alternative? Why do
we have so many “programmers” but when we need the real ones, they are
always hard to find? Why do so many software projects fail? Have we ever
heard of airline manager ordering a flight captain to take half-ready
plane in the air, for the sake of some “Time to Market”?</p>
<p> </p>
<p>Why are open-source projects producing better software? Is it because of
the less intrusion of remorseless Business? Is it because, in the
open-source projects, only people who prove themselves useful are kept
and there is no place for those who “we\‘ve got, so let\’s think, now,
what to do with them”? Is it because there is much less space for the
bureaucracy in the open-source projects? Or is it all just a myth?</p>
<p> </p>
<p>The questions, and answers they lead to, are arguable, maybe, but when
there is a question - there is uncertainty. Uncertainty allows, some of
us, afford thinking a little bit differently. Maybe, just maybe,
building and publishing software is more than just constructing
buildings of bricks; maybe we have put the technology into too tight
chains of business? Maybe we have hurried too much declaring software as
another commodity?</p>
<p> </p>
<p>Maybe… But one thing is clear - we need permission to fly. We need a
confident captain and a capable crew. Aircraft is in position and we are
requesting permission to fly - maybe it will be too late afterwards.</p>
<p> </p>
Protection from Mailinator.
2004-06-21T00:00:00-04:00
http://www.freshblurbs.com/blog/2004/06/21/protection-mailinator.html
<p>I have been a big fan of <a href="www.mailinator.com">Mailinator</a>. Not only it
helped me with the annoying sites that beg for registration and then
bomb with spam but it was invaluable in the debugging of our system when
I needed new email accounts to test functionality on production. \r <br />
\r <br />
From the news on their site I knew that, actually, The Mailinator Guy
has something else to offer a Java developer -
<a href="http://www.preemptive.com/products/dasho/index.html">DashO</a> -
Obfuscator + optimizer. They say Sun and RSA use it in critical
applications. Impressive indeed… that if I was not an open-source
developer :-) But then - you never know, do you? heh</p>
XML Button with CSS
2004-06-06T00:00:00-04:00
http://www.freshblurbs.com/blog/2004/06/06/xml-button-css.html
<p>If you want to style a button link to look like XML icon,
you can use the following stylesheet</p>
<div class="language-css highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="o"><</span><span class="nt">--</span> <span class="nt">from</span> <span class="nt">style</span><span class="nc">.css</span> <span class="nt">--</span><span class="o">></span>
<span class="nt">a</span><span class="nc">.button</span><span class="nd">:link</span> <span class="p">{</span>
<span class="nl">font-weight</span><span class="p">:</span> <span class="nb">bold</span><span class="p">;</span> <span class="nl">color</span><span class="p">:</span> <span class="no">white</span><span class="p">;</span>
<span class="nl">font-size</span><span class="p">:</span> <span class="m">10px</span><span class="p">;</span>
<span class="nl">font-family</span><span class="p">:</span> <span class="n">Verdana</span><span class="p">;</span>
<span class="nl">background-color</span><span class="p">:</span> <span class="m">#FF6600</span><span class="p">;</span>
<span class="nl">border-left</span><span class="p">:</span> <span class="m">1px</span> <span class="nb">solid</span> <span class="m">#FF9A57</span><span class="p">;</span>
<span class="nl">border-top</span><span class="p">:</span> <span class="m">1px</span> <span class="nb">solid</span> <span class="m">#FFC8A4</span><span class="p">;</span>
<span class="nl">border-right</span><span class="p">:</span> <span class="m">1px</span> <span class="nb">solid</span> <span class="m">#7D3302</span><span class="p">;</span>
<span class="nl">border-bottom</span><span class="p">:</span> <span class="m">1px</span> <span class="nb">solid</span> <span class="m">#3F1A01</span><span class="p">;</span>
<span class="nl">padding</span><span class="p">:</span> <span class="m">2px</span> <span class="m">5px</span> <span class="m">1px</span> <span class="m">4px</span><span class="p">;</span>
<span class="nl">margin</span><span class="p">:</span> <span class="m">0px</span> <span class="m">0px</span> <span class="m">0px</span> <span class="m">0px</span><span class="p">;</span>
<span class="p">}</span>
<span class="nt">a</span><span class="nc">.button</span><span class="nd">:hover</span> <span class="p">{</span>
<span class="nl">text-decoration</span><span class="p">:</span> <span class="nb">none</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Screenshot: <img src="http://www.freshblurbs.com/files/Picture%208.png" alt="" /></p>
New Design
2004-06-06T00:00:00-04:00
http://www.freshblurbs.com/blog/2004/06/06/new-design.html
<p>Changed design. Hopefully - for the better :)</p>