Friday, December 30, 2011

Gimp Script-Fu Hacking: Image Spinning and Sprite Generation

I've been working on a project that required some relatively simple, but time consuming image hacking. Specifically, I needed to generate a CSS sprite image from an image that has to be rotated a number of times. The result are the following two Script-Fu functions.

bs-spin-layer: This plugin takes the currently selected layer and duplicates it, then rotates it a number of degrees. It will prompt you for the starting and ending rotation, as well as the step value to use. Nothing fancy here.

bs-layers-to-sprite-ribbon: This plugin is a bit sexier, and may turn out to be a generally useful tool. Supposing you've got a file named foo.xcf, the plugin creates a brand new image named foo.sprite.xcf which consists of each of the layers in foo.xcf, though, they are laid out side by side to create a sprite ribbon. At the same time the foo.sprite.xcf is created, foo.sprite.css is created, which contains the basic CSS you'd need to power the generated sprite. The correct background-position offsets and the appropriate height and width for each layer are calculated and stored in this file.

Every time I use it, I like Script-Fu just a little bit more. I may be the only fan left, but I'm a big one.

Download the code at: utils.scm (needed by both plugins), sprite-ribbon.scm and spin-layer.scm.

And here are the functions plugins minus the required utility functions:

;;
;; The spin-layer module is responsible for spinning (rotating) a layer a number
;; of times to create new layers.
;;


(define (bs-spin-layer img drawable start end step)
  (gimp-image-undo-group-start img)
  (let loop ((angle start))
    (cond ((<= angle end)
           (let ((layer (car (gimp-layer-new-from-drawable drawable img))))
             (gimp-image-add-layer img layer -1)
             (gimp-drawable-set-name layer (number->string angle))
             (gimp-drawable-transform-rotate layer (d->r angle) TRUE 0 0 TRANSFORM-FORWARD
                                             INTERPOLATION-CUBIC FALSE 3
                                             TRANSFORM-RESIZE-ADJUST)
             (loop (+ angle step))))
          (else
           'done)))
  (gimp-image-undo-group-end img)
  (gimp-displays-flush))


(script-fu-register
 "bs-spin-layer"
 "Spin Layer"
 "Spin (rotate) a layer a bunch of times"
 "Ben Simon"
 "Copyright 2011, Ideas2Executables"
 "2011/12/29"
 "RGB* GRAY*"
 SF-IMAGE "Image to Spin" 0
 SF-DRAWABLE "Layer to Spin" 0
 SF-VALUE "Start Angle" "15"
 SF-VALUE "End Angle" "360"
 SF-VALUE "Step" "15")

(script-fu-menu-register "bs-spin-layer" "<Image>/Filters/Util")


;;
;; The sprite-ribbon is responsible for generating a CSS sprite image.
;; Inspired by: http://registry.gimp.org/node/24538
;;
(define (bs-layers-to-sprite-ribbon img drawable css-selector sprite-prefix)
  (define (sprite-css-header file-name)
    (display (&& css-selector " { "
                 "background-repeat: no-repeat; "
                 "background-image: url(" file-name "); "
                 "}\n")))
  (define (sprite-css-entry layer x-off)
    (display (&& css-selector "." sprite-prefix (car (gimp-drawable-get-name layer)) " {"
                 "width: " (car (gimp-drawable-width layer)) "px; "
                 "height: " (car (gimp-drawable-height layer)) "px; "
                 "background-position: " (* -1 x-off) "px 0px; "
                 "}\n")))
  (gimp-image-undo-group-start img)
  (let ((layers (bas-image-layer-list img))
        (file-name  (car (gimp-image-get-filename img))))
    (let ((width (foldr (lambda (w layer)
                                 (+ w (car (gimp-drawable-width layer)) 2))
                        0 layers))
          (height (foldr (lambda (h layer)
                           (max h (car (gimp-drawable-height layer))))
                         0 layers)))
      (let ((sprite (car (gimp-image-new width height RGB))))
        (with-output-to-file (morph-filename file-name "sprite.css")
          (lambda ()
            (sprite-css-header (morph-filename file-name "sprite.png"))
            (let loop ((layers (reverse layers)) (x-off 0))
              (cond ((null? layers) 'done)
                    (else
                     (let ((clone (car (gimp-layer-new-from-drawable (car layers) sprite))))
                       (gimp-image-add-layer sprite clone -1)
                       (gimp-drawable-set-name clone (car (gimp-drawable-get-name (car layers))))
                       (gimp-layer-set-offsets clone x-off 0)
                       (sprite-css-entry clone x-off)
                       (loop (cdr layers) (+ x-off (car (gimp-drawable-width (car layers))) 2))))))))
        (gimp-image-set-filename sprite (morph-filename file-name "sprite.xcf"))
        (gimp-display-new sprite)
        (gimp-image-undo-group-end img)))))


(script-fu-register
 "bs-layers-to-sprite-ribbon"
 "Layers > Sprite Ribbon"
 "Create a CSS spirte ribbon from the layers in the image"
 "Ben Simon"
 "Copyright 2011, Ideas2Executables"
 "2011/12/29"
 "RGB* GRAY*"
 SF-IMAGE "Image to process" 0
 SF-DRAWABLE "Active layer" 0
 SF-STRING "Sprite CSS Selector" ""
 SF-STRING "CSS Layer Prefix" "")


(script-fu-menu-register "bs-layers-to-sprite-ribbon" "<Image>/Filters/Util")

Carry On vs. Checking Luggage vs. Listening To Your Wife

I caught this story on Mamamia.com.au yesterday and had to laugh:

We are lucky enough to be going on a family trip to Europe in late September. That’s me, my husband and our two boys aged 12 and 6. We will be gone for close to one month and are travelling to the UK, Italy and France. Our kids have never been out of Australia and are very excited. My husband has a conference to go to in Cannes so we have arranged this trip around his business trip.

I’m sure it will be amazing but last night my husband announced that he can’t stand dragging huge amounts of luggage around and hates waiting for suitcases with other impatient travellers all hustling for space around the baggage collection areas…..so……we are (apparently!) taking one overnight bag each.
Now this news has given me a mild heart attack. I don’t think I can do it. Don’t my clothes deserve a holiday too? Is this even possible? I can’t imagine leaving for a month without at least four pairs of shoes (trainers, Birkenstocks, one ‘party’ pair and another gorgeous day wear pair – at least!).
And then my mind really went wild. What if it’s cold in the UK? We’ll need jackets. What if we go to a fabulous party in Cannes? That’s a whole special frock with matching shoes and handbag. What about toiletries and all the technology/chargers/power converter crappola you have to take? Not to mention book, camera, hat, bathers.

And then there’s the stuff I wouldn’t go away for a weekend without. Jeans, tops, t-shirts, trackie pants, wrap thingy, cool dress….

I reckon I can pack light for my boys. They wouldn’t care if they wore the same thing every day. But I don’t plan to spend every night of our holiday washing socks and jocks for the next day! I want to ask the lovely and very clever MamaMias if they ever travel very light and if so, what do they take and what do they leave? I need help!

You know, we kind of had this discussion on our last overseas trip. I suggested we carry on only. There were a number of responses I was expecting:

  • No, no we are not. Next topic.
  • Sure Benji, you do whatever you want. I'm going to pack how I want, and you can pack how you want.
  • Sure Benji, we'll pack carry on (as we walk out the door, two large rolling bags appear*).

Never, in my wildest dreams, would I expect her to be unhappy with my request, and go along with it!

On a more serious note, for our last trip, checking luggage turned out to be not evil at all. In fact, there were a number of benefits:

  • The travel arrangement was simple - car, to baggage check, to baggage pickup, to taxi, to our hotel room. We weren't shlepping bags using public transportation, so having a couple of large'ish rolling bags, was quite reasonable.
  • Checking the suitcases meant that while traveling through the airport we had less to schelp and less to worry about it. It was the ultimate in packing light.
  • Both our carry-ons fit under the seat in front of us, so we didn't need to stress about finding an available overhead compartment. This, made boarding a more relaxed experience.
  • Smaller carry-ons meant a slight easier trip through security

And then there are two main arguments one might use: what if they lose your luggage and what about lost time waiting for your luggage at baggage claim?

I try to approach travel is as an adventure that's an exercise in making the best of your circumstances. If they lose my luggage, that's cool, it'll give me a chance to improvise and make do without. And if the luggage arrives, that's fine too.

And what's the rush? So, you have to wait 5 more minutes to pick up your bags? Again, I'm all about making do with my circumstances. Perhaps the baggage claim area is a good time to get my bearings, do a little people watching, and generally get my head in the game.

If our trip had been different (say, we were changing hotels a number of times, or we needed to take public transportation to get to our hotel), I may have pushed harder on the one-carry-on-bag suggestion. But, realistically, our trip was probably more enjoyable because I listened to my wife, and didn't push it.

Via: Carryology.com

*Maryn, not I, came up with this gem of a response. But, thinking on it, I could totally see it happening.

Thursday, December 29, 2011

Gotcha of the Day: Google Maps setCenter(...) Doesn't Work

One of my favorite tricks using the Google Maps API is to create one or more little maps that are in sync with a larger map on the page.

You can do something like:

// Assume that bigMap is setup already, and smallMapDiv is an HTML node ready
// for us to add our smallMap to

// Show a marker on the bigmap
var m = new google.maps.Marker({position: bigMap.getCenter(), 
                                animation: google.maps.Animation.DROP,
                                map: bigMap,
                                draggable: true});

// Now create a small map that stays in sync with the marker's position
var ops = { center: m.getPosition(),
            zoom: bigMap.getZoom(),
            mapTypeId: google.maps.MapTypeId.ROADMAP };
var smallMap = new google.maps.Map(smallMapDiv, ops);

// Keep 'em in sync
google.maps.event.addListener(m, 'position_changed', function() { smallMap.setCenter(m.getPosition()); });
google.maps.event.addListener(bigMap, 'zoom_changed', function() { smallMap.setZoom(bigMap.getZoom()); });

The above code was essentially working for me, with one major issue. The marker's position (m) wasn't causing driving smallMap's centering. That is, the smallMap was not a zoomed in view of m.

After fiddling around, I learned that smallMap wasn't randomly misplaced. Instead of m.getPosition() setting the center of the map, it was driving the top left hand corner of the map. That is, smallMap synchronized with bigMap, but what should have been dead center of the map, was corresponding to the top left.

After further analysis, I did indeed figure out the problem: when I created smallMap and added it to smallMapDiv, smallMapDiv had yet to be added to the page's DOM. The result was that smallMap apparently didn't know the dimensions of the area it had to work with so setCenter(...) couldn't function.

Telling smallMap to recalculate its dimensions turns out to be painless. I just needed to arrange for the following code to be invoked once smallMapDiv was actually added to the page.

google.maps.event.trigger(smallMap, 'resize');

With that line of code, my little map and big map played quite nice with each other.

Wednesday, December 28, 2011

One Of My Least Favorite Jobs: Defending Airport Security

I hate having to defend the TSA. But when I read articles like this one, I can't help but feel like I should say something. Sure, part of this article is dead on: there are some TSA practices which are goofy and seem absurd to me. But, to describe the whole process as insane and kvetch about how inconvenient it is seems to be missing the point.

Here, I'll let Louis C.K. explain (sorry about the foul language):

Comedy Central Stand-Up
Get More: Jokes,Joke of the Day,Funny Jokes

Take my last trip to Boston. In exchange for 10 minutes of waiting in line, the horror of removing my shoes and taking my laptop out of my bag, I was able to fly through the air in a metal tube (loaded with thousands of gallons of flammable liquid, no less) and land safely on the other side. Instead of a 10 hour car trip, I had 45 minutes of whizzing through the clouds. And people want to complain about waiting a few minutes in a security line? Or that a security guard might actually want to see what you're carrying?

To me, the miracle of flight isn't that heavy objects can fly. Nahhhh, that's just physics. The miracles is that we're able to take something so inherently complex and dangerous and make it something absolutely routine. I'd guess the most dangerous part of my trip is the car ride to the airport.

I'm glad there are people who push back on the TSA, no government agency deserves a blank check. Let's keep security experts on both sides fine tuning the process. But a little perspective sure would go a long way.

Via: Parent Hacks.

Tuesday, December 27, 2011

The Capital Christmas Tree

David snapped this photo last night while he was on the DC Mall and near the Capital Christmas Tree:

It's an especially impressive shot when you consider he captured it with his cell phone.

He told me a bit about the tree, mainly that it was 63 footer and a whopping 118 years old. As the tradition calls for, the National Park Service provided it.

We both had the same reaction: 118 years old?! Did it really need to be cut down? The tree lives through two World Wars, the great depression and countless other events and is finally chopped down to be used as a Christmas tree for a few weeks. Man, that's rough. I know, I'm such the Grinch.

Apparently, the tree will be turned into mulch and used in the area...which I suppose means it's not being wasted. But still.

Bah, Humbug.

A Foolproof Anti-Theft System

I've found bulletproof anti-theft system for goodies I want to keep for my own in my fridge. I just attach the following note to said item, and nobody seems to touch it*.

*Yes, I'm aware that Shira could steel items with this note attached. But, in that case, I'd really rather she have it. Never forget the key principle: A happy wife is a happy life.

Monday, December 26, 2011

Another Moment of Bragging: Running a 7 Miler

A couple weeks back, I couldn't help but take a moment to blog about Shira's accomplishment of running a 6 mile route. Today, she crushed that, and ran a 7 miler. I'm already pushing her to map out an 8 miler.

Sure, we're both a bit sore - but man, was it worth it!


View Shira and Ben's 7 Miler in a larger map

Sunday, December 25, 2011

Coach's Customer Service

The zipper on Shira's Coach wallet broke. We weren't quite sure what they could do about it, but we hit up a nearby Coach Outlet to find out. The experience went more or less as described below.

The manager on duty took one look at the broken zipper and said something like "oh, my! Let's get you a replacement." She didn't have that exact model, so she scurried around the store finding wallets that more or less matched the original one. After a couple minutes she had a few options for Shira. The only question she asked was, "which one do you want?" A few minutes at the counter and we were on our way, new wallet in hand.

I was absolutely shocked. No question about when or where the wallet was purchased, or how much the wallet was worth versus the replacement one. No question about whether this was a factory defect or misuse by Shira. No attitude, or push back. She sympathized and fixed the problem.

I've never though of Coach as having great customer service, but they really showed me. Go Coach!

On The Beach

Sure, it may be chilly - but who cares? The beach is still the place to be, right?

Happy Chanukah and Merry Christmas y'all.

Friday, December 23, 2011

Chutzpah Awards

Came across these links over the last few days...talk about Chutzpah!

1. "Insane" e-mail from John Boehner’s office. Long story short, Boehner's press secretary had this e-mail back and forth:

Zinnnnng!

Personally, I love the response and think that the folks over at deathandtaxesmag.com are the ones with the chutzpah - calling that "insane" is just a little overkill, no?

2. WW II needle point. Yes, apparently needlepoint can require chutzpah. Here's the needlework:

And here's the story behind it:

"After six months held by the Nazis in a prisoner of war camp, Major Alexis Casdagli was handed a piece of canvas by a fellow inmate. Pinching red and blue thread from a disintegrating pullover belonging to an elderly Cretan general, Casdagli passed the long hours in captivity by painstakingly creating a sampler in cross-stitch. Around decorative swastikas and a banal inscription saying he completed his work in December 1941, the British officer stitched a border of irregular dots and dashes. Over the next four years his work was displayed at the four camps in Germany where he was imprisoned, and his Nazi captors never once deciphered the messages threaded in Morse code:"

"God Save The King" and "F*** Hitler"

Amazing, no?

3. Siri overcompensating with abortion information. Remember that Siri abortion controversy? Someone worked up a parity on the topic that's just hilarious. For example:

See them all here. Now that's some serious chutzpah.

4. Minnesota Gay Community Apologizes to State Senator Amy Koch.

Dear Ms. Koch,

On behalf of all gays and lesbians living in Minnesota, I would like to wholeheartedly apologize for our community’s successful efforts to threaten your traditional marriage. We are ashamed of ourselves for causing you to have what the media refers to as an “illicit affair” with your staffer, and we also extend our deepest apologies to him and to his wife. These recent events have made it quite clear that our gay and lesbian tactics have gone too far, affecting even the most respectful of our society.
...

And it goes on from there. Youch and well done.

Thursday, December 22, 2011

I Had A Little Dreidel - I Even Won Some Gelt With It

We attended a most excellent Chanukah party tonight. It had it all: fun folks to talk with, delicious latkes, a huge variety of deserts, whip cream(!) and yes, a rousing game of spin-the-dreidel. We left before a true winner could be declared, but I was hanging in there with a few chocolate coins left to my name. It really was tons of fun.

So go ahead, bust out a dreidel, grab some M&M's or other gambling material, and play away. If nothing else, it's a great way to teach kids the joys and sorrow of gambling.

If Christmas Were a Jewish Holiday

How did the presence of this amazing document elude me for so many years? I give you the excruciatingly accurate set of would be Jewish law if Christmas was a Jewish holiday. For example:

1. ANY SPECIES OF TREE IS KOSHER FOR USE AS A XMAS TREE, PROVIDED THAT IT HAS NEEDLES AND NOT LEAVES. IN OUR LANDS IT IS CUSTOMARY TO USE A FIR TREE.(7) IT SHOULD BE REASONABLY FRESH, BUT NOT TOO FRESH, IN ACCORDANCE WITH THE PRINCIPLE "A XMAS TREE WITH NO FALLEN NEEDLES IS LIKE A SUKKAH WITH NO BUZZING BEES."

(7) If the lady of the house already has a fur, then any evergreen may be used.

2. THE TREE SHOULD BE CHOPPED DOWN SPECIFICALLY FOR USE AS A XMAS TREE; IF IT HAD BEEN CUT FOR LUMBER IT IS INVALID. IF THE TREE WAS CUT FOR GENERAL DECORATIVE PURPOSES, BUT NOT SPECIFICALLY AS A XMAS TREE, SOME AUTHORITIES ALLOW IT WHILE OTHERS ARE STRICT. A STOLEN TREE IS NOT VALID FOR THE MITZVAH.(8) FORTUNATE IS ONE WHO IS ABLE TO CHOP HIS OWN TREE HIMSELF.(9)

(8) One who cuts his own tree must make sure that he has permission from the landowner to do so. Ideally, cut only from one's own backyard. A tree taken from a reshus harabim, such as the county park (which is actually a carmelis, not a reshus harabim,) is considered as stolen and pasul.

(9) One who is unable to cut his own tree should make sure to purchase it from a reputable dealer, or one who is certified by a national kashrus organization.

And it goes on and on - it's really quite impressive. Take the section on Havdalah:

IX. HAVDALA

1. THERE ARE MANY OPINIONS REGARDING WHEN THE XMAS SEASON IS OVER.(40) BAIS HILLEL HOLDS THAT XMAS IS OVER WHEN THE LAST ITEM IN THE AFTER XMAS SALE HAS BEEN SOLD. BAIS SHAMMAI IS STRICT AND HOLDS THAT XMAS IS OVER IMMEDIATELY AT THE CONCLUSION OF THE FOOTBALL GAME.

(40) Many are confused by the term "twelve days of Xmas", implying that the Xmas continues until and including January 5. Today, this view is accepted only by the Eastern Orthodox, who hold that December 26 through January 5 constitute Chol Hamoed Xmas. This view is opposed by both the Modern Orthodox and the Ultra Orthodox (and even the Non Orthodox) who hold that Xmas is only one day long, and any context which seems otherwise actually refers to the Xmas *season*.

Amazing and hilarious.

Happy Chanukah Y'all (day #2 and going strong)!

Wednesday, December 21, 2011

All Pumped Up

I'm trying to get back into the habit of donating blood - something I used to do on a somewhat regular basis years ago. Thing is, I'm still nervous around needles but I try not let that slow me down.

This morning's donation, like all the ones before it, was essentially painless and left me with that warm feeling of having done something meaningful for my community (or maybe that's just light-headedness + Fig Newtons?)

This morning, as in the past, I used an Inova Blood Donation center to make my deposit. They'll gladly make an appointment for you to avoid waiting. Seriously, it's a good thing to do, so go make an appointment.

Tuesday, December 20, 2011

Enjoy Gift Giving More - Embrace The Wrapping Process

Happy first day of Chanukah! With the big Ch (or H, I suppose), upon us and Christmas only days away, it was especially fortunate that I ran across Kelli Crowe's creative gift wrap blog entry. She has rounded up a number of cool (and thrifty) ways to make the packages you've purchased look even more appealing. Definitely more fun than focusing on trying to traditional wrapping paper to be perfectly aligned (which I can never do anyway).

Before I had seen Kelli's post, I was thinking I should do something a little different this year in the wrapping department. See, over the last year I've gotten pretty good about using reusable shopping bags, rather than bringing home and being cluttered by scores of plastic bags. So, in the same spirit of re-usability, I wondered what I could wrap my brother's gift in that he could reuse? Here's what I came up with:

Yes, that's a gift wrapped in toilet paper and tied with a dental floss bow. My half serious, half joking logic, is that he can untie the bow remove the TP, and drop them both in a ziplock bag for our next hike or camping trip. Who knows, in a tight spot, those items could be even more handy than the gift I'm giving him?

I suppose I'm going to need to get a bit more clever - after all, not every person is worthy of getting a gift wrapped in TP. Still, Kelli's inspired me to keep looking for clever gift wrapping hacks.

Monday, December 19, 2011

Website I Want: A Political Rorschach Test

A few days back, I was talking to one of my conservative friends and I asked him who his pick was in the GOP field. His response: Herman Cain. What?! How was this possible? Sure, I liked Cain's outsider appeal, and his 9-9-9 tax plan was delightfully audacious. But what about his comments about a Muslim serving in his cabinet, or his odd reading of the first amendment, or his unusual stance on abortion, or the infamous Libya interview question? Didn't these sway my friend? Nope, not really.

Which got me thinking...you've got sites like Politifact.com which try to tease apart truth from lies. And that's a good thing. But I'm curious about what people actually see when they see a clip or transcript. Which is why I think we need the a political Rorschach website. Here's how it would work:

  • Website curators post a clip or transcript to the site (heck, maybe even an article or blog entry)
  • Visitors come to the site perform one of two actions:
    1. They offer a one or two sentence explanation ("I see a clip that's been edited to tell a new story", "Here's proof that candidate X knows nothing about Y!")
    2. They vote on explanations that are most appealing to them

That's it. Over time, I'd think a few different explanations would converge. If all went as planned, you'd get an idea what each constituency was actually interpreting when viewing the same media.

This site isn't really about changing people's minds. Instead, it's about understanding what someone who adamantly disagrees with you can be thinking. Who knows, from there, maybe a little common ground could be found. Or not.

Who's with me?

Review: Conquering YouTube

I really didn't want to like Jay Miles' Conquering YouTube. After all, what a ridiculous title, right? I mean, how short sighted can one person be but to write a book about a single website? Only thing is, when I picked it up I accidentally flipped it to Tip #68, Camera in a Coal Mine, which talks about leveraging the small cameras most novices have by putting them in unusual spots (like in a fridge) to get a unique perspective. At that bit of wisdom, I was hooked (at least hooked enough to rent the book from the library).

Turns out, Conquering YouTube has absolutely nothing to do with YouTube. Really, the book should have been titled Techniques and Exercises You Need To Master To Start Shooing Quality Video. In Miles' defense, Conquering YouTube is wittier.

I love how the author not only gives solid advice, but assigns useful homework assignments to really get you to master the essentials (and does it in a lighthearted, yet not overly goofy way). From learning how to manually operate your video camera to advice on editing, I've got to think that this is an excellent intro to intermediate course on video creation. I'd love to see a book that uses this same approach and format to teach photography.

I definitely knew the book was have an effect on me when I started to find myself decomposing the scenes on TV. I'd find myself thinking: oh look, they used the rule of thirds there -- or, oh look, you can't see the actor speaking, I bet this clip was shot in a totally different take than the one before. Any book that can change how I see the world is a winner in my mind.

If you're interested in getting serious about movies or video, or you know someone who is, this book is the way to go.

Sunday, December 18, 2011

Sugar Overload

Yesterday, I come home from shul to find a big heap of sugar cookies lovingly made and frosted by a crack team of kid bakers. And I woke up from a Shabbat nap to find two amazing gingerbread houses courtesy of David and Maryn (OK, one a house and one a Greek Temple!).

It's like sugar heaven here! And all I had to do was load and unload the dishwasher about 19 times.

What a treat!

Thursday, December 15, 2011

Gotcha of the Day: Combine rows into a single cell in Excel

Last night, Shira posed me a spreadsheet quandary: how do you take a series of rows and combine them together into a single cell (say, comma separated)? After looking around, I realized that there wasn't a built in function that would do this. transpose will turn rows in columns, but it doesn't join items up in a single cell. To get this job done, I was going to have to turn to VB. Gulp.

I knew how I wanted the function work, it should behave like countif. That is, I didn't want it to combine every cell in a range, only those that matched some criteria.

Why Excel offers countif and sumif but doesn't offer concatenateif is beyond me. But, luckily it wasn't beyond MikeRickson over at ozgrid.com. He and a couple other folks provided me with a bunch of wonderful useful bits of knowledge:

1. An implementation of >concatenateif(...):

Function concatenateIf(ByVal compareRange As Range, _ 
    ByVal criteriaEQ As Variant, _ 
    ByVal stringsRange As Range, _ 
    Optional Delimiter As String, _ 
    Optional Unique As Boolean) As String 
     
    Dim stringsRRay As Variant 
    Dim compRRay As Variant 
    Dim i As Long, j As Long 
     
    Set compareRange = Application.Intersect(compareRange, _ 
    compareRange.Parent.UsedRange) 
     
    compRRay = compareRange.Value 
    stringsRRay = compareRange.Offset(stringsRange.Row - compareRange.Row, _ 
    stringsRange.Column - compareRange.Column).Value 
     
    Select Case TypeName(compRRay) 
    Case "Variant()" 
        concatenateIf = Delimiter 
        For i = 1 To UBound(compRRay, 1) 
            For j = 1 To UBound(compRRay, 2) 
                If compRRay(i, j) = criteriaEQ Then 
                    If Unique Imp (InStr(concatenateIf, Delimiter & CStr(stringsRRay(i, j)) & Delimiter) = 0) Then 
                        concatenateIf = concatenateIf & CStr(stringsRRay(i, j)) & Delimiter 
                    End If 
                End If 
            Next j 
        Next i 
        concatenateIf = Left(concatenateIf, Len(concatenateIf) - Len(Delimiter)) 
        concatenateIf = Mid(concatenateIf, Len(Delimiter) + 1) 
    Case "Double", "String", "Boolean": Rem cell.count = 1 
        If compRRay = criteriaEQ Then concatenateIf = CStr(stringsRRay) 
    Case Else 
        concatenateIf = TypeName(compRRay) 
    End Select 
End Function 

2. A simpler concat function which dispenses with the criteria concept:


Function Concat(r As Range) As String 
    Dim av  As Variant 
    Dim v   As Variant 
     
    av = Intersect(r, ActiveSheet.UsedRange) 
    For Each v In av 
        If Not IsEmpty(v) Then 
            Concat = Concat & v & "," 
        End If 
    Next 
    Concat = Left(Concat, Len(Concat) - 1) 
End Function

3. Instructions on how to set these functions up.

[The code] needs to be posted in a code module. Open the VBE (Alt+F11), and from that menu bar, do Insert > Module, and paste the code into the window that opens.

Besides providing some useful code, this forum post showed me just how easy it is to add new functions to Excel. I've written VB code before, but it's usually as a stand alone app, and not something that truly leverages the existing Excel model.

I can't remember the last time such a brief forum post was so enlightening.

With the above code in place I was able to say:

 =concatenateif(A:A, "=100", C:C, ", ")

(Where column A (A:A) contained a bunch of numbers, and column C contained the text I wanted to join up with ", ".)

Wednesday, December 14, 2011

Pocket Dump: Winter Edition

It's been a while since I've done a pocket dump, so here's the latest snapshot of what's in my pockets. A few items have changed due to the weather, and the need to be more jeans friendly (less bulging is a good thing, right?).

I'd love to know what your EDC is -- do share in the comments.

In my pants pockets:

  • A CPR mask and gloves smooshed and taped between two business cards. What good is being CPR certified if you aren't ready for action, right? The business cards approach seems to be the smallest possible way to carry the items.
  • A Pilot G2 pen. Still my favorite writing instrument.
  • A Schrade Tactical Pen. This currently replaces my Alpha Innovations Stylus Kubaton. I like that it does extra duty as a pen, and is nice and solid. If the Alpha Innovations stylus worked with my G2 I may prefer it better.
  • Android G2. This guy is really beat up, but it's still holding its own.
  • Regular old wallet. A couple extra safety pins (for repairs), a paper clip (for whatever) and stickers (to entertain kids) are in it. Other than that, there's nothing unusual about it.
  • A hanky. My probably most used EDC item.
  • Keyring that hasn't changed much since I last inventoried it. Still love everything on it, and find it all useful. The compass came in handy getting oriented on our last trip, the USB drive held backup copies of my passport and other travel documents, the pill fob saved Shira during a headache (thanks to the headache medicine within), I could go on, but you get the point.
  • A P-51 can opener and Derma-Safe razor blade rubber banded together. This little setup has replaced my Swiss Army knife for daily carry. It's much slimmer in the pants, which prompted me to try it. So far, I'm really impressed. The P-51 has come in handy a number of times, the Derma-Safe is super sharp. The rubber bands have probably gotten the most use, as I'll take them off and use them for various odds and ends. I love that the setup is basically disposable if I end up at place where I can't bring a knife. There are still times when a Swiss Army knife makes the most sense, but for EDC, this little combo is working.
  • A cheapy 3x5 notepad. Absolutely essential.

Gone is the lanyard - I never got any use out of it.

In my jacket pockets:

It's almost winter time, which means wearing jacket, which means *more pockets*. Whoo! Here's what's been floating around in my coat:

  • Brandless knit hat from REI. Your mom always told you to wear a hat, right? Listen to mom.
  • Seirus Gloves from REI. I love these guys. Super lightweight, allow for lots of dexterity, yet are wind resistant and keep you warm.
  • A Buff. The ultimate neck warmer + balaclava + whatever else you can think of. Love this guy.
  • A Mini-Bic Lighter. When it's cold out, it just seems right to carry around a way to make fire instantly.
  • An urban survival kit packed in, of course, an Altoids tin. It's got headphones for G2, quarters for the meter, dental floss and more.
  • Sea to Summit day pack. Another frequently used item. Definitely don't underestimate this guy.

So, nu? What's in your pockets?

Tuesday, December 13, 2011

Up Close and Personal: Playing with Digital Concepts Macro Filter Set

Chanukah came early this year, as a gift from my Sister and Brother-in-law showed up a few days ago. Sure, I could have been an adult about it and waited for the holiday, but what fun would that be? They bought me two items off my wishlist, the Digital Concepts 1 2 4 10 Close-Up Macro Filter Set and a remote shutter release, both for my relatively new EOS T3i.

I'm quite impressed with both items. The closeup filter (basically, magnifying glasses) Polaroid branded item, and not some off brand product. The lenses look solid to me, and the case is impressive too; not some after thought cheapy item you might expect.

There's not much to the shutter release, but it worked perfectly out of the box with the camera.

I had the new toys, but I didn't have any idea what I wanted to photograph. Then it occurred to me, I may have just the right set of items from our recent trip. Whenever I travel, I usually pick up various somewhat interesting pebbles from where I've been. I've been doing this for years, and have (a) never taken the time to label anything and (b) never really found a use for the rocks. But, as souvenirs go, a rock from the top of Table Mountain or Robben Island seems precious to me.

They're small and I have new close-up equipment - I thought they'd be a great fit. Alas, I'm totally underwhelmed by how the photos turned out. Though, I blame that not on the new equipment but on my poor composition skills. Still, in the interest of sharing at least some results, here they are.

With close up lenses like these, very narrow depth of field is to be expected. So, I cranked down the aperture as far as I could, and used my new shutter release to trigger the camera. that way, I would reduce the chances of camera shake.

One other little tidbit: the cork in the photos was one that I found at the Cape of Good Hope. If you can't find a message in a bottle, you can at least find the cork that belonged to it (or, to the people who were drinking on the beach last night).

Like I said: I'm really impressed by the macro filters. Definitely a lot more polished product than one might expect for the relatively low close.

Sunday, December 11, 2011

Meeting Georgia

Today I met Georgia. Georgia is perfect. Georgia is also a little over two weeks old, and the first born of one of my best friend's from High School.

How did this happen? How did we go from sitting around on a Saturday night watching cruddy movies and playing charades (yes, I was running with quite the roudy crowd in high school!), to sitting around discussing sleep strategies and day care options with my friend and her BABY?!

Yeah, this one has hit me hard.

But Georgia is so cute. And my friend and her husband seem to have it so together. They just make it look so easy.

Anyway, Georgia, when you're old enough, I'll play charades with you and tell you all the stories about your mommy growing up she probably doesn't want you to know. I can't wait.

Twinners +1 - Visiting the "Fish Museum"

Today we made our way to the Boston Aquarium, where Elana, the Kids, Shira and Myself took in the "fish museum" (the kids wanted another visit to the Children's Museum, so we promised them the Fish Museum instead).

The personalities of the kids were out in force today. Fearless Chana was perturbed that she wasn't allowed to swim in the tanks with the fish, and all but climbed into the sting ray and (baby) shark tank. Dovid, our intellectual one, was delighted to count star fish and study the sting rays, but had zero interest in touching anything (heck, he didn't want to put his hands in the Dyson hand dryers, for fear that he might not get them back when it was done making all that noise!). And Tzipora was memorized by the giant fish swimming by, and was soaking it all up.

Shira and I felt especially proud that a little over a week ago we were at Boulder's Beach, where one (or more?) of the penguins featured at the aquarium were from.

Speaking of fun activities, yesterday, on our Shabbat walk, we poked our heads into one of the fire station's near the house. One of the firemen on duty eagerly invited us in and suggested we show the kids around the trucks. They even started up one of the engines and got the lights going. Of course, the whole thing was a bit overwhelming for the kids, but they did work up the courage to approach the truck and ended up having a great time. And I was right along with them, soaking it all in. Score one for the Boston FD, they couldn't have been more welcoming to the kiddies. I'd suggest dropping by your local station to see if they're as nice.

Would you believe we took more photos today? Yeah, just a few. These kids are just so dang cute.

Friday, December 09, 2011

Twinners +1 - Visting the Boston Children's Museum

Wow, what a day! We got into Boston this morning, and have been whooping it up with the Twins +1 all day. The main event was a trip to the Boston's Children Museum (which is more activity center, than traditional museum - but it was all awesome).

The Twins couldn't get enough of the water table, and Tzipora was totally drumming to Latin beats in the baby room. I think I probably enjoyed the construction room more than the kids. I even let them sit in the Bobcat, instead of pushing them out of the way so I could monopolize. See how mature I am?

Nobody, including myself, wanted to go home, but alas, Shabbat was approaching and we had a very full day.

Here's a few of the 400+ photos we shot of the kids that day. The new camera plus wonderful subjects sure makes for lots of photos.

Gotcha of the Day: Porting a WordPress Blog to Magento's Blogging Plugin

Magento has a pretty sweet Blogging plugin that one of my clients wanted to use. No problem, right? Except for one itty bitty catch, they've been blogging in WordPress and sure would love to port over their content.

Unfortunately, the Magento Blogging plugin doesn't offer any sort of importing capability, so I was going to need to get creative.

After a bit of poking around, I finally settled on a strategy: I would load both the WordPress and Magento databases into the same mysql server instance, and run SQL queries that would SELECT from WordPress tables and INSERT into Magento tables.

The strategy turned out to work surprisingly well. The queries (described below) weren't that tricky to write, and while it took a little practice to get all the data inserted properly, once I got the recipe right, the import went smoothly.

One word of caution: Magento will refuse to operate if you manage to insert duplicate IDs in the blogging or category tables. I solved this by making sure that before importing I cleared out whatever was in the Magento blogging database. This worked well because my client didn't have any articles written yet (only test stuff they wouldn't mind losing). In other words, mind the DELETE statements below - understand what they are doing before you run them :-).

In general, loading up two databases and SELECT/INSERT'ing between them is an approach I've found can work exceedingly well. After I implemented this solution, I remembered that months back I did something similar with WordPress and ExpressionEngine. Sure, I could have exported WordPress to RSS or CSV and written custom code to import it, but why bother with all that parsing when the database already has things structured so well?

Here's the import script. Note I've got two databases, one named wordpress and one named magento. For no particular reason, I'm changing magento at the top of the script and explicitly pulling from wordpress.

USE magento;

-- Target: aw_blog
DELETE FROM aw_blog; -- Careful!  Start off by deleting all our data

-- Magic happens here: fill up Magento's (aw_blog) post table from WordPress
INSERT INTO aw_blog(post_id, title, post_content, status, created_time, update_time, identifier,
                    user, update_user, meta_keywords, meta_description, comments, tags, short_content)
 SELECT
    p.ID,
    p.post_title,
    p.post_content,
    1,
    p.post_date,
    p.post_date,
    p.post_name,
    a.user_nicename,
    a.user_nicename,
    '',
    '',
    0,
    '',
    p.post_excerpt
  FROM wordpress.wp_posts p JOIN wordpress.wp_users a ON p.post_author = a.ID
  WHERE
    p.post_type = 'post'        AND
    p.post_status = 'publish';

-- The hard work is done. Now we need to fill up a few more tables with corresponding
-- IDs. Without these tables, Magento gets confused and won't be able to find posts.

-- Target: aw_blog_post_cat
DELETE FROM aw_blog_post_cat;

INSERT INTO aw_blog_post_cat(cat_id, post_id)
  SELECT DISTINCT 1, post_id FROM aw_blog;

-- Target: aw_blog_store
DELETE FROM aw_blog_store;

INSERT INTO aw_blog_store(post_id, store_id)
  SELECT DISTINCT post_id, 0 FROM aw_blog;

-- All Done!

Thursday, December 08, 2011

Handy Running Tool: eGear Guardian Strobe Light

Now that it gets dark at 2pm (OK, closer to 4:30pm, I suppose), I feel like I should take some extra steps to be visible while running. A couple of the routes I take use bike paths which can be pretty dang dark.

After doing a bit of shopping on Amazon, I took the plunge and purchased a Guardian eGear Signal Light. It promised to be compact and bright. I was so happy with it, that I immediately turned around and bought a couple more colors.

Here's what they look like:

(The second photos is taken with the lights on top of a 3x5" notepad to show scale.)

I really like the design of these guys:

  • The twist-to-turn-on mechanism is fairly tight, so I don't worry about accidentally turning them on or off.
  • They are waterproof and somewhat drop-proof (3 meters?). I've taken them out in the rain and dropped them from waist height, and so far, no issues.
  • They're really lightweight (a bit more on that below) and do easily clip to anything
  • You can reverse the batteries to switch from a strobe light to a standard flash light. This makes for a simple design, and provides a nice little backup.
  • They aren't terribly expensive

I find that I can clip one light to the front of my hat, another to the back, and head off into the dark without even noticing the lights are there. Here's what the setup looks like:

As for areas of improvement, I was going to mention that of the three lights I received, the green one came with a simpler clip than the others. It's smooth and resembles a money clip, while the other colors have an improved design, including a lip that catches on clothing to be more secure, and a hole in the back which also looks useful. I was ready to write up a warning that you should make sure to get the newer clip. Thing is, this morning I sent an e-mail to eGear and asked them about the clip difference. Within an hour, I got a response back and a promise to send me an updated clip style for no charge.

So, now I'm even more impressed, because eGear's customer service came through so well.

I suppose the only real con is that I don't have a good way of measuring and comparing how effective this strobe is against what else is out there. For my purposes, which is mostly piece of mind, the lights work well. But, I can't really say that they will outperform other lighting options. I just know their awfully convenient (and they do have a claim of 2 mile visibility, for whatever that's worth).

If you're running in the dark, I say give 'em a try.