text:
Well, the Atathualpa theme has served me well since I first migrated my blog to WordPress from Slashcode (yeah, crazy). However we live in a new world now, with a growing majority of web traffic coming from mobile devices. It's time I got with the times and used a responsive design theme. So I've made a switch to the TwentyFifteen theme. I'm going minimalist for now, and will likely bring modifications back in as I see value.
Jetpack Broke My Comments
So apparently "JetPack Comments" broke my comments, causing recent comments to get posted to the wrong thread. They claim it's not their fault, saying that it's due to a lack of implementation of the comment_form() function in WordPress, but Atahualpa seems to support this just fine. Well, anyhow, for now I'll be disabling JetPack Comments on my blog. So if you want to comment, you'll have to sign up. I know. It's a pain. I'll get it fixed.
Update 6/10/2015: After switching themes to TwentyFifteen, the problem seems to be gone. JetPack Comments re-enabled.
Adfree Breaks Pinterest on Android
If you're like me, you like keeping your Android device screen free from ads. AdFree from BigTinCan is an invaluable tool in assisting with this by customizing your hosts file on a rooted Android phone so that any ad network links get redirected to your phone, effectively disabling ads. The side effect of using host-based ad blocking is that sometimes valid sites get blocked as well.
"I don't always do Pinterest, but when I do, I prefer pinning homebrew stuff." And unfortunately, Adfree blocks pinning on Android. You'll notice this when doing any pin outside of a re-pin (ie, within your pin feed). The app will churn saying it's finding images, but then finally fail with the popup error "Sorry, couldn't find any pinnable images on this page". The issue is that the Pinterest app requires access to a few hostnames that Adfree hijacks:
- api.pinterest.com
- assets.pinterest.com
- log.pinterest.com
This solution to this is fairly simple. Thankfully, BigTinCan offers an option to set up a customizable exception list but of course you'll have to register for a free account. Once you have registered, add exceptions for each of the hosts above. Then sign in to your account on the AdFree android app and update your hosts. You should now be able to pin to your heart's content.
Let me know if this helped you!
Pebble Smartwatch Skins
One of my biggest beefs with the Pebble is the plastic case. These guys have a solution to not only the scratchability of the case, but the plain black style. The woodgrain one looks really nice, and is probably the one I would go with if I were to get a Pebble.
AHK Script to Clean Up Dead PuTTY Sessions
I have a love-hate relationship with tabbed interfaces. On one hand, they keep my taskbar clean. On the other, they merely scuttle my window-hoarding behaviors into a single window, where the mess grows into a pile of outdated, unused tab sessions (i.e., Firefox). I also have need for some types of programs to be opened in separate windows on a regular basis, such as SSH sessions, where I often work on multiple related tasks which have to be monitored simultaneously. In those instances, the number of PuTTY sessions I have open (and have disconnected) can quickly grow out of control, clogging my taskbar.
Here's a quick script I wrote to clean up any inactive/disconnected PuTTY windows: Cleanup PuTTY Windows
Fix for Chromecast "No Cast devices found"
Every so often I run into a Chromecast user who says they can't get their PC to find their Chromecast. More often than not, it's due to a bug in how the Chromecast plugin handles multiple network connections. The Chromecast plugin assumes that your primary active network connection is on the same LAN as your Chromecast dongle. Obviously this is not always the case, especially in the case of VPN users. What you have to do is move that connection to the top priority in your network connection list.
Here's how you fix the dreaded "No Cast devices found" issue. This is for Windows 7, but probably works with 8 and Vista as well:
1) If you are connected to a VPN, disconnect it and try detecting the Chromecast again. Still not working? Proceed...
2) Go to the Network and Sharing Center
3) Click "Change Adapter Settings"
4) Click the Advanced menu and select "Advanced Settings..." (Alt+N, S)
5) Find the network connection that shares the same LAN as your Chromecast and select it
6) Repeatedly click the green up arrow until that connection is at the top of the list.
7) Click OK to close the dialog and apply the new connection priority settings
8) Try detecting your Chromecast again
If you use a VPN, you may be wondering why you have to disconnect. The answer is that many VPN clients manage the connection priority of the virtual adapter they create and automatically moves it to the top of the list. It's best just to disconnect and try again instead of battling that behavior.
Good Luck! I hope this helps someone out there!
If you found this helpful, maybe you'd like to send a thank you from my wishlist?
Brewblog: All-Grain Bavarian Hefeweisen (Northern Brewer)
Just a quick update on my homebrewing adventures.
Finally got around to doing my first AG brew using my new mash tun, using the Northern Brewer Bavarian Hefeweisen kit. The crushed grain sat in my garage for a couple weeks, then got tossed into the kegerator for storage for the next 4-5 months. Hopefully the grains didn't go stale and affect the flavor of the malt. As this was my first AG experience, I had a slight hurdle with the volume of the strike (?) water. I was attempting to do the more complex multi-step protein/saccharide rests, and may have started out with far too much water. Thus I ended up with about 9 gallons of liquid that needed to be boiled down to ~5. I still don't fully understand what grain/water target ratio I should be using at mash-in. Needless to say, I burned off a good amount of propane just boling off those 4 gallons of excess liquid.
I'm unsure of how to properly calculate mash tun efficiency, however what I do know is that the listen target for original gravity was 1.049, and I ended up with 1.046. I was hoping for higher, as I did rinse the grain pretty well (or so I thought), and by comparison, my experience with the extract version of this kit has resulted in an OG of as high as 1.052. The comparison might not be valid though.
Fermentation was very active, as usual, finishing up it's frothy activity within the first 36-48 hours. This time around I didn't have any issues with blowoff.
So, with any luck, I should have a perfectly drinkable beverage in just under 4 weeks. Now to figure out where to re-fill my 10# CO2 cylinder.
Here's my current brewhouse/pub status:
On deck: Pumpkin Ale (Indie) Primary: Bavarian Hefeweisen (Northern Brewer) Secondary 1: Empty Secondary 2: Empty Keg 1: Tapped-out Keg 2: Tapped-out Keg 3: Tapped-out Keg 4: Tapped-out
HowTo Resolve StartSSL (StartCom) Domain Blacklisted: Domain appears on a blacklist
Does this look familiar to you?
Welcome to my world. Not sure at this point how I got on this list, how to get off it, or even where this list is. But perhaps my findings will help you resolve the same issue for your domain. At this point, my suspicion is that it's due to and odd report from Google Safe Browsing that "Yes, this site has hosted malicious software over the past 90 days. It infected 0 domain(s), including .". It would be great if I knew what the malware/badware is/was so that I could remove it. Even more odd is that my supposed infection infected no other sites.
Oh well. More to come...
Update: I've emailed "Certmaster" and they responded letting me know that they see my domain on Google's Safe Browsing blacklist results. Oddly enough, here are the results:
I see the report that "Yes, this site has hosted malicious software over the past 90 days. It infected 0 domain(s), including ." What's odd about this is that when I check my Google Webmaster tools, the site reports that "Google has not detected any malware on this site.", and it seems I'm not the only one. Not sure if I'm just bitten by a previously unseen issue that I've since cleaned up with WordPress updates or what.
Given the date that is shown above (2013-05-04), I'd guess that the "past 90 days" implies I'll have to wait until 2013-08-04 for this status to clear. I guess that's the penalty I pay for lack of diligence in monitoring the updates and health of my server up until then. If you're saying to yourself "I can't wait that long!", you do have the option of paying StartSSL the fee required for them to manually intervene in what would otherwise be an automated process. I choose to wait it out: I don't really need SSL for anything practical. For my purposes, it's just for the sake of writing articles like this: research and writing howto's based upon my experiences. So I'll be waiting out the presumably prerequisite "90 days" for the sake of research.
See you on 8/4 with an update!
Update 8/15: As the saying goes: "Time heals all wounds". I'm now off the naughty list for Google. Now to (re-)try obtaining a cert from StartSSL...
Accidental Evangelist
It's been a while since updating my blog with anything overtly Catholic. I guess work, family, and life in general started to consume far more of my time in last several years. Non-geek-related posts have been sparse to non-existent. It's been bothering me some privately in recent months with elections coming, and now gone. There's so much topical matter to cover, and unfortunately, most of it gets posted to Facebook where my audience is limited (and intentionally so).
If been feeling that, as a result, I haven't been doing a very good job of being an active evangelist for Catholicism. It's been taking a back seat to being charitable with my technical knowledge. I've gained a lot of knowledge from peers in the past 15+ years, and this blog is one of the ways I like to "pay forward" that generosity.
Which brings me to this blog article by Creative Minority Report: Accidental Evangelism.
I think my sense of charity directly, and most specifically a personal impressibility to be actively charitable stems from my Catholic upbringing. I'd could only hope that some person reading this blog would be converted (at least in part) by my actions.
May God bless, and the grace of God be with you!
Solution to the NVidia Gray/Grayscale Screen Problem
Today I came in to work to find that the video output for my Dell Latitude e6520 laptop's NVidia head was displaying in black and white. At first I thought that the problem was a driver bug, something wrong with the video memory, or a faulty display. But eventually I found out that, somehow (without any user interaction with the applicable setting), the "Digital Vibrance" setting was set to 0%, when it should be 50%. Below you'll see a simple annotated screenshot showing where you can quickly fix this.
Good luck!
Streaming RTMP with VLC and RTMPDump
This quick post is as much for your benefit as for the benefit of my memory...
To stream RTMP with VLC, you'll need rtmpdump, which you can get here: http://rtmpdump.mplayerhq.hu/. I used rtmpdump-2.4-git-010913-windows.zip, though you may be able to use the latest version. I also had VLC 2.0.6 32-bit installed. Once installed, you can run the following from a cmd window:
rtmpdump.exe -r "rtmp://your.domain.com:1935/yoururl/here" -v -o - | vlc.exe -
This worked nicely for me. YMMV. Good luck!
If you found this helpful, maybe you'd like to send a thank you from my wishlist?
FFMPEG "Server error: Not Found" with Short URLs
Just a quick post about a problem I helped a buddy of mine resolve. He was setting up a Helix media streaming server, and was trying to capture the stream data to a file with the following command:
ffmpeg -i "rtmp://10.132.245.4:1935/flash/meet.flv" out.flv
The result was this error in the output:
[rtmp @ 0x28e1dc0] Server error: Not Found
Oddly enough, the connection information shown on the Helix console showed that a strange URL was being requested. Upon further investigation with Wireshark, I found that this was the request being made.
Note that "\360" is a hex character. For some odd reason, it would appear that ffmpeg improperly handles short URLs, inserting a string of "\360xw0". If you pad the URL with the current directory "./", then the request succeeds:
ffmpeg -i "rtmp://10.132.245.4:1935/flash/./././././meet.flv" out.flv
This results in a request of
Which worked fine in our environment.
For future reference, I was running this ffmpeg version (on CentOS 6.4 x86_64):
ffmpeg version N-53616-g7a2edcf Copyright (c) 2000-2013 the FFmpeg developers
built on May 29 2013 00:19:54 with gcc 4.4.7 (GCC) 20120313 (Red Hat 4.4.7-3)
So if you're running into the "Server error: Not Found" error on a known good URL, try padding the path of the stream with "./" and see if that fixes it for you. I'm guessing this is an ffmpeg bug, but don't really have the access to a streaming server to troubleshoot and submit a bug report. From the time that I did have, it appears that it's related to the .flv extension in the rtmp URL. If you drop the extension, the URL can be of any size.
Brewblog: Rubbermaid 50 Quart Mash Tun
After several months of lingering in my garage, I finally finished my 50 qt. Rubbermaid mash tun. The cooler I used is the one shown below:
I picked it up at my local Menards for about $30. You should be also able to find them at Walmart for about $40. I chose this cooler because I've purchased a few of them over the past years, so I know they'll likely be making them for a while. Also, the design is relatively easy to build a mash tun manifold for. And, according to this chart, I should be able to make up to 10 gallons of wort comfortably in there, allowing me to eventually make double batches.
The manifold is a design that I came up with, and eventually I'll get around to actually measuring and posting dimensions of the piping so you can build one too. I used under 8' of copper pipe for it, and should have enough length left over to eventually build a fly sparge manifold (or at least a start on it). The design relies on two lengths of bare copper wire to hold the whole thing together, and two small segments of tubing at the back of the cooler keeps the manifold securely wedged in position. I'm not averse to soldering, or even all that concerned about contamination from the silver-based solder. My main reason for going solderless is to make it easy to clean. I can literally disassemble the entire manifold into individual components, ready for a thorough brushing if desired.
Recovering the PPP Username and Password from a Centurylink Actiontec C1000A
Some time ago I wrote up a similar procedure to recover a password from an Actiontec M1000 back when Centurylink was known as Qwest (gotta love rebranding). Back then, Actiontec left the operating system a bit more open, actually placing the PPP credentials in a flat file in /var/tmp/. Nowdays, Actiontec tries to obfuscate/encrypt the password in a config XML, making it just difficult enough for most people to give up on the idea of recovering the password.
In addition to this, it would appear to the casual telnet console user that the commonplace busybox shell had been removed or made inaccessible, removing the ability to peer into the embedded linux operating system underneath, and replacing it with a stripped-down properietary shell with limited commands. However, dig a little deeper by trying the undocumented "sh" command, and you'll find that busybox is alive and well on this device, exposing the configs and services that support the router's functions. Since the configs contain the encrypted password, we can't directly extract them from there, however fortunately for us, pppd (the service that authenticates and creates the DSL connection) requires the password to either be kept in plain text in a flat config file (not the case here) OR have the password specified on the command line. The "ps" command on these devices has been handicapped to only display 80 columns, leading to output similar to this:
1623 admin 1144 S pppd -c ppp0.1 -D 0 -i ptm0.0 -u "your___username@qwe
At first, when I saw this, I figured it was another dead end, until I realized that "/proc/(pid)/cmdline" displays the command line of any running process. And fortunately for us, Actiontec left "pidstat" enabled in busybox, making reading those command line arguments fairly simple with a single command:
> sh -c "/usr/bin/pidstat -l -C pppd"
Linux 2.6.30 ((none)) 05/23/13 _mips_ (2 CPU)
14:59:38 PID %usr %system %guest %CPU CPU Command
14:59:38 1623 0.00 0.01 0.00 0.01 1 pppd -c ppp0.1 -D 0 -i ptm0.0 -u "firstname.lastname@example.com" -p "AbCDEfgH" -f 0 -k -P "AbCDEfgH" -M 1492
And there you have it! In this case, I've altered the password output (shown as AbCDEfgH) to protect my own privacy, but it'll look similarly like jumbled letters and numbers on your command line. Also note the "@qwest.net" username. Qwest used to be the LEC in my area, and likely the transition hasn't been made to the newer branding in the back-end systems. Your situation may be different.
Also, in case you hadn't figured it out by now, you're going to need telnet console access. My modem's console admin password was not the default "admin", nor the admin password listed on the box. I had to log into the web UI, enable remote console, and (re)set the console password. After that, you should be able to log into the telnet console with "admin" and the password you've set.
Lastly, one might ask "Why would I want to obtain this password?". My personal reason is that eventually I want to replace this leased modem with one I've purchased, and use it in transparent bridging mode (using RP-PPPOE to terminate the PPPoE connection and it's leased static IP on my firewall). When that day comes, I'd like to be able to do the swap without interacting with Centurylink. Call them by whatever new brand they've been changed to, Ma' Bell is always a pain to talk to.
Good luck to you!
If you found this helpful, maybe you'd like to send a thank you from my wishlist?
Pitfall-Free Howto/Guide to StartCom/StartSSL Class 2 Organization Validation/Certification
...in just three not-so-simple steps.
A couple quick notes before we begin: I threw this article together over a period of weeks, so the layout is a bit... odd. At some point I'll come back to this article and clean it up, however for now, I think it does the job of conveying the process to a new StartSSL user. Also, I use the names "StartCom" and "StartSSL" interchangeably, so don't look any deeper into the name usage than that.
A few weeks ago, I started the process of renewing several StartCom certs for my employer, and started to become familiar with the processes and pitfalls of identity and organization validation with StartCom. After delving into the process head-first, it became evident that this might not be as straight-forward as one might expect. However, I think that once you know what to expect, the process should go much more smoothly.
Also, please note that this how-to merely documents what I did to get a cert, and what pitfalls I ran into along the way. Therefore, your requirements and path may (and probably will) vary from mine. For instance, the tax document I submitted was a "State of Delaware Annual Franchise Tax Report". This document lists all of the items shown on StartCom's requirements. Your document(s) may not.
First, let's understand the steps required in obtaining Class 2 Org validation. Basically, you keep escalating your level of validation, providing increasingly trusted levels of personal and organization documentation as you go. Here's a rough outline:
- Get Email Address validation with StartSSL (free)
- Sign up
- Validate email
- Get personal client cert (for browser) via website
- Back it up!!!
- Get Personal Class 2 validation (~$60)
- Submit 2 forms of ID
- 1 Photo ID (i.e.: Driver's license)
- 1 other form of ID. May be photo (i.e.: Passport), OR non-photo (i.e.: birth certificate)
- AND submit either:
- Phone bill showing your name, current address, AND (most importantly) phone number.
- May be land line or cell
- Request for certified mail validation
- Delivery will take ~2.5 to 5 weeks (from Israel)
- If expedited service is required, you may additionally request express mail (~4-5 bus. days) for approx $30.
- Delivery will take ~2.5 to 5 weeks (from Israel)
- Phone bill showing your name, current address, AND (most importantly) phone number.
- Wait for call or letter, and verify provided code on StartSSL website control panel.
- Submit 2 forms of ID
- Get Organization Class 2 validation (~$60)
- Submit tax document which contains:
- Name of CEO
- Names of Directors
- Co. Address (not sure if this is an actual requirement)
- Co. Phone number (not sure if this is an actual requirement)
- AND submit StartSSL's "Delegate Authorization Letter" (https://www.startssl.com/authorization-letter-class2-organizational-validation.pdf) with:
- Your name, title as delegate
- Name and signature of CEO, President, or Director (CFO also appears to work. Other C?? titles may suffice)
- Have your signatory receive a phone call from StartCom to verify your authorization.
- Submit tax document which contains:
- Validate your domain(s)
- Perform the "Domain Name Validation" validation wizard for each new or expiring domain
- Confirm validation using code sent to email
- Generate Certs
- Perform the "Web Server SSL / TLS Certificate" certificate wizard
- Only new/expired certs or certs expiring within 2 weeks may be renewed (when the existing cert is with StartCom)
- Generate password-protected key / cert pairs
- Keep that password safe and backed up!
- Save key to .key file, cert to .crt file (ie, wildcard.mydomain.com.key, wildcard.mydomain.com.crt)
- Perform the "Web Server SSL / TLS Certificate" certificate wizard
- Install Certs
- Decrypt (strip password protection from) key file
- Place decrypted key and crt files on webserver
- Configure Apache SSL
- Reload Apache
- Verify correct cert in web browser
- ???
And now for the more elaborate explanation:
1) Get your email address set up, and obtain a website authentication certificate. This is free. Go to the Control Panel and click Sign Up. Fill out the forms and submit. Soon you should receive an authentication code via email. You will submit this to the StartCom site, and then wait for another email that has a verification link, which you'll click. Once that's done, you'll get a personal client certificate for your browser. Follow the instructions in the email/website on how to backup this certificate. Don't skip this! Think of this as cert the key to your account. If you lose it, you're likely going to have to a hard time regaining access. Back it up to an external storage medium (perhaps even encrypted as well - TrueCrypt is good for this).
2) Get yourself a Class 2 validation. This will cost you ~$60 (with one potential caveat, described below). This is where things start to get more complex. You'll need two scanned or photographed forms of documentation that prove that you exist, AND a means of verifying that the person submitting the documentation is actually you. For the two forms of identification, one must be a photo ID (afaik), and another can be another photo ID (such as a passport) OR something that simply proves you exist, such as a birth certificate (this is what I used). Submitted photos/scans must be of "high" quality, but less than 1400x1400 resolution. The second half of this, and this is where I got hung up, is the verification that the person submitting the information is YOU. StartCom apparently trusts phone companies, because you "just" need to submit an invoice/bill showing your name, address, and phone number. This can be either a scan/photo or a PDF. This is where I got hung up. My current cell service is not in my name, and I have Ooma VOIP for home phone service, which doesn't do traditional paper or PDF invoicing. Attempts to submit website screenshots, or PDFs of a webpage will likely be rejected. StartCom needs to be able to verify that you own the number you say you do, and then call you at that number to verify that you submitted the request (presumably with a code conveyed by voice, then submitted to the StartCom website). In lieu of a verified phone number, your next/only option is a registered mail letter from StartCom (in Israel). They claim this takes 3-5 business days. That may be true if you lived in Israel. I live in the US. Internet rumor has it that this letter takes ~5 weeks to get to the US destinations. I'll see if one of my letters end up taking this long (see update below... took ~2 weeks). The alternative is to request express mail delivery, which costs ~$30. This will take approximately 4-5 business days. I opted for this to expedite the process. Once you receive the letter, it will contain a code which you submit via the StartCom website control panel. Shortly after, StartCom should send you confirmation that you have been personally Class 2 verified.
3) Get your Organization Class 2 verified (another ~$60). This part is still in progress for me. I will be updating as I go along. First step appears (at least for now) that I have to obtain a yet-to-be-identified tax document from our finance/accounting department that proves that our company is recognized to exist by either the State or the US. Also, it's not clear if I, as an employee of the company, can submit the tax documentation and as a result get access to create these certs, OR do I also need to submit an authorization form that delegates me to make cert changes on behalf of the company. Sure would be nice if StartCom would clear some of this up on their website, or at least on their forums.
More on this as the mystery unfolds...
Update 5/28: A few updates
- Today I received my initially-requested snail-mail letter from StartCom. The letter was requested late on the 10th, so that means it takes 14-16 postal days (Mon-Sat) to get to Minneapolis, MN. But of course, YMMV.
- In the case of my company, the tax document used was a Delaware Annual Franchise Tax Report (as the company is incorporated in Delaware). Your document will almost surely be different. My recommendation is to ask your accountant or executive for a copy of the Articles of Incorporation applicable to your state.
- Unless you are the CEO, President, or a Director of the company/org you are applying for, you'll need to fill out the StartSSL Delegate Authorization Letter, printed on company letterhead, and have one of the aforementioned individuals sign it. Currently I'm attempting to use our CFO's signature to see if that is sufficient. If not, I'll be going to CEO to get the required signature.
Update 6/4: Eventually I got a signature from our CFO. I submitted the document to StartCom, and within a few hours I got an email back they they were unable to reach anyone at the listed office number. Presumably they tried to contact our CFO. I asked them to try again, and soon after got an email stating that the Class 2 Org Validation is complete! Once that was done, I was able to log into the StartCom control panel and perform Domain Name Validation(s) for each of our domains. It appears they offer a number of hostmaster/postmaster addresses as options to send a validation email to your domain. In addition to our other TLD's, they offered hostmaster@our_main_domain.com. Not sure how they linked them to our main corporate domain (possibly public WHOIS data), but they did. Up next, cert generation!...
Update 6/7: This ended up being the most straightforward process of the entire adventure. In my case, the web service in use was Apache. This process will likely vary for an MS-based/IIS server. Once your domain(s) is/are validated, you can go back into the StartSSL control panel, go the the certificates wizard, and select "Web Server SSL/TLS Certificate". Set a password for you keyfile and generate the key. Keep good tabs on this password as it's what decrypts your private key for use on your webserver. Save the resulting key text out to a file named something like "wildcard.mydomain.com.key". Continue on and select your domain, and enter/add your subdomain(s) or subdomain wildcards as needed (see notes below regarding restrictions). Once the cert is generated, save the text into a file named something like "wildcard.mydomain.com.crt". Keep these files safe and backed up!
A few other notes related to this: Note that a subdomain wildcard only applies to the level of that wildcard. So for instance, *.mydomain.com would cover test.mydomain.com, byt not test1.test2.mydomain.com. For that, you need to specify wildcards for each recursive level, ie *.test2.mydomain.com. Also note that domains that still have active StartSSL certs (or are not expiring within 2 weeks) are not able to be renewed. If you must renew them, you must revoke the existing cert, which costs approx $25. Be aware that you could still generate certs for individual specific (sub)domains instead to avoid going through the revocation process.
You can now proceed to install the cert on your webserver, however note that hte .key file is password protected/encrypted. You must strip the password in order to allow your web service to start up unattended. Here's a quick command to do that:
openssl rsa -in wildcard.mydomain.com.key > wildcard.mydomain.com.decrypted.key
You can then take the decrypted key and use it in your Apache config. Please note however that you must take care to restrict access to your server so that your private key is not copied by unauthorized persons. They alternative to this is to leave password protection on, but intervene manually by entering in the password each time Apache is (re)started.
So there you have it! At some point I'll probably come back to this article and clean it up. For now, I just wanted to get the information out there to help my fellow interweb users. Good luck!
Routed OpenVPN HOWTO
This is my OpenVPN HOWTO. There are many like it, but this one is mine.
It seems every few months I get asked the question by one of my friends "How do I set up a VPN?". Sometimes the person is looking to set up a MS VPN variant, other times, OpenVPN. The principles and concepts seem simple to me, now, however for someone new to VPN architectures and perhaps even routing, it can be confusing. This is my attempt to make the mysterious understandable. Since roadwarrior (individual laptop clients) configs are fairly well documented by the official OpenVPN wiki, I'll concentrate on a simple routed, LAN-to-LAN VPN networking concept, and cover roadwarrior config as an afterthought.
My weapon of choice distro-wise is CentOS, however these instructions could be applied to any other distro (ie, Ubuntu) with a basic understanding of your particular platform's networking configuration methods. Really, OpenVPN can run on just about anything, including Windows, if you feel so inclined. However, you'll probably get the most bang for your buck (free) using Linux. In my test environment, running stock CentOS 6.4, I had the scenario below running on a server with less than 90MB of total system memory usage.
Why CentOS?
I have two main reasons for promoting the use of CentOS:
1) CentOS is based upon RedHat Enterprise Linux (RHEL), which currently enjoys status as the most vendor-supported OS in enterprise environments. Translation? Knowledge of an RHEL derivitaves like CentOS is marketable skill to put on your resume. Yes, Ubuntu is gaining popularity in tech circles, but still doesn't compare to RHEL for vendor support. There's a reason both VMWare and Citrix use RHEL derivitaves as their baremetal OS.
2) CentOS has long-term-support (LTS). I've used Fedora for years, and I enjoy(ed) playing with some of the bleeding-edge features it offers. But the bleeding edge is on a double-edged sword. Fedora has a relatively aggressive release and support schedule. Install Fedora X, and expect that Fedora Z will replace it in about a year, leaving version X effectively without support. This gets to be a pain when you need to "yum update" your system just a year or so after you installed it. CentOS however has a support schedule that will ensure you likely have updates for far more years than the lifecycle of your hardware. For example CentOS 6, released in 2011, reaches EOL in late 2020. That's almost 10 years of support, on a free platform!
First, let's diagram the network we are going to design:
Remote Office 1 (10.101.0.x/24)
VPN Tunnel (10.200.101.1/30)
Main Office (10.100.0.x/24)
VPN Tunnel (10.200.102.1/30)
Remote Office 2 (10.102.0.x/24)
For this guide, we're going to assume you want all remote offices to have routing enabled to each other (via the Main office).
Note that the IP addresses above are just for example. You could create your own IP addressing scheme with FAR better utilization of the the private address space. The subnets I have used (ie 10.200.x.x/16) are just for increased clarity.
Each OpenVPN server/endpoint can have one interface (assuming you are doing NAT/firewalling elsewhere on your network), OR you could have dual interfaces: One on the LAN, the other on the WAN/Internet connection. It's up to you depending on where you want to do your firewalling. For the purposes of this guide, we're putting the VPN server behind another firewall.
On your firewall
Forward UDP port 1194 for your external internet connection to the internal IP of your VPN servers/endpoints, ie:
Main Office 10.100.0.5:1194
Remote Office 1 10.101.0.5:1194
Remote Office 2 10.102.0.5:1194
If for some reason UDP/1194 were blocked by your ISP, you could switch to something like TCP/80, but for the purposes of this guide, we'll stick with the default UDP/1194.
On each server/endpoint
Install your base OS. I chose to just install CentOS 6.4 minimal installation with the default options. Once installed, get networking set up and run
yum update
and get everything up-to-date.
Install the EPEL Repo configs
yum install http://download.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm
Turn off the built-in firewall (remember, we're using a 3rd party device for this). You could leave it on, but then you'd have to configure it to pass traffic to/from your VPN tunnel interface. I'll leave that up to you to figure out should you choose to do so.
chkconfig iptables off ; service iptables stop
Install the OpenVPN packages and dependencies:
yum install openvpn
Server (Main Office)
Copy the the easy-rsa environment to /etc/openvpn/easy-rsa, do some config prep, and alter the vars file
cp -rp /usr/share/openvpn/easy-rsa/2.0 /etc/openvpn/easy-rsa
cd /etc/openvpn/easy-rsa/
cp -rp vars vars.orig
cp -rp openssl-1.0.0.cnf openssl.cnf
vi vars
Go down to "KEY_COUNTRY" and edit the Country, Province, etc, down to the OU, ie:
export KEY_COUNTRY="US"
export KEY_PROVINCE="MN"
export KEY_CITY="Minneapolis"
export KEY_ORG="Muchtall"
export KEY_EMAIL="firstname.lastname@example.com"
export firstname.lastname@example.com
export KEY_CN=vpn.mydomain.com
export KEY_NAME=MuchtallOpenVPNServer
export KEY_OU=Muchtall
Now generate your server's certificate authority:
. ./vars
Accept the defaults for the prompts (we already set them)
Now build the server key
./build-key-server vpn.mydomain.com
Similar to above, accept the default prompts. You will have to answer "y" to the questions "Sign the certificate? [y/n]:" and "1 out of 1 certificate requests certified, commit? [y/n]"
Now generate certs/keys for each remote site
./build-key remote-office-1
./build-key remote-office-2
Rinse, repeat on the prompts.
And generate the Diffie-Hellman parameters:
Great! Our certificates are all set up!
Next time you want to generate a new client key, just run
cd /etc/openvpn/easy-rsa/
. ./vars
./build-key remote-office-3
Now, let's set up the configs. There's a sample config at /usr/share/doc/openvpn-2.2.2/sample-config-files/server.conf, however we're going to set one up using this template, just to keep things simple:
port 1194
proto udp
dev tun
ca easy-rsa/keys/ca.crt
cert easy-rsa/keys/vpn.mydomain.com.crt
key easy-rsa/keys/vpn.mydomain.com.key
dh easy-rsa/keys/dh1024.pem
server 10.200.0.0 255.255.0.0
ifconfig-pool-persist ipp.txt
# Tell clients that we can handle routes for these networks
push "route 10.100.0.0 255.255.0.0"
push "route 10.101.0.0 255.255.0.0"
push "route 10.102.0.0 255.255.0.0"
client-config-dir ccd
# Tell OpenVPN that it routes for anything within these subnets
route 10.101.0.0 255.255.0.0
route 10.102.0.0 255.255.0.0
keepalive 10 120
status openvpn-status.log
verb 3
Now create the ccd directory
mkdir /etc/openvpn/ccd
And lets create the client-specific configs to route each individual subnet to the respective site:
# In /etc/openvpn/ccd/remote-office-1
iroute 10.101.0.0 255.255.255.0
# In /etc/openvpn/ccd/remote-office-2
iroute 10.102.0.0 255.255.255.0
Good? Good!
Normally, IP subnets for the tunnels are allocated as new tunnels connect to the server. Let's pre-set the IPs for each tunnel. This part isn't necessary, however I like to do this to assist with clarity in troubleshooting with traceroutes. In /etc/openvpn/ipp.txt:
And re-set the SELinux permissions on the ipp.txt file
restorecon -v './ipp.txt'
Now we're ready to start the the OpenVPN service up:
service openvpn restart
Check the syslog to see if anything serious got spit out:
tail -100 /var/log/messages
You should see something similar to this:
May 7 14:54:53 mainoffice openvpn[13362]: OpenVPN 2.2.2 x86_64-redhat-linux-gnu [SSL] [LZO2] [EPOLL] [PKCS11] [eurephia] built on Aug 10 2012
May 7 14:54:53 mainoffice openvpn[13362]: NOTE: the current --script-security setting may allow this configuration to call user-defined scripts
May 7 14:54:53 mainoffice openvpn[13362]: Diffie-Hellman initialized with 1024 bit key
May 7 14:54:53 mainoffice openvpn[13362]: TLS-Auth MTU parms [ L:1542 D:138 EF:38 EB:0 ET:0 EL:0 ]
May 7 14:54:53 mainoffice openvpn[13362]: Socket Buffers: R=[229376->131072] S=[229376->131072]
May 7 14:54:53 mainoffice openvpn[13362]: ROUTE default_gateway=10.0.3.2
May 7 14:54:53 mainoffice openvpn[13362]: TUN/TAP device tun0 opened
May 7 14:54:53 mainoffice openvpn[13362]: TUN/TAP TX queue length set to 100
May 7 14:54:53 mainoffice openvpn[13362]: /sbin/ip link set dev tun0 up mtu 1500
May 7 14:54:53 mainoffice openvpn[13362]: /sbin/ip addr add dev tun0 local 10.200.0.1 peer 10.200.0.2
May 7 14:54:53 mainoffice openvpn[13362]: /sbin/ip route add 10.101.0.0/16 via 10.200.0.2
May 7 14:54:53 mainoffice openvpn[13362]: /sbin/ip route add 10.102.0.0/16 via 10.200.0.2
May 7 14:54:53 mainoffice openvpn[13362]: /sbin/ip route add 10.200.0.0/16 via 10.200.0.2
May 7 14:54:53 mainoffice openvpn[13362]: Data Channel MTU parms [ L:1542 D:1450 EF:42 EB:135 ET:0 EL:0 AF:3/1 ]
May 7 14:54:53 mainoffice openvpn[13369]: UDPv4 link local (bound): [undef]:1194
May 7 14:54:53 mainoffice openvpn[13369]: UDPv4 link remote: [undef]
May 7 14:54:53 mainoffice openvpn[13369]: MULTI: multi_init called, r=256 v=256
May 7 14:54:53 mainoffice openvpn[13369]: IFCONFIG POOL: base=10.200.0.4 size=16382
May 7 14:54:53 mainoffice openvpn[13369]: IFCONFIG POOL LIST
May 7 14:54:53 mainoffice openvpn[13369]: remote-office-1,10.200.101.4
May 7 14:54:53 mainoffice openvpn[13369]: remote-office-2,10.200.102.4
May 7 14:54:53 mainoffice openvpn[13369]: Initialization Sequence Completed
May 7 14:54:53 mainoffice kernel: tun0: Disabled Privacy Extensions
Once you've verified based upon the above output that everything is running fine, go ahead and mark the service to start automatically
chkconfig openvpn on
Client Configs (Remote Offices)
On each server, create the file "/etc/openvpn/vpn.mydomain.com.conf", and populate with the following:
dev tun
proto udp
remote 192.168.56.100 1194
resolv-retry infinite
ca ca.crt
cert remote-office-1.crt
key remote-office-1.key
verb 3
Be sure to change the cert name as appropriate.
Copy the ca.crt, remote-office-1.key, and remote-office-1.crt to the /etc/openvpn/ directory of the client. Repeat for Office 2.
Set the permissions on the key file so that it can't be copied by non-root users.
chmod 600 /etc/openvpn/remote-office-1.key
Start the OpenVPN service
service openvpn start
Check the output of syslog for similar output:
May 7 16:26:39 remote-office-1 openvpn[1566]: OpenVPN 2.2.2 x86_64-redhat-linux-gnu [SSL] [LZO2] [EPOLL] [PKCS11] [eurephia] built on Aug 10 2012
May 7 16:26:39 remote-office-1 openvpn[1566]: WARNING: No server certificate verification method has been enabled. See http://openvpn.net/howto.html#mitm for more info.
May 7 16:26:39 remote-office-1 openvpn[1566]: NOTE: the current --script-security setting may allow this configuration to call user-defined scripts
May 7 16:26:39 remote-office-1 openvpn[1566]: LZO compression initialized
May 7 16:26:39 remote-office-1 openvpn[1566]: Control Channel MTU parms [ L:1542 D:138 EF:38 EB:0 ET:0 EL:0 ]
May 7 16:26:39 remote-office-1 openvpn[1566]: Socket Buffers: R=[229376->131072] S=[229376->131072]
May 7 16:26:39 remote-office-1 openvpn[1566]: Data Channel MTU parms [ L:1542 D:1450 EF:42 EB:135 ET:0 EL:0 AF:3/1 ]
May 7 16:26:39 remote-office-1 openvpn[1566]: Local Options hash (VER=V4): '41690919'
May 7 16:26:39 remote-office-1 openvpn[1566]: Expected Remote Options hash (VER=V4): '530fdded'
May 7 16:26:39 remote-office-1 openvpn[1567]: UDPv4 link local: [undef]
May 7 16:26:39 remote-office-1 openvpn[1567]: UDPv4 link remote: x.x.x.x:1194
May 7 16:26:39 remote-office-1 openvpn[1567]: TLS: Initial packet from x.x.x.x:1194, sid=f439995e ac9dd302
May 7 16:26:39 remote-office-1 openvpn[1567]: VERIFY OK: depth=1, /email@example.com
May 7 16:26:39 remote-office-1 openvpn[1567]: VERIFY OK: depth=0, /firstname.lastname@example.com
May 7 16:26:39 remote-office-1 openvpn[1567]: Data Channel Encrypt: Cipher 'BF-CBC' initialized with 128 bit key
May 7 16:26:39 remote-office-1 openvpn[1567]: Data Channel Encrypt: Using 160 bit message hash 'SHA1' for HMAC authentication
May 7 16:26:39 remote-office-1 openvpn[1567]: Data Channel Decrypt: Cipher 'BF-CBC' initialized with 128 bit key
May 7 16:26:39 remote-office-1 openvpn[1567]: Data Channel Decrypt: Using 160 bit message hash 'SHA1' for HMAC authentication
May 7 16:26:39 remote-office-1 openvpn[1567]: Control Channel: TLSv1, cipher TLSv1/SSLv3 DHE-RSA-AES256-SHA, 1024 bit RSA
May 7 16:26:39 remote-office-1 openvpn[1567]: [vpn.mydomain.com] Peer Connection Initiated with 192.168.56.150:1194
May 7 16:26:41 remote-office-1 openvpn[1567]: SENT CONTROL [vpn.mydomain.com]: 'PUSH_REQUEST' (status=1)
May 7 16:26:41 remote-office-1 openvpn[1567]: PUSH: Received control message: 'PUSH_REPLY,route 10.100.0.0 255.255.0.0,route 10.101.0.0 255.255.0.0,route 10.102.0.0 255.255.0.0,route 10.200.0.0 255.255.0.0,topology net30,ping 10,ping-restart 120,ifconfig 10.200.101.6 10.200.101.5'
May 7 16:26:41 remote-office-1 openvpn[1567]: OPTIONS IMPORT: timers and/or timeouts modified
May 7 16:26:41 remote-office-1 openvpn[1567]: OPTIONS IMPORT: --ifconfig/up options modified
May 7 16:26:41 remote-office-1 openvpn[1567]: OPTIONS IMPORT: route options modified
May 7 16:26:41 remote-office-1 openvpn[1567]: ROUTE default_gateway=10.0.3.2
May 7 16:26:41 remote-office-1 openvpn[1567]: TUN/TAP device tun0 opened
May 7 16:26:41 remote-office-1 openvpn[1567]: TUN/TAP TX queue length set to 100
May 7 16:26:41 remote-office-1 openvpn[1567]: /sbin/ip link set dev tun0 up mtu 1500
May 7 16:26:41 remote-office-1 kernel: tun0: Disabled Privacy Extensions
May 7 16:26:41 remote-office-1 openvpn[1567]: /sbin/ip addr add dev tun0 local 10.200.101.6 peer 10.200.101.5
May 7 16:26:41 remote-office-1 openvpn[1567]: /sbin/ip route add 10.100.0.0/16 via 10.200.101.5
May 7 16:26:41 remote-office-1 openvpn[1567]: /sbin/ip route add 10.101.0.0/16 via 10.200.101.5
May 7 16:26:41 remote-office-1 openvpn[1567]: /sbin/ip route add 10.102.0.0/16 via 10.200.101.5
May 7 16:26:41 remote-office-1 openvpn[1567]: /sbin/ip route add 10.200.0.0/16 via 10.200.101.5
May 7 16:26:41 remote-office-1 openvpn[1567]: Initialization Sequence Completed
And verify that the routing is taking place
ping 10.100.0.1
Set the openvpn service to start automatically
chkconfig openvpn on
Repeat these steps for the Office 2 client. And verify that you can ping across both tunnels to Office 1
Roadwarrior Config (this is optional)
As an afterthought, I said I'd cover Roadwarrior configuration. Here's a basic rundown:
- Generate a new cert/key pair for your username using the above ./build-key commands
- Install OpenVPN for Windows (if you're on Mac or Linux, you likely know how to do this already)
- Copy the ca.crt, username.crt, and username.key files to "C:\Program Files\OpenVPN\config\"
- Create a config file named C:\Program Files\OpenVPN\config\vpn.mydomain.com.ovpn with these contents:
dev tun
proto udp
remote vpn.mydomain.com 1194
resolv-retry infinite
ca ca.crt
cert myusername.crt
key myusername.key
verb 3
Right-click on the OpenVPN GUI in the taskbar and click "Connect".
Muchtall Window Arranger (Save Window Positions and Size)
Over the years, I've noticed that there's one "drawback" to multiple heads/screens on a laptop workstation. I get in the habit of arranging my workspace how I like it, where eventually I have 8-10 windows in positions I would prefer to be permanent whenever I hook up my external 2 heads. When I undock, of course everything collapses back to my main display. When I re-dock, the windows remain in a cluttered pile on my main screen. In addition to this, changes in resolution can result in windows needing to be re-sized as well.
I've found one or two utilities over the years that have allowed me to save window positions and sizes, but nothing that handled it for me as automatically as I would have liked. So I wrote my own in AutoHotKey: the Muchtall Window Arranger.
It's fairly simple, yet powerful if you want it to be. Since it's written in AutoHotKey, you can write custom filters to apply to your window rules (assuming you know AHK). But, for the casual user, it simply grabs the active window information and allows you to alter the conditions that apply to the window matching before saving those settings.
Downloadfrom GitHub: Muchtall Window Arranger
You must have AutoHotKey installed before using this script.
There's one setting in the source you'll probably want to modify before you get started. The variable "NumberOfScreens = 3" should be changed to the number of heads you want to have activate the auto-rearrange feature. If this is set to something higher than you'd ever have installed (say 10), the auto-rearrange feature should never activate.
I'll probably clean up the rough edges as I get feedback on it. I know there may be some use for features like re-arranging for multiple head settings, so there's work to be done.
Edit: Moved code to GitHub repo
Brewblog: Kickoff w/ Northern Brewer Nut Brown Ale
My wonderful wife got me a Northern Brewer Deluxe Brewing Starter Kit (Glass) a couple of Christmases ago, and I've been slowly expanding my "brewery" ever since. I've made maybe 6 batches of beer using the kit. One of which I royally messed up (NB Bavarian Hefeweizen) when I scorched the malt in my newly-keggle-fied boiling vessel (on high heat of course).
So far, here's my inventory of equipment:
Northern Brewer Deluxe Starter Kit:
- 6 Gallon Primary Fermentor (Glass), Fermometer, Bung, Airlock, Blowoff Assembly
- 5 Gallon Secondary Fermentor (Glass), Fermometer, Bung, Airlock
- 6.5 Gallon Bottling Bucket, Bottling Spigot, Bottle Filler, Bottling Tubing
- Auto-Siphon, Siphon Tubing
- Beer Bottle Brush, Bottle Capper
- Carboy Brush
I also had a few pieces of equipment from my prior homebrewing adventures of years past:
- Another bottle-capper
- Another 5 gallon secondary glass fermentor
- Airlock (from a Mr. Beer kit)
- One of those common orange dual-vent carboy caps
- ~3 Gallon stainless steel kettle (w/glass lid that I interchange with the keggle below)
And a few new acquisitions and creations:
- 15 gallon boiling "keggle", modified from an old stainless Miller keg (inherited)
- 10lb. CO2 canister w/ regulator
- 4 ball-lock corny kegs
- 1 set of ball lock inlet/outlet tubing, "foam-free" faucet, and connections (I can tap one keg at a time)
- 4 Perlick 545PC Flow Control Faucets (Xmas gift from Santa/Father-in-Law)
- ~7.x cu ft. Freezer (from grandmother-in-law)
- Johnson Controls A419 Temperature Controller (to convert freezer into kegerator)
- Bayou Classic SP10 High-Pressure Outdoor Gas Cooker
- ~20' counter-flow chiller w/partial convolution (see: http://www.thegatesofdawn.ca/wordpress/homebrewing/wort_chiller/)
- ~2' stainless steel spoon
- 2 reusable hop bags
- Yet-to-be-finished ~56qt mash tun cooler (still have to cut slots in my manifold, otherwise done)
Anyhow, I expect to be posting updates on future brewing exploits, so to kick it off, here's my 6th-ish brew: the Northern Brewer Nut Brown Ale (extract kit). This is video I took of the fermentation just a mere 24 hours after directly pitching dry yeast into the wort. Not bad I think, considering that Danstar recommends prepping the yeast before pitching it.
Brewed: 4/14
Kegged: 5/21
Quick Tip: Identifying Space Consumption in Linux via Command line
Firstly, let me strongly recommend JDiskReport if a GUI is available to you. It's super easy to use and helps you quickly drill down into the disk and identify disk space usage, on any platform with Java support.
In lieu of that, if you have need to identify disk usage via the command line, run this set of commands:
find / -exec du -ks {} \; 2> /dev/null | sort -n | awk '{printf $1 "\t"; if (system("test -d \""$2"\"")) { print $2 } else { print $2 "/" } }' | tail -1000
This will spit out a list of the largest 1000 individual files and folder sums, sorted by size.
Depending on the size of the disk, this will take a while, as should be expected as it runs a "du" for each path it finds. Caching helps if/when you re-run this.
Excel Formula to Convert Polycom 8020/8440 Serial Number to MAC Address
This is an obscure tip, but it thought it was cool enough to post as it comes in handy when scanning in inventory with a barcode scanner. This works on Polycom 8400's (8440/8450) and 8000's (8020/8002)., and probably any other Polycom SIP device.
This formula will take the serial number in the column to the left and convert it to a MAC address.


text:
This award is given annually to recognize those individuals who have dedicated time and effort to promote the objectives of career/technical student organizations/Business Professionals of America or provided outstanding service to BPA at the National level. To discover more about the Outstanding Service Award, please visit http://www.bpa.org/service/bpacares.
2017 Recipients
MS. SUE ELWOOD, IOWA BPA ASSOCIATIONSue is one of the most valuable advisors and Iowa State BPA Board members. She who works as a team player to accomplish what it takes to organize and put on a state leadership conference. Putting in extra time and effort along with attention to detail are some of her most admired attributes.MS. SONYA GUTHRIE, INDUSTRY PARTNER-AICPAMs. Guthrie has consistently worked on behalf of BPA to ensure that the long-standing partnership that has been in place between BPA and the AICPA continues to thrive and offer support to the thousands of students and advisors that make up our organization.
MS. ANGIE LIGHTCAP-HEWES, DELAWARE BPA ASSOCIATIONMs. Angie Lightcap-Hewes has been a continuously supportive member BPA for the past 20 years as a local chapter advisor at Smyrna High Schooland Polytech High School in Delaware. During her time as a BPA advisor, Ms. Hewes has shown dedication to the organization in countless ways.
MRS. SHARON WYBLE, MICHIGAN BPA ASSOCIATIONMrs. Wyble has served in many capacities on the local, Regional and State levels during her tenure in BPA. Sharon has been involved as a local chapter advisor since BPA was OEA. She began her career in BPA as local chapter advisor in the late 1970's. She has dedicated countless hours to the students and BPA Program at Stephenson High School and the Michigan BPA State Association.
2016 RecipientsMR. DUSTIN DEVERS, OKLAHOMA BPA ASSOCIATION
2015 Recipients
2014 Recipients
2013 RecipientsHeather Bunning, AICPA - North CarolinaKelly Williams, Michigan
2012 Recipients
2011 RecipientClay Long, IdahoLois Flaig, Minnesota
2010 RecipientBrian Gurule, New Mexico
2009 RecipientMildred Woerndel, Texas
2008 RecipientRon Draayer, MichiganDebra Jones, IowaEllen Long, AlaskaKathy O'Brien, Idaho
2007 RecipientBrenda Jacobsen, Idaho
2006 RecipientAngie Neal, Idaho
2005 RecipientPam AllenderMable Burchfield, Tennessee Colleen Hunt, Iowa Rebecca SimonsSherrell Wheeler, TexasRita Young, Tennessee
2004 RecipientsRobin Goff, Texas Darrell Muck, IdahoDorothy M. (Goodman) Palmer, Missouri
2003 RecipientsJanet Garrett, Marjorie Gillespie, New Mexico Bonnie Manns, Ohio Vickie Thomas, TX
2002 RecipientJames A. Urness, Wisconsin
2001 RecipientLeAnn Snyder, Ohio
2000 RecipientsLois Chipperfield, Ohio Don Smith, Iowa Barbara Steele, Wisconsin
1999 RecipientsPaul DavisPhil MyersJoyce SmithMarla StelloJames Zimmer, Wisconsin
1998 RecipientsDavid F. Fong, CaliforniaLarry Kantrud, MinnesotaTheresa TenEyck, Idaho
1997 RecipientsMike Cashman, Washington Trudy Formanek, Montana Patty Housh, MontanaDr. Kathy Lasater, Tennessee
1996 RecipientSharon Souder, Ohio
1995 RecipientsMary Hite, DelawareLynn Wells, Ohio
1994 RecipientsRobert K. Gordon, Texas Gay Sweet Harris, Texas Marie Maddox, Texas Gladys Renick, WisconsinMildred Woerndel, Texas
1993 RecipientsRoger Fulk, Ohio Bonnie Herr, Minnesota Rita Johnson, Kansas Karen Lutes, Kansas
1992 RecipientsDorothy Baum, Texas Dr. William Dross, Ohio Barbara L. Portzen, Wisconsin Billie E. Scott, Kansas Morgan B. Wright, Wisconsin
1991 RecipientsSuevonne Carlson, Minnesota Charlotte Coomer, Ohio Dave McCabe, Minnesota Marion Reed, Montana Korlyn Williams, Alaska
1990 RecipientsDr. Sarah Bell, Delaware Steve Darnell, Delaware Beth Fogelsong, Ohio Dr. Marianne Frye, WisconsinSharon A. Sharrett, Indiana
1989 RecipientsPeggy A. Demgen, Wisconsin Charles GeickNancy Perkins, MassachusettsGladys Renick, Wisconsin Bea Wells, Ohio

subset: commoncrawl


text:
Tuesday, September 14, 2010
AP calls 3rd, 4th CD primaries
U.S. Rep. Gwen Moore, D-Milwaukee, has won her 4th CD primary against Paul Morel, while state Sen. Dan Kapanke of La Crosse will be the GOP candidate against La Crosse Dem U.S. Rep. Ron Kind.
Kapanke defeated Bruce Evers in the 3rd CD GOP primary.
-- By Andy Szal
Labels: 2010_fall_primary


text:
LoginSign up Forgot Password?
III International Conference on Environmental, Industrial and Applied Microbiology (BioMicroWorld2009)
Venue: Faculty of Dentistry (University of Lisbon) and ISCTE (Lisbon University Institute)
|Event Date/Time: Dec 02, 2009
|End Date/Time: Dec 04, 2009
|Registration Date: Nov 11, 2009
|Early Registration Date: Sep 04, 2009
|Abstract Submission Date: Sep 15, 2009
BioMicroWorld2009 intends to consolidate a series of conferences, whose last edition, held in Seville (Spain) in 2007, received about 1000 abstracts to be considered for presentation and attracted researchers from nearly 60 countries.
- Agriculture, Soil, Forest Microbiology
- Analytical and Imaging Techniques. Microscopy
- Environmental, Marine, Aquatic Microbiology. Geomicrobiology
- Food Microbiology
- Industrial Microbiology - Future Bioindustries
- Medical Microbiology - Pharmaceutical Microbiology
- Methods - Quantitative Models and Bioinformatics in Microbiology
- Microbial Physiology, Metabolism and Gene Expression
- Antimicrobial Surfaces
- Biofilms
- Bioremediation
- Biotechnologically Relevant Enzymes and Proteins
- Microarrays in Microbiology
- Microbial Biosensors (transducers, recognition)
- Microfactories - Microbial Production of Chemicals and Pharmaceuticals
- Single-cell analysis of microbes
- Synthesis of nanomaterials by microorganisms (nanowires, nanoparticles)
- 4 September 2009: Deadline for early registration
- 15 September 2009: Deadline for abstract submission
- 11 November 2009: Deadline for registration
In addition to the oral and posters presentations, a Virtual Participation mode has been established for those researchers who are unable to attend the Conference personally. These participants will be requested to send "virtual papers", which will be exhibited at the online platform for virtual participation. These papers can be prepared using Power Point, Flash or similar software, or video recordings. Please consult the conference website for details.
To keep informed about all conference details, you may fill-in the Pre-registration form, which is available at http://www.formatex.org/biomicroworld2009/preregistration-form/preregistration.html
- Abstract Book
A Book of Abstracts will be published including all abstracts of works presented in the Conference. It will be distributed among all participants at the beginning of the Conference and dispatched to virtual participants after it.
- Proceedings Book/ International Journals special issues
Conference participants can submit manuscripts to be considered for publication either in the Conference Proceedings Book or in the special issues of the journals with which the Conference will agree their publication. Authors must select only one of these two publication options (submission of full papers is optional)
The Proceedings Book will be published in 2010 by an international publisher to give it a broad international distribution.
Full papers published in the International Journals collaborating with BioMicrowold2009 will go through a standard scientific review process. This means that each paper will be strictly reviewed and treated as a regular paper since our goal is to produce high quality and high impact special issues based on some of the best conference papers.
Information about the Proceedings Book and the International Journals special issues published in the previous edition of our conference, held in 2007, is available at: http://www.formatex.org/biomicroworld2007
We look forward to receiving your presentation proposals.


text:
All About Reaching Children, Inc. All About Reaching Children, Inc.
Here's a sample of our volunteer opportunities:VIEW AS
Please wait . . .
Mission Statement
Our mission is to provide a safe haven for at-risk children through animal care, responsibilities on the farm and outreach into the community. Children who come to AARC gain the tools necessary to become productive members of society.
AARC provides children with opportunities such as:
Caring for animals:
- Caring for horses, goats, chickens, dogs, and other farm animals
- Feeding and watering animals, cleaning stalls
- Assisting on-site vet with various duties, such as the birthing process
Growing vegetables and harvesting fruit trees:
- Teach children how to grow, care for and harvest various types of fruits & vegetables
- Apply principles of sowing & reaping
- Link principles of finances and giving with the marketing process
- The children learn various life skills by participating in camps, service projects and over events.
- AARC also provides children of low-income families with food and clothing, as well as other needs
We believe that human interactions coupled with animals as well as other responsibilities can result in both physiological changes and psychological benefits.
This information
Might be out of date
Do you work for this organization?
Request administrator status and update its information!
Would you recommend All About Reaching Children, Inc.?


text:
Tracking Request Volume Based On IP Addresses In ColdFusion
This much less a "how to" post and much more just a "thinking out loud" post. I don't really know if I even like what I came up with; but, I figured I would put it out here in case it lead to some good conversations. In the wake of some spam comments on my site, I started to think about tracking the IP addresses of requests in ColdFusion in order to see if a given IP address was making too many requests in too short a time period.
This kind of task actually has some very interesting problems to solve:
- We want to track request volume by IP address.
- We only want to track volume over a given period of time.
- We want to efficiently dereference old tracking information.
- We want to make this all thread-safe, but fast.
To start with, let me just say I ignored thread-safety for the time being; I figured that could be re-addressed later on (this was more an exploration). What was more interesting to me was the idea of tracking volume for a given time period and efficiently de-referencing old tracking data. Because we only want to look at request volume for a given time period, we can't simply keep a running sum of requests for each IP address; doing that would prevent us from constantly moving the viewing window forward without corrupting the existing aggregates. We also don't want to have to loop over hundreds (or even thousands) of items looking for data as this would probably not be performant.
To account for a valid time period and efficient de-referencing, I came up with the idea of using time offset buckets. By grouping IP tracking into buckets, we could store IP-based aggregates while still being able to dump old tracking information without corruption. Also, by storing time offset data in the bucket itself, rather than with the IP value, we don't have to loop over IP values - of which there could be thousands - looking for outdated tracking information.
With this approach, IP keys will get duplicated in each bucket (in which they made a request); but, by using this approach, the most processing we'll ever have to do is looping over the buckets, of which there will be a small and constant number. As such, the only scaling issues here would be RAM availability and the speed of hash table lookups; meaning, the number of requests shouldn't have too much of an impact on how well this runs.
Before we look at the ColdFusion component that contains this business logic, let's take a quick look at the calling code (simply an API demo, not a real-world use case):
-
- <cfset tracker = createObject( "component", "IPTracker" ).init() />
-
- #tracker.trackIP( cgi.remote_addr )#

- #tracker.trackIP( cgi.remote_addr )#

- #tracker.trackIP( cgi.remote_addr )#

- #tracker.trackIP( cgi.remote_addr )#

- #tracker.trackIP( cgi.remote_addr )#

- #tracker.trackIP( cgi.remote_addr )#

-
- <cfthread
- action="sleep"
- duration="#(1000 * 5)#"
- />
-
- #tracker.trackIP( cgi.remote_addr )#

- #tracker.trackIP( cgi.remote_addr )#

-

-
- <cfdump
- var="#tracker.getBuckets()#"
- label="Buckets Data"
- />
Here, we are creating the tracker and then logging many requests to it. The TrackIP() method tracks the given IP address and then returns a True / False value as to whether or not the given IP has reached the request volumne threshold. Running the above code, we get the following output:
As you can see, the IP tracking, even over the few seconds in this demo, have been split up into two buckets, each containing a sub-aggregate for each IP address for that time period.
Now that you kind of see what's going on, let's take a look at the IPTracker.cfc ColdFusion component:
- <cfcomponent
- output="false"
- hint="I track IP addresses over time for abuse protection.">
- <cffunction
- name="init"
- access="public"
- returntype="any"
- output="false"
- hint="I initialize this component.">
-
- <cfset variables.buckets = [] />
-
- <cfset variables.bucketDuration = 3 />
-
- <cfset variables.trackingDuration = 60 />
-
- <cfset variables.validThreshold = 5 />
-
- <cfset variables.bucketCount = ceiling(
- variables.trackingDuration / variables.bucketDuration
- ) />
-
- <cfset variables.startTime = now() />
-
- <cfreturn this />
- </cffunction>
- <cffunction
- name="getBucketKey"
- access="public"
- returntype="numeric"
- output="false"
- hint="I return the bucket key based on the given time.">
-
- <cfargument
- name="timeStamp"
- type="date"
- required="true"
- hint="I am the time being translated into a bucket key."
- />
-
- <cfset var local = {} />
-
- <cfset local.offset = dateDiff(
- "s",
- variables.startTime,
- arguments.timeStamp
- ) />
-
- <cfset local.bucketKey = (
- local.offset -
- (local.offset mod variables.bucketDuration)
- ) />
-
- <cfif (local.offset gt 86400)>
-
- <cfset variables.startTime = now() />
- </cfif>
-
- <cfreturn local.bucketKey />
- </cffunction>
- <cffunction
- name="getBuckets"
- access="public"
- returntype="array"
- output="false"
- hint="I return the buckets.">
- <cfreturn variables.buckets />
- </cffunction>
- <cffunction
- name="hasIPReachedThreshold"
- access="public"
- returntype="boolean"
- output="false"
- hint="I determine if the given IP address has reached the request threshold.">
-
- <cfargument
- name="ip"
- type="string"
- required="true"
- hint="I am the IP address being tracked."
- />
-
- <cfset var local = {} />
-
- <cfset local.hitCount = 0 />
-
- <cfloop
- index="local.bucket"
- array="#variables.buckets#">
-
- <cfif structKeyExists( local.bucket.ips, arguments.ip )>
-
- <cfset local.hitCount += local.bucket.ips[ arguments.ip ] />
- </cfif>
- </cfloop>
-
- <cfreturn (local.hitCount gt variables.validThreshold) />
- </cffunction>
- <cffunction
- name="paramFirstBucket"
- access="public"
- returntype="void"
- output="false"
- hint="I param the first bucket.">
-
- <cfset var local = {} />
-
- <cfset local.bucketKey = this.getBucketKey( now() ) />
-
- <cfif (
- !arrayLen( variables.buckets ) ||
- (variables.buckets[ 1 ].key neq local.bucketKey)
- )>
-
- <cfset local.bucket = {
- key = local.bucketKey,
- ips = {}
- } />
-
- <cfset arrayPrepend( variables.buckets, local.bucket ) />
-
- <cfif (arrayLen( variables.buckets ) gt variables.bucketCount)>
-
- <cfloop
- index="local.bucketIndex"
- from="#arrayLen( variables.buckets )#"
- to="#(variables.bucketCount + 1)#"
- step="-1">
-
- <cfset arrayDeleteAt(
- variables.buckets,
- local.bucketIndex
- ) />
- </cfloop>
- </cfif>
- </cfif>
-
- <cfreturn />
- </cffunction>
- <cffunction
- name="trackIP"
- access="public"
- returntype="boolean"
- output="false"
- hint="I track the given IP address and return a boolean as to whether the given IP address has exceeded the threshold.">
-
- <cfargument
- name="ip"
- type="string"
- required="true"
- hint="I am the IP address being tracked."
- />
-
- <cfset var local = {} />
-
- <cfset this.paramFirstBucket() />
-
-
- <cfparam
- name="variables.buckets[ 1 ].ips[ arguments.ip ]"
- type="numeric"
- default="0"
- />
-
- <cfset variables.buckets[ 1 ].ips[ arguments.ip ]++ />
-
- <cfreturn this.hasIPReachedThreshold( arguments.ip ) />
- </cffunction>
- </cfcomponent>
So anyway, that's what I've got. Again, this was not so much a solution as it was just (hopefully) the basis of some good conversation. I understand that much more thread safety thinking has to be put into place; I left that out of this in order to keep things simple.
Looking For A New Job?
Ooops, there are no jobs. Post one now for only $29 and own this real estate!
Reader Comments
You might check out Open BlueDragon's CFTHROTTLE tag for some additonal implementation ideas:
Looks interesting - definitely the same concept (tracking hits per IP per time period). Is there a way to look at the source code they have? Or is that all in Java classes?
Yep, that's what open source is all about. ;-) Since this is native to the engine it's in Java of course, but if you grab the source and navigate to com/naryx/tagfusion/cfm/tag/ext/cfTHROTTLE.java you can check things out.
I'm curious.... how many requests are too many?
Hey Ben,
Yeah good post, I had hit into the same problem and this is a code sample of what I have been using successfully to handle issue for quite some tome now with no issue.
Note this is a somewhat hacked except of my request facade object (so some of the generic methods are inherited but not shown, aswell as some other code being called, but only to get some mentioned config vars), but it at least gives you an idea.
This works via a struct (fast) keyed on ip address, then an array of times per key. It is thread safe also.
Let me know if you have any questions and keep up the great blog :)
values currently returned from getEngine().getGeneral()
requestsResetTime = 24
requestsTimeframe = 10
requestsInTimeframeByIpMax = 50
Other code is removed to make this easier to follow
hint="RequestFacade creates an interface to store request based code">
<cffunction name="init" access="public" output="false" returntype="application.model.core.facade.RequestFacade"
hint="Constructor for this CFC.">
<cfargument name="engine" type="application.model.core.Engine" required="true" />
<cfset super.init(arguments.engine) />
<cfset resetRequests() />
<cfreturn this />
<cffunction name="getRequests" access="public" returntype="struct" output="false">
<cflock type="readonly" name="#getUniqueLockId('requests')#" timeout="10" throwontimeout="true">
<cfreturn variables.instance.requests />
<cffunction name="setRequests" access="private" returntype="void" output="false">
<cfargument name="requests" type="struct" required="true" />
<cflock type="exclusive" name="#getUniqueLockId('requests')#" timeout="10" throwontimeout="true">
<cfset variables.instance.requests = arguments.requests />
<cffunction name="getRequestsStart" access="public" returntype="date" output="false">
<cflock type="readonly" name="#getUniqueLockId('requestsStart')#" timeout="10" throwontimeout="true">
<cfreturn variables.instance.requestsStart />
<cffunction name="setRequestsStart" access="private" returntype="void" output="false">
<cfargument name="requestsStart" type="date" required="true" />
<cflock type="exclusive" name="#getUniqueLockId('requestsStart')#" timeout="10" throwontimeout="true">
<cfset variables.instance.requestsStart = arguments.requestsStart />
<cffunction name="onRequestStart" access="public" output="false" returntype="void"
hint="Should be fired when the request starts from the Application bootstrapper.">
<cfargument name="targetPage" type="string" required="true" />

<cfset purgeRequestsIfNeeded() />
<cfset manageRequests() />
<cfreturn />
<cffunction name="resetRequests" access="private" returntype="void" output="false">
<cfset setRequests(structNew()) />
<cfset setRequestsStart(now())>
<cffunction name="purgeRequestsIfNeeded" access="private" returntype="void" output="false">
<cfif dateDiff("H", getRequestsStart(), now()) gt getEngine().getGeneral().getRequestsResetTime()>
<cfset resetRequests() />
<cffunction name="getRequestsByIp" access="private" returntype="array" output="false">
<cfargument name="ip" type="string" required="true" />
<cfset var requests = getRequests() />
<cflock type="exclusive" name="#getUniqueLockId('request_#arguments.ip#')#" timeout="10" throwontimeout="true">
<cfif not structKeyExists(requests, arguments.ip)>
<cfset requests[arguments.ip] = arrayNew(1) />
<cfreturn requests[arguments.ip] />
<cffunction name="getRequestByIp" access="private" returntype="date" output="false">
<cfargument name="ip" type="string" required="true" />
<cfargument name="index" type="numeric" required="true" />
<cfset var requests = getRequests() />
<cflock type="exclusive" name="#getUniqueLockId('request_#arguments.ip#')#" timeout="10" throwontimeout="true">
<cfreturn requests[arguments.ip][arguments.index] />
<cffunction name="appendRequestByIp" access="private" returntype="void" output="false">
<cfargument name="ip" type="string" required="true" />
<cfargument name="timestamp" type="date" required="false" default="#now()#" />
<cfset var requests = getRequests() />
<cflock type="exclusive" name="#getUniqueLockId('request_#arguments.ip#')#" timeout="10" throwontimeout="true">
<cfset arrayAppend(requests[arguments.ip], arguments.timestamp) />
<cffunction name="deleteRequestByIp" access="private" returntype="void" output="false">
<cfargument name="ip" type="string" required="true" />
<cfargument name="index" type="numeric" required="true" />
<cfset var requests = getRequests() />
<cflock type="exclusive" name="#getUniqueLockId('request_#arguments.ip#')#" timeout="10" throwontimeout="true">
<cfset arrayDeleteAt(requests[arguments.ip], arguments.index) />
<cffunction name="getRequestSizeByIp" access="private" returntype="numeric" output="false">
<cfargument name="ip" type="string" required="true" />
<cfreturn arrayLen(getRequestsByIp(arguments.ip)) />
<cffunction name="manageRequests" access="private" returntype="void" output="false">
<cfset var ip = getEngine().getRuntime().getIpAddress() />
<cfset var requestsTimeframe = getEngine().getGeneral().getRequestsTimeframe() />
<cfset var requests = getRequests() />
<cfset var requestsSize = getRequestSizeByIp(ip) />
<cfset var index = 0 />
<cflock type="exclusive" name="#getUniqueLockId('request_#ip#')#" timeout="10">
<cfloop condition="true">
<cfset index = index + 1>
<cfif index gt requestsSize>
<cfbreak />
<cfif dateDiff("S", getRequestByIp(ip, index), now()) gt requestsTimeFrame>
<cfset deleteRequestByIp(ip, index)>
<cfset index = index - 1>
<cfset requestsSize = requestsSize - 1>
<cfbreak />
<cfset appendRequestByIp(ip, now()) />
<cfif requestsSize gt getEngine().getGeneral().getRequestsInTimeframeByIpMax()>
message="Your IP address: #ip# has exceeded the maximum number of requests within the allowed time frame." />
It looks cool, but I am not seeing where you purge old IP request data. For example, say someone hits your site, and then doesn't come back - where is that IP address eventually purged from your tracking?
Last time I tried blocking spam with IP traffic it was with CF5. I don't remember the exact code I used; I no longer maintain the site or have access to the code.
Tracked IPs were kept in an application scope and dumped every 5 minutes. Each IP had a startTrackingTime and IPHitCount if the IP hit more than a certain frequency it was removed from tracking and placed in a banned list. The frequency was checked by something like <cfif IPHitCount / dateDiff("s", startTrackingTime, now()) gt 5>ban the IP</cfif>
Banned IPs were simply <cfabort>ed.
Hi Ben,
All requests are purged if needed on request start via purgeRequestsIfNeeded()
(Which in turn fires resetRequests() if conditions are met)
Also within manageRequests() which is the overall checking method, induvidual ones are removed if needed via deleteRequestByIp(ip, index)
Does that help?
Hmmm, I think I am missing something; but no worries - I get the general drift.
Well it goes like this: every request fires a method that will purge/reset the whole struct if needed, then after that occurs will check the ip etc, removing it from the struct if it should be ejected. It the records this new request made, then finally checks to see if the ip has reached a limit if so throws an error
This seems like something some open source message boards would already be doing to address getting spammed. Anyone know of one off hand that may have done this?


text:
RECUB is a horizontal formwork for the construction of bi-directional reticular slabs with reusable box moulds (waffles).
With the same standard items, slabs with different rib widths can be built, according to the fire protection standard (12, 16 and 20 cm).
This modular formwork is mainly oriented towards non-residential construction and is ideal for car park construction.
Main features of reticular slabs compared to solid slabs:
- Eases large spans between piers. It also allows free and strategic positioning of the columns, which provides a great deal of flexibility for complex project solutions (openings, ramps, etc.)
- Withstands high live loads
- Consists of lightened areas and solid slab areas
- Quick and easy assembly
- The steel grid can be assembled previously to the placing of waffle moulds and plywood
- For erection, only hammer required
- Long-lasting heavy-duty design. Highly resistant steel structure with polyester resin coating
- Long-lasting waffle moulds, resisting damages and deformation
- Main beams and props (or shoring) make up the load-bearing structure of the system. The recoverable material can be retrieved after 3 days for the next pouring stage
- No re-propping nor prop moving until complete falsework removal
- High assembly efficiency. Trolleys or mobile towers for erection can be easily moved (large distance between props)
- Flexible system:
- Covers different geometries, with varying grid widths, several main beam lengths available
- Adapts to solid and lightened areas (plywood, waffle and half-waffle moulds)
- Perimeter solutions
- Formwork support with prop or shoring
- Safe system:
- Easy integration of perimeter and openings protection with handrails
- Waffle mould and board firmly fitted between main beam and secondary beam
- Net under formwork as safety item and for collective protection when assembling waffle moulds and plywood


text:
Copyright © ComicSpectrum.com All rights reserved.
Up Next:EC Era (1949-1955) - Overlapping the Golden Age
Timely Comics (that would eventually go on to become Atlas and finally Marvel Comics) burst onto the scene not long after the debut of Superman and Batman, offering up Marvel Comics #1 in October 1939, debuting the iconic characters of the Human Torch and the Sub-Mariner. Captain America joined them in March 1941 and the Golden Age had another strong stable of super-heroes for the young fans to buy.
The third major contender in the Golden Age super-hero market was Fawcett Comics. Their most iconic super-hero was Captain Marvel, debuting in WHIZ Comics #2 (Feb 1940). Fawcett created a number of other heroes over the years, but none had the endurance of Captain Marvel and the "Marvel Family". Their adventures dominated the comics at Fawcett, they would guest star in a number of other comics and even introduce new characters to the Fawcett fans. There were certainly other publishers during the Golden Age, dozens, but the 3 spotlighted here created the most enduring super-hero characters.
By the early 1950s, with the exception of Batman, Superman, and Wonder Woman, the Golden Age of Super-Heroes was over. DC's "Big 3" would keep the lights on until the super-hero resurgence that became known as the Silver Age.
When it comes to back issues from this time period, as you might expect, they're getting older and tougher to find. Action Comics #1 for example: it's estimated that only 50-100 copies of this book still exist and with that rarity comes value. In 2011 a copy of Action Comics #1 in really nice condition sold for over $2 million dollars! If you're looking to buy or collect back issues from this time period, just understand what a challenge it could be, especially in higher grades.
The Golden Age of comics is considered by most fans and comics scholars to have started with the first appearance of Superman in Action Comics #1 (June 1938) and ran through 1956. Action Comics #1 changed the landscape of comic book from that point all they way to today. Batman soon followed, debuting in Detective Comics #27 (May 1939) and then a host of other super-heroes who would ultimately form a team, The Justice Society of America, in All-Star Comics #3 (Winter 1940). Super-Heroes became very popular and soon dominated the majority of the titles that were being produced. DC Comics (known as National in the Golden Age) is often thought of first when people think of the Golden Age because of iconic characters like Batman and Superman.
Follow US