tag:blogger.com,1999:blog-332605992024-03-15T18:09:54.342-07:00Imposterrific - a blog by Jeff ScudderCoding can be fun!Jeff Scudderhttp://www.blogger.com/profile/13002167096451875802noreply@blogger.comBlogger105125tag:blogger.com,1999:blog-33260599.post-87477680439412408242023-09-30T16:58:00.007-07:002023-09-30T17:20:34.257-07:00Guitar Wiring - Phase Switch and Blend Pot <p>Half the fun of building a partscaster is to experiment with unique guitar circuitry. The first guitar that I made has been a platform for experimentation and the journey continues. A couple of things bugged me about the <a href="https://blog.jeffscudder.com/2020/09/partscaster-t-style-with-p-rails.html">first iteration of this guitar's wiring</a>, so I decided to try a couple of new idea.
<p>One was to use a knob that changes the balance between the neck pickup and the bridge pickup. This is done using what's called a blend/balance potentiometer. In the middle position, there is no added resistance to either pickup, then when turned one way or the other there is added resistance (lower volume) from one of the two pickups.
<p>The second idea, was to add a switch to provide an out-of-phase sound. The effect is to create a thinner brighter sound because some of the waveforms that come from the two pickups are canceling each other out. Perhaps the most famous example of out of phase pickups is in a guitar called <a href="https://en.wikipedia.org/wiki/Greeny_%28guitar%29">Greeny</a>. Here's the wiring diagram:
<div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiTxc1L1qwz0ELo4yBrmPHSbFIXfHi10c1gai2pb0ahpA0wzcDOOFtTi4oLFak1Ujlxwmzimo3JgQbd3E0rOLegMqLK560Emnjze1CoLE7KcKxVTOZUgS79CyaGcRcMzFSIYgm0ARbOTNRF6dd8cbsUv_MlWu__IjY91umU6QnFHX8QM2UKJ_g1/s1440/2018-Guitar-Wiring-Version-C.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1080" data-original-width="1440" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiTxc1L1qwz0ELo4yBrmPHSbFIXfHi10c1gai2pb0ahpA0wzcDOOFtTi4oLFak1Ujlxwmzimo3JgQbd3E0rOLegMqLK560Emnjze1CoLE7KcKxVTOZUgS79CyaGcRcMzFSIYgm0ARbOTNRF6dd8cbsUv_MlWu__IjY91umU6QnFHX8QM2UKJ_g1/s320/2018-Guitar-Wiring-Version-C.png" width="320" /></a></div><br /><div><br /></div>
<p>This was a fun experiment. Though after using this guitar for a while now, I find though that I rarely touch the blend pot, nor do I use the phase switch. The fact that the phase switch only effects the middle position when both pickups are on makes it a little limited. Also, if the blend pot isn't in the balanced center spot, the out of phase effect is greatly limited. Having a switch to brighten up the sound is still something I'm interested in and I'm wondering if putting in a high pass filter using a capacitor would be a more effective technique since it could apply to all pickup selection positions. Jeff Scudderhttp://www.blogger.com/profile/13002167096451875802noreply@blogger.com0tag:blogger.com,1999:blog-33260599.post-79818370897175903002021-08-17T00:16:00.005-07:002021-08-17T00:53:05.408-07:00The 2021 Guitar - In Search of the Guitar That Can Do It AllOn any given Sunday, I play covers that call for a few different electric guitar styles. I like to get as close to the original sound as possible without the hassle of bringing three or four different guitars. (The Kemper mimics the sounds of multiple different amps, so that side of the equation is taken care of.) What if I could get all of those great sounds, the brightness and clarity of single coil pickups, the power and mid-range sweetness of humbuckers, in a single guitar? Here's my latest attempt.
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-jsZIl3YuYSs/YRlQfieZs7I/AAAAAAABhxE/rXb3Oo0T9HwT60XiICZIkCjcBIs_W7rTgCPcBGAsYHg/s4032/PXL_20210713_054037882.jpg" style="display: block; padding: 1em 0; text-align: center; "><img alt="" border="0" height="400" data-original-height="4032" data-original-width="3024" src="https://1.bp.blogspot.com/-jsZIl3YuYSs/YRlQfieZs7I/AAAAAAABhxE/rXb3Oo0T9HwT60XiICZIkCjcBIs_W7rTgCPcBGAsYHg/s400/PXL_20210713_054037882.jpg"/></a></div>
<p>At it's heart, this is a Telecaster inspired machine. The grit and cutting voice of a wound-hot Tele pickup has become one of my favorite sounds and the clarity and chiminess of a Tele bridge pickup gives the Tele a versatility that works for many styles. To the Tele foundation, I added a high output humbucker pickup and stuck it in the middle position. This is a bit unusual as most humbucker equipped guitars have two pickups, with higher output on the bridge pickup. Using the humbucker in this spot provides a sound that pushes the amp much harder than the other pickups while emphasizing the mid-range frequencies, just what is needed to round out the sonic versatility of this guitar.
<p>Here's this new guitar in action, first the neck pickup, thin and chimey, then the the grittier middle humbucker pickup:
<div class="separator" style="clear: both; text-align: center;"><iframe src="http://www.youtube.com/embed/cSONJ_9C5I4"
width="560" height="315" frameborder="0" allowfullscreen></iframe></div>
<p>The controls for the guitar are standard modern tele controls: three way switch for the neck and bridge pickups (neck, both, bridge) with a single volume and tone control. To accomodate the additional middle pickup, I added a volume knob which can by pulled out to switch the coils into parallel, pushed down they are in series. There is a three-way toggle switch on the horn of the guitar which selects between the standard tele circuit, the middle humbucker only, or both. Using the two switches (tele blade switch, toggle on the horn) any combination of pickups can be selected. As an added bonus, the tone knob can also be pulled out to bypass the tone circuit, letting all of those glorious highs slip through.
<p>This wiring diagram describes the full circuit for the guts of the guitar:
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-ovgdznWXmjg/YRtn1tmtx9I/AAAAAAABhzc/1AUTbODNZa8f7zz05yCch1GT2RPCdlS7gCLcBGAsYHQ/s2048/The2021GuitarWiringA.png" style="display: block; padding: 1em 0; text-align: center; "><img alt="" border="0" height="400" data-original-height="2048" data-original-width="1024" src="https://1.bp.blogspot.com/-ovgdznWXmjg/YRtn1tmtx9I/AAAAAAABhzc/1AUTbODNZa8f7zz05yCch1GT2RPCdlS7gCLcBGAsYHQ/s400/The2021GuitarWiringA.png"/></a></div>
<p>As for the look, I went for a somewhat aged 50s tele: Butterscotch blonde with a bit of relicing to show some where, especially around the lower bout where my elbow tends to run the body of the guitar.
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-b8yeXzSTIKQ/YRnvu1Xe3OI/AAAAAAABhx4/akHwQ2ySkZ4WP9CtVsqc2Sc4P-Xh-ydZwCPcBGAsYHg/s4032/PXL_20210711_044502424.jpg" style="display: block; padding: 1em 0; text-align: center; "><img alt="" border="0" height="400" data-original-height="4032" data-original-width="3024" src="https://1.bp.blogspot.com/-b8yeXzSTIKQ/YRnvu1Xe3OI/AAAAAAABhx4/akHwQ2ySkZ4WP9CtVsqc2Sc4P-Xh-ydZwCPcBGAsYHg/s400/PXL_20210711_044502424.jpg"/></a></div><div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-RFRWrySxfl0/YRnsk5fnWgI/AAAAAAABhxk/PQFTJFi0-Zgvbr2WyJcZXljHoQZaUn4xwCPcBGAsYHg/s4032/PXL_20210713_054319304.jpg" style="display: block; padding: 1em 0; text-align: center; "><img alt="" border="0" height="400" data-original-height="4032" data-original-width="3024" src="https://1.bp.blogspot.com/-RFRWrySxfl0/YRnsk5fnWgI/AAAAAAABhxk/PQFTJFi0-Zgvbr2WyJcZXljHoQZaUn4xwCPcBGAsYHg/s400/PXL_20210713_054319304.jpg"/></a></div><div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-1CuvKfYx7HI/YRnskzNa_HI/AAAAAAABhxk/_nesrvpfAMMJ_b_BWBdcqWS4fuIt5HBjgCPcBGAsYHg/s4032/PXL_20210713_053946196.jpg" style="display: block; padding: 1em 0; text-align: center; "><img alt="" border="0" height="400" data-original-height="4032" data-original-width="3024" src="https://1.bp.blogspot.com/-1CuvKfYx7HI/YRnskzNa_HI/AAAAAAABhxk/_nesrvpfAMMJ_b_BWBdcqWS4fuIt5HBjgCPcBGAsYHg/s400/PXL_20210713_053946196.jpg"/></a></div><div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-YsqAmRLUGsA/YRnsk7aeQ6I/AAAAAAABhxk/5Vz4MCxUPT0gNZO7Xreetml6T1BolgObACPcBGAsYHg/s4032/PXL_20210713_053958303.jpg" style="display: block; padding: 1em 0; text-align: center; "><img alt="" border="0" height="400" data-original-height="4032" data-original-width="3024" src="https://1.bp.blogspot.com/-YsqAmRLUGsA/YRnsk7aeQ6I/AAAAAAABhxk/5Vz4MCxUPT0gNZO7Xreetml6T1BolgObACPcBGAsYHg/s400/PXL_20210713_053958303.jpg"/></a></div>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-TOWLHqmA-9Y/YRnwOmMYIpI/AAAAAAABhyI/i1fno0h65kQZfA-5k2-9q63AJlyqPY8igCPcBGAsYHg/s4032/PXL_20210816_045636765.jpg" style="display: block; padding: 1em 0; text-align: center; "><img alt="" border="0" height="400" data-original-height="4032" data-original-width="3024" src="https://1.bp.blogspot.com/-TOWLHqmA-9Y/YRnwOmMYIpI/AAAAAAABhyI/i1fno0h65kQZfA-5k2-9q63AJlyqPY8igCPcBGAsYHg/s400/PXL_20210816_045636765.jpg"/></a></div>
<p>Now for the detailed specs:
<ul>
<li>Body
<ul>
<li>Shape: Telecaster (traditional)
<li>Wood: Alder
<li>Finish: Nitrocellulose Laquer (Blonde undercoat, Butterscotch topcoat) then lightly reliced using high grit sandpaper. Covered with a final coat of Tru-oil.
<li>Pickguard, solid black
<li>Bridge: vintage brass sadles - compensated for improved intonation
</ul>
</li>
<li>Neck
<ul>
<li>Shape: Telecaster with Vintage/Modern truss rod access
<li>Wood: Solid maple
<li>Profile: Warmoth Boatneck
<li>Radius: Warmoth compound radius (10"-16")
<li>Frets: Stainless steel size 6150 (medium jumbo)
<li>Finish: Tru-oil
<li>Tuners: vintage style - string inserts in the top
</ul>
</li>
<li>Electronics
<ul>
<li>Pickups:
<ul>
<li>Bridge: <a href="https://www.dimarzio.com/pickups/stacked-hum-canceling-tele/area-hot-t-bridge">Dimarzio Area Hot T Bridge</a>
<li>Middle: <a href="https://www.dimarzio.com/pickups/high-power/super-distortion">Dimarzio Super Distortion</a>
<li>Neck: <a href="https://www.dimarzio.com/pickups/stacked-hum-canceling-tele/area-t-neck">Dimarzio Area T Neck</a>
</ul>
</li>
<li>Pots: 250k push pull pots for tele volume and tone controls, 500k push pull pot for middle pickup volume control
<li>Switches: Three way blade switch for tele controls, three way LP-style toggle switch for selecting between tele controls and middle pickup
<li>Tone Capacitor: .022uF
<li>Tone Bleed Circuits: .001uF capacitor with 150K-ohm 1/4-watt resistor in parallel. This is used on both volume knobs.
</ul>
</li>
</ul>
<p>This was a fun build and is a blast to play. Is this the only guitar I'll be bringing to gigs? Only time will tell.Jeff Scudderhttp://www.blogger.com/profile/13002167096451875802noreply@blogger.com0tag:blogger.com,1999:blog-33260599.post-7703123706757918642020-09-17T22:39:00.006-07:002021-08-15T21:52:42.631-07:00Partscaster: T style with P-RailsSuper pleased with this guitar that I put together from custom parts a short while ago:
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-Js2AA9NkKUI/X0K8RKfxdII/AAAAAAABQsM/iF2mN3qktKU9gzBKwboHJ4sP1G_ZzEUPACPcBGAsYHg/s4048/IMG_20190101_143339.jpg" style="display: block; padding: 1em 0; text-align: none;"><img alt="" border="0" height="400" data-original-height="4048" data-original-width="3036" src="https://1.bp.blogspot.com/-Js2AA9NkKUI/X0K8RKfxdII/AAAAAAABQsM/iF2mN3qktKU9gzBKwboHJ4sP1G_ZzEUPACPcBGAsYHg/s400/IMG_20190101_143339.jpg"/></a></div>
<p>One of my life-long passions has been creating music. For the past decade and a half, the form that musical expression has taken is in playing the guitar. I've played most Sundays in church for the past several years and over time, I've been exploring different variations on amps, effects, and guitars to try to find the perfect balance of tones, to fit the mood of the moment in music.
<p>Since many of the songs we play are by different groups, who each use different instruments, I've been looking for a way to have a wide variety of different sounds on tap. Ideally, this wouldn't require carting half a dozen different guitars and amps on stage each weekend. This started me looking for different styles of guitar pickups that are versatile and mimic a number of different popular configurations. When I learned about Seymour Duncan's <a href="https://www.seymourduncan.com/single-product/p-rails">P-Rails</a> pickups, they sounded like a perfect solution for the kind of versatility I sought.
<p>These pickups include a P90 pickup as well as a "rail" style coil, both in a tidy package that fits a space for most humbucker pickups. If wired to switch between the P90, the rail pickup, or both, this one pickup could do triple-duty; matching three common pickup styles. Seymour Duncan also provides a great way to handle the switching between these different modes in their <a href="https://www.seymourduncan.com/single-product/triple-shot">Triple Shot mounting rings</a>. These are essentially pickup rings that also include two small switches, and by flipping through different combinations, the pickups can be run as: P90-only, rail-only, both in parallel, and both in series. My mind was swimming with possibilities.
<p>With the pickups sorted out, now the question was, what kind of platform should these pickups be put into? I've recently been enjoying Telecaster guitars, and the traditional shape and style of an early 1950s Telecaster has a timeless appeal that seemed like an inconspicious way to bring a surprising amount of versatility on stage. Rather than buy a Tele to rip it apart, I thought I could start fresh, and it seemed like building my own Tele-style guitar from parts might not be too far a stretch for me, as little woodworking experience as I had had at this point. The place many people turn for custom guitar parts <a href="https://www.warmoth.com/">Warmoth</a>, which has a great reputation for high quality custom work. I choose a Telecaster <a href="https://www.warmoth.com/guitar/bodies/">shape</a> routed for Humbucker pickups, made of Alder (same as the American Standard Telecaster I also have).
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-AITf4Lx0Oo0/X0K5fia2xVI/AAAAAAABQr4/4D0_lRjtFXQFyfXBc5tH7FnDRWSVOtHnwCPcBGAsYHg/s4048/IMG_20181214_170322.jpg" style="display: block; padding: 1em 0; text-align: none;"><img alt="" border="0" width="400" data-original-height="3036" data-original-width="4048" src="https://1.bp.blogspot.com/-AITf4Lx0Oo0/X0K5fia2xVI/AAAAAAABQr4/4D0_lRjtFXQFyfXBc5tH7FnDRWSVOtHnwCPcBGAsYHg/s400/IMG_20181214_170322.jpg"/></a></div>
<p>For the neck of the guitar, I had a couple of unique things in mind. First was the thickness of the neck. I have relatively long fingers, and the thin necks on some electric guitars tend to cause discomfort on long playing sessions. I've found thicker necks to be much more comfortable, so I decided to pick a <a href="https://www.warmoth.com/guitar/necks/backcontours.aspx">Boatneck</a> profile when ordering from Warmoth. The second non-traditional detail that I had in mind was to spring for stainless steel frets. I dislike the idea of the frets wearing down over the years as I play, and I wanted to build something that I'd enjoy playing for years to come. The durability of stainless frets might mean that I'll never need to refret this neck, which sounds like a win to me.
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-DwxbHKmnu3o/X0K5flS2UZI/AAAAAAABQr4/wXJhPNVxp4IxTg08odyD_KPGdMIqrFYxgCPcBGAsYHg/s4048/IMG_20181214_170007.jpg" style="display: block; padding: 1em 0; text-align: none;"><img alt="" border="0" width="400" data-original-height="3036" data-original-width="4048" src="https://1.bp.blogspot.com/-DwxbHKmnu3o/X0K5flS2UZI/AAAAAAABQr4/wXJhPNVxp4IxTg08odyD_KPGdMIqrFYxgCPcBGAsYHg/s400/IMG_20181214_170007.jpg"/></a></div>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-YaQCFxnnEB8/X0K5fp3ItCI/AAAAAAABQr4/7zghJvyA0jAPvFVNDLEeBrC55_1TArTdQCPcBGAsYHg/s4048/IMG_20181214_170102.jpg" style="display: block; padding: 1em 0; text-align: none;"><img alt="" border="0" width="400" data-original-height="3036" data-original-width="4048" src="https://1.bp.blogspot.com/-YaQCFxnnEB8/X0K5fp3ItCI/AAAAAAABQr4/7zghJvyA0jAPvFVNDLEeBrC55_1TArTdQCPcBGAsYHg/s400/IMG_20181214_170102.jpg"/></a></div>
<p>The last question was the finish. Traditionally, the early Fender guitars were finished with nitrocellulose laquer, and even today many high end instruments use this as the weatherproof coating. While in some ways inferior to modern materials, there are two aspects to this finish that I found attractive: ease of applying the finish and repairing mistakes (thanks to its ability to "burn in" to previous layers) and the way that it hardens and wears over time. The worn-in look is quite popular these days, especially on telecasters, and while I have no plans to artificially relic this guitar, I'd love to watch how the finish ages over the years. I decided to apply the finish myself, so I bought a few rattle cans of nitrocellulose laquer in butterscotch transparent and clear. I applied a few coats of clear as a sealer, then around 4 coats of butterscotch, followed by around 10 coats of clear on top. The neck of the guitar I sprayed with clear only. After waiting a couple of weeks for it to dry, I wet-sanded with a series of increasingly high grits of sandpaper. Starting from around 180 grit, I worked up slowly to 4000. It was pretty nerve-wracking at the start, seeing the shiny, but a bit orange-peel-y, finish turn dull and flat. Not until over 2000 grit did it start to shine again.
<p>The painting all finished, it was time to put it together! For the wiring, I thought it would be cool to try a 4-way switch with positions for neck pickup only, bridge pickup only, both in parallel, and both in series (to match the multiple ways to wire each pickup). This would create a dizzying array of pickup combinations - 40, to be precise, which is probably too many, but hey, if you've got it why not! The last detail of the wiring which is somewhat unusual is the "treble bleed circuit" which consists of a capacitor + resistor on the volume potentiometer. It allows some of the high frequencies to continue to "bleed" through the volume control as it is turned down. The effect is that as the volume is turned down, the sound gets "thinner" and more bright, rather than darker and more muddy which would naturally happen on a volume pot without this added detail. I've loved this feature of my American Standard Telecaster, so I decided to duplicate it here.
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-VosJImW_Qh0/X0K5flqxsvI/AAAAAAABQr4/bPtV3l-EIKIUXPC4B1n7-pjGGb8xj5gDgCPcBGAsYHg/s4048/IMG_20181229_213634.jpg" style="display: block; padding: 1em 0; text-align: none;"><img alt="" border="0" height="400" data-original-height="4048" data-original-width="3036" src="https://1.bp.blogspot.com/-VosJImW_Qh0/X0K5flqxsvI/AAAAAAABQr4/bPtV3l-EIKIUXPC4B1n7-pjGGb8xj5gDgCPcBGAsYHg/s400/IMG_20181229_213634.jpg"/></a></div>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-SgtV4oVCVyE/X0K8RDX3UpI/AAAAAAABQsM/dwMJzNef1SE6I41OmURwmRnWaHYMCIHZgCPcBGAsYHg/s4048/IMG_20190111_214920.jpg" style="display: block; padding: 1em 0; text-align: none;"><img alt="" border="0" width="400" data-original-height="3036" data-original-width="4048" src="https://1.bp.blogspot.com/-SgtV4oVCVyE/X0K8RDX3UpI/AAAAAAABQsM/dwMJzNef1SE6I41OmURwmRnWaHYMCIHZgCPcBGAsYHg/s400/IMG_20190111_214920.jpg"/></a></div>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-EoL6So2Ku7w/X0K8RL3LNgI/AAAAAAABQsM/rYL2EGwLZUUskq7ujtYdK-JetIgtdf1nACPcBGAsYHg/s4048/IMG_20190111_220701.jpg" style="display: block; padding: 1em 0; text-align: none;"><img alt="" border="0" width="400" data-original-height="3036" data-original-width="4048" src="https://1.bp.blogspot.com/-EoL6So2Ku7w/X0K8RL3LNgI/AAAAAAABQsM/rYL2EGwLZUUskq7ujtYdK-JetIgtdf1nACPcBGAsYHg/s400/IMG_20190111_220701.jpg"/></a></div>
Here's the schematic for the wiring:
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-jNeE8LrW_QM/YRnu3nnlVpI/AAAAAAABhxw/Dnv971BxZLIU6GwalOP8kAvxTV3lxIm3ACLcBGAsYHQ/s1440/2018-Guitar-Wiring-Version-B.png" style="display: block; padding: 1em 0; text-align: none; "><img alt="" border="0" width="400" data-original-height="1080" data-original-width="1440" src="https://1.bp.blogspot.com/-jNeE8LrW_QM/YRnu3nnlVpI/AAAAAAABhxw/Dnv971BxZLIU6GwalOP8kAvxTV3lxIm3ACLcBGAsYHQ/s400/2018-Guitar-Wiring-Version-B.png"/></a></div>
Over the course of a few months, I worked on this over the weekends and vacations and finally wrapped it all up around Christmas time. Without further ado, the pictures:
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-5eVRfCD90kE/X0K5fiCdNKI/AAAAAAABQr4/nKTZ_GTPi58gfLAfF1SmnPVHbJ6GUgXzgCPcBGAsYHg/s4048/IMG_20190524_232454.jpg" style="display: block; padding: 1em 0; text-align: none;"><img alt="" border="0" height="400" data-original-height="4048" data-original-width="3036" src="https://1.bp.blogspot.com/-5eVRfCD90kE/X0K5fiCdNKI/AAAAAAABQr4/nKTZ_GTPi58gfLAfF1SmnPVHbJ6GUgXzgCPcBGAsYHg/s400/IMG_20190524_232454.jpg"/></a></div>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-oX4A_Hzlc18/X0K5fgwmmyI/AAAAAAABQr4/MglS8IS0DV4mu1Z5LoQ4o6VrTko9XULlgCPcBGAsYHg/s4048/IMG_20190101_144752.jpg" style="display: block; padding: 1em 0; text-align: none;"><img alt="" border="0" height="400" data-original-height="4048" data-original-width="3036" src="https://1.bp.blogspot.com/-oX4A_Hzlc18/X0K5fgwmmyI/AAAAAAABQr4/MglS8IS0DV4mu1Z5LoQ4o6VrTko9XULlgCPcBGAsYHg/s400/IMG_20190101_144752.jpg"/></a></div>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-upwNagHjx3w/X0K5flMTNJI/AAAAAAABQr4/4jPNyUpRBBoOlHN6fLUdZTTGm9CW6VdYwCPcBGAsYHg/s4048/IMG_20181229_164002.jpg" style="display: block; padding: 1em 0; text-align: none;"><img alt="" border="0" height="400" data-original-height="4048" data-original-width="3036" src="https://1.bp.blogspot.com/-upwNagHjx3w/X0K5flMTNJI/AAAAAAABQr4/4jPNyUpRBBoOlHN6fLUdZTTGm9CW6VdYwCPcBGAsYHg/s400/IMG_20181229_164002.jpg"/></a></div>
<p>Here are the specs at a glance:
<ul>
<li>Body
<ul>
<li>Shape: Telecaster (traditional)
<li>Wood: Alder
<li>Finish: Nitrocellulose Laquer (Butterscotch and Clear)
<li>Pickguard, solid black
</ul>
</li>
<li>Neck
<ul>
<li>Shape: Telecaster with <a href="https://www.warmoth.com/Guitar/Necks/NeckConstructions.aspx">Vintage/Modern truss rod access</a>
<li>Profile: <a href="https://www.warmoth.com/guitar/necks/backcontours.aspx">Warmoth Boatneck</a>
<li>Radius: <a href="https://www.warmoth.com/Guitar/Necks/Radius.aspx">Warmoth compound radius (10"-16")</a>
<li>Frets: <a href="https://www.warmoth.com/guitar/necks/fretsize.aspx">Stainless steel size 6150 (medium jumbo)</a>
<li>Finish: Nitrocellulose Laquer (Clear)
<li>Tuners: <a href="http://www.sperzel.com/">Sperzel locking tuners</a>
</ul>
</li>
<li>Electronics
<ul>
<li>Pickups: <a href="https://www.seymourduncan.com/single-product/p-rails-triple-shot-set-flat">P-Rails for Neck and Bridge pickups, wired to Triple Shot mounting rings</a>
<li>Oak Grigsby 4 way switch
<li>Treble bleed circuit on volume pot
<li>CTS pots
</ul>
</li>
</ul>Jeff Scudderhttp://www.blogger.com/profile/13002167096451875802noreply@blogger.com0tag:blogger.com,1999:blog-33260599.post-81884992790255778892020-08-23T11:26:00.000-07:002020-08-23T11:26:43.364-07:00CrptopalsI've had a longstanding interest in cryptography and recently dove into a set of exercises that teach basic concepts of cryptanalysis. I highly recommend it if you are looking to learn more about cryptography: <a href="https://cryptopals.com/">Cryptopals</a>. Jeff Scudderhttp://www.blogger.com/profile/13002167096451875802noreply@blogger.com0tag:blogger.com,1999:blog-33260599.post-72478684936820710552020-08-23T11:22:00.000-07:002020-08-23T11:22:20.407-07:00Early Telecasters A Visual HistoryAlong with software development, my other passion is for making music. There have been a few instruments I've specialized in over the years, but my far and away favorite at the moment is electric guitar, specifically a Fender Telecaster. For the past couple of years, I've been playing a 2015 American Standard. Here are a few pictures:
<br/>
<a imageanchor="1" style="margin: 0"
href="https://3.bp.blogspot.com/-4_R6FMOz7mQ/W3Jakam6YxI/AAAAAAAA1dQ/18DGVVEAiUoHufE0N2BtbaTLdVHJp_NPQCLcBGAs/s1600/Screen%2BShot%2B2018-08-13%2Bat%2B9.22.59%2BPM.png">
<img border="0" data-original-height="500" data-original-width="420" width="195px"
src="https://3.bp.blogspot.com/-4_R6FMOz7mQ/W3Jakam6YxI/AAAAAAAA1dQ/18DGVVEAiUoHufE0N2BtbaTLdVHJp_NPQCLcBGAs/s1600/Screen%2BShot%2B2018-08-13%2Bat%2B9.22.59%2BPM.png" />
</a>
<a imageanchor="1" style="margin: 0"
href="https://3.bp.blogspot.com/-k-db67KvYkA/W3MBdhdQjcI/AAAAAAAA1eg/4qYU-JVfN6YPUm1A07_8ubzrtfRrUJs4ACLcBGAs/s1600/Screen%2BShot%2B2018-08-14%2Bat%2B9.20.30%2BAM.png">
<img border="0" data-original-height="500" data-original-width="420" width="195px"
src="https://3.bp.blogspot.com/-k-db67KvYkA/W3MBdhdQjcI/AAAAAAAA1eg/4qYU-JVfN6YPUm1A07_8ubzrtfRrUJs4ACLcBGAs/s1600/Screen%2BShot%2B2018-08-14%2Bat%2B9.20.30%2BAM.png" />
</a>
<a imageanchor="1" style="margin: 0"
href="https://4.bp.blogspot.com/-KavmNW9x0P0/W3MHji0jUKI/AAAAAAAA1fE/GRFKa7A7waYlYArbxuX17oQ6uZ_UWuiIQCLcBGAs/s1600/Screen%2BShot%2B2018-08-14%2Bat%2B9.46.07%2BAM.png">
<img border="0" data-original-height="500" data-original-width="420" width="195px"
src="https://4.bp.blogspot.com/-KavmNW9x0P0/W3MHji0jUKI/AAAAAAAA1fE/GRFKa7A7waYlYArbxuX17oQ6uZ_UWuiIQCLcBGAs/s1600/Screen%2BShot%2B2018-08-14%2Bat%2B9.46.07%2BAM.png" />
</a>
<br/>
<a imageanchor="1" style="margin: 0"
href="https://4.bp.blogspot.com/-M2PWMD4dfvI/W3MEcQGdkxI/AAAAAAAA1es/1qDhlW-vatkghNZOVmFCgap5DLlUgoEfgCLcBGAs/s1600/Screen%2BShot%2B2018-08-14%2Bat%2B9.33.12%2BAM.png">
<img border="0" data-original-height="500" data-original-width="420" width="195px"
src="https://4.bp.blogspot.com/-M2PWMD4dfvI/W3MEcQGdkxI/AAAAAAAA1es/1qDhlW-vatkghNZOVmFCgap5DLlUgoEfgCLcBGAs/s1600/Screen%2BShot%2B2018-08-14%2Bat%2B9.33.12%2BAM.png" />
</a>
<a imageanchor="1" style="margin: 0"
href="https://4.bp.blogspot.com/-oyMSeUlLZlw/W3MGpvhau7I/AAAAAAAA1e4/Nsp3NzCsTfwNjp7BvvrRWB2_-ssk8cEywCLcBGAs/s1600/Screen%2BShot%2B2018-08-14%2Bat%2B9.42.33%2BAM.png">
<img border="0" data-original-height="500" data-original-width="420" width="195px"
src="https://4.bp.blogspot.com/-oyMSeUlLZlw/W3MGpvhau7I/AAAAAAAA1e4/Nsp3NzCsTfwNjp7BvvrRWB2_-ssk8cEywCLcBGAs/s1600/Screen%2BShot%2B2018-08-14%2Bat%2B9.42.33%2BAM.png" />
</a>
<a imageanchor="1" style="margin: 0"
href="https://2.bp.blogspot.com/-DQbxMEerm0Q/W3MIaILncYI/AAAAAAAA1fQ/BALDlvVBN-wi6gT2AEYZcLPTo9Dbjm5GwCLcBGAs/s1600/Screen%2BShot%2B2018-08-14%2Bat%2B9.49.59%2BAM.png">
<img border="0" data-original-height="500" data-original-width="420" width="195px"
src="https://2.bp.blogspot.com/-DQbxMEerm0Q/W3MIaILncYI/AAAAAAAA1fQ/BALDlvVBN-wi6gT2AEYZcLPTo9Dbjm5GwCLcBGAs/s1600/Screen%2BShot%2B2018-08-14%2Bat%2B9.49.59%2BAM.png" />
</a>
<br/>
<a imageanchor="1" style="margin: 0"
href="https://1.bp.blogspot.com/-F_3u1X_Qqw4/W3Jae1AtfqI/AAAAAAAA1dI/Frlb0L4EOJIPph_ccbVfViZU1pr_7THdQCLcBGAs/s1600/Screen%2BShot%2B2018-08-13%2Bat%2B9.28.02%2BPM.png">
<img border="0" data-original-height="500" data-original-width="420" width="195px"
src="https://1.bp.blogspot.com/-F_3u1X_Qqw4/W3Jae1AtfqI/AAAAAAAA1dI/Frlb0L4EOJIPph_ccbVfViZU1pr_7THdQCLcBGAs/s1600/Screen%2BShot%2B2018-08-13%2Bat%2B9.28.02%2BPM.png" />
</a>
<a imageanchor="1" style="margin: 0"
href="https://1.bp.blogspot.com/-zzwgb0UX4t4/W3JaoU9J1NI/AAAAAAAA1dU/CAVqhjbMWDkqmP2NCj7TbNZLwJoj613AgCLcBGAs/s1600/Screen%2BShot%2B2018-08-13%2Bat%2B9.22.10%2BPM.png">
<img border="0" data-original-height="500" data-original-width="420" width="195px"
src="https://1.bp.blogspot.com/-zzwgb0UX4t4/W3JaoU9J1NI/AAAAAAAA1dU/CAVqhjbMWDkqmP2NCj7TbNZLwJoj613AgCLcBGAs/s1600/Screen%2BShot%2B2018-08-13%2Bat%2B9.22.10%2BPM.png" />
</a>
<a imageanchor="1" style="margin: 0"
href="https://2.bp.blogspot.com/-rwlSvzLzv_Q/W3JahdZSjpI/AAAAAAAA1dM/tPaxtzRiEz4I9mJ_bTolNqsiiTY6g3E_ACLcBGAs/s1600/Screen%2BShot%2B2018-08-13%2Bat%2B9.25.14%2BPM.png">
<img border="0" data-original-height="500" data-original-width="420" width="195px"
src="https://2.bp.blogspot.com/-rwlSvzLzv_Q/W3JahdZSjpI/AAAAAAAA1dM/tPaxtzRiEz4I9mJ_bTolNqsiiTY6g3E_ACLcBGAs/s1600/Screen%2BShot%2B2018-08-13%2Bat%2B9.25.14%2BPM.png" />
</a>
<br/>
<p>One of the things that amazes me about this instrument is the classic design which has undergone very few changes since this instrument was first introduced in 1950. As one of the very first mass produced electric guitars, the Telecaster continues to influence modern music as well as the design of electric guitars. Most electric guitar makers sell a "T" style guitar in their lineup.
<p>Lets look back at a brief visual history of the first decade of the Telecaster family of guitars.
<h4>1950</h4>
<p>Beginning in 1950, the Fender Electric Instrument Manufacturing Company began selling a couple of styles of electric guitar. First, the single pickup Esquire, followed shortly by the two pickup Broadcaster.
<h5>Esquire</h5>
<p>One of the surprising details to me about this guitar, is the presence of a three-way selector switch. In most electric guitars, the selector switch activates different combinations of the pickups in the guitar. Most single pickup guitars omit a selector switch (see for example, <a href="https://en.wikipedia.org/wiki/Gibson_Les_Paul_Junior">the Gibson Les Paul Junior</a>). So what is a selector switch doing on a single pickup guitar?
<p>In the wiring for an Esquire, the middle position matches what most would consider a normal setup for a single pickup guitar with two knobs. In this position, the volume and tone knobs control the output from the pickups. When the switch is up towards the neck of the guitar, an additional capacitor is in the output chain in place of the tone knob. This cuts out many of the high frequencies in the output and produces a somewhat muddy sound more reminiscent of a bass guitar. <a href="https://www.youtube.com/watch?v=lD2DbtBY5xU&t=47">This video has a great demonstration of the Esquire tones</a>. A demonstration of the tones begins around <a href="https://youtu.be/lD2DbtBY5xU?t=207">3:27 in the video</a>. This circuit position in particular is not typically found on a modern electric guitar, pretty unique! The final position, down towards the bridge is a circuit that bypasses the tone control entirely and is the least filtered of the circuit options. Only the volume control is changing the output, so you get the widest possible set of frequencies. There are a few guitars out there today that dispense with a tone control. One example is the Jim Root Telecaster, however it is a very different beast than the 1950 Fender Esquire.
<p>And now for the look:
<br/>
<a imageanchor="1" style="margin: 0"
href="https://3.bp.blogspot.com/-9xo_5bjUK5I/W3eiRfYgn0I/AAAAAAAA1mo/36YhrQbru1AYFXo_aT1pikJPgYph_gr4ACLcBGAs/s1600/Screen%2BShot%2B2018-08-17%2Bat%2B9.33.44%2BPM.png">
<img border="0" data-original-height="500" data-original-width="420" width="195px"
src="https://3.bp.blogspot.com/-9xo_5bjUK5I/W3eiRfYgn0I/AAAAAAAA1mo/36YhrQbru1AYFXo_aT1pikJPgYph_gr4ACLcBGAs/s1600/Screen%2BShot%2B2018-08-17%2Bat%2B9.33.44%2BPM.png" />
</a>
<a imageanchor="1" style="margin: 0"
href="https://2.bp.blogspot.com/-uHyMuoXj0sc/W3eiP-VReDI/AAAAAAAA1mk/s6hKyLP8Whw9EJnLK-wmzFu0YOWIpyj4wCLcBGAs/s1600/Screen%2BShot%2B2018-08-17%2Bat%2B9.35.28%2BPM.png">
<img border="0" data-original-height="500" data-original-width="420" width="195px"
src="https://2.bp.blogspot.com/-uHyMuoXj0sc/W3eiP-VReDI/AAAAAAAA1mk/s6hKyLP8Whw9EJnLK-wmzFu0YOWIpyj4wCLcBGAs/s1600/Screen%2BShot%2B2018-08-17%2Bat%2B9.35.28%2BPM.png" />
</a>
<a imageanchor="1" style="margin: 0"
href="https://4.bp.blogspot.com/-QV5m2EE9RWs/W3ekgdfc_4I/AAAAAAAA1m8/7MzJNi0tlBkSCKjnaMS33ENW6Zhe1cWTwCLcBGAs/s1600/Screen%2BShot%2B2018-08-17%2Bat%2B9.44.57%2BPM.png">
<img border="0" data-original-height="500" data-original-width="420" width="195px"
src="https://4.bp.blogspot.com/-QV5m2EE9RWs/W3ekgdfc_4I/AAAAAAAA1m8/7MzJNi0tlBkSCKjnaMS33ENW6Zhe1cWTwCLcBGAs/s1600/Screen%2BShot%2B2018-08-17%2Bat%2B9.44.57%2BPM.png" />
</a>
<p>While the single pickup guitar was the first to be widely available, from the beginning, Fender had planned to produce a two pickup guitar. In fact, these early Esquire guitars reportedly had a cutout for the neck pickup ready to go but hidden away under the pickguard. And that brings us to the next guitar available in 1950: the Broadcaster.
<h5>Broadcaster</h5>
With it's two pickups mounted on a solid ash body, this is very recognizably the first example of what is today the Telecaster. Originally named the Broadcaster, it would soon have to be renamed due to a trademark dispute. Few guitars carry the Broadcaster name.
<br/>
<a imageanchor="1" style="margin: 0"
href="https://4.bp.blogspot.com/-p56mq7M1GpQ/W3el-NYE5uI/AAAAAAAA1nQ/yc4giYF5kHs4u8v__z_I40LmoEYz9bw5QCLcBGAs/s1600/Screen%2BShot%2B2018-08-17%2Bat%2B9.51.38%2BPM.png">
<img border="0" data-original-height="500" data-original-width="420" width="195px"
src="https://4.bp.blogspot.com/-p56mq7M1GpQ/W3el-NYE5uI/AAAAAAAA1nQ/yc4giYF5kHs4u8v__z_I40LmoEYz9bw5QCLcBGAs/s1600/Screen%2BShot%2B2018-08-17%2Bat%2B9.51.38%2BPM.png" />
</a>
<a imageanchor="1" style="margin: 0"
href="https://2.bp.blogspot.com/-r8TLhDfC8uc/W3emS-R3-SI/AAAAAAAA1nY/c-Y2POz_yik-xEiCY1l2dEGvjcizDQ2fQCLcBGAs/s1600/Screen%2BShot%2B2018-08-17%2Bat%2B9.52.45%2BPM.png">
<img border="0" data-original-height="500" data-original-width="420" width="195px"
src="https://2.bp.blogspot.com/-r8TLhDfC8uc/W3emS-R3-SI/AAAAAAAA1nY/c-Y2POz_yik-xEiCY1l2dEGvjcizDQ2fQCLcBGAs/s1600/Screen%2BShot%2B2018-08-17%2Bat%2B9.52.45%2BPM.png" />
</a>
<a imageanchor="1" style="margin: 0"
href="https://4.bp.blogspot.com/-fC2vGRne-0Q/W3enR4CET2I/AAAAAAAA1ns/aMLwNECBYZE1nox_-cI_NymzwB-RTojgQCLcBGAs/s1600/Screen%2BShot%2B2018-08-17%2Bat%2B9.56.53%2BPM.png">
<img border="0" data-original-height="500" data-original-width="420" width="195px"
src="https://4.bp.blogspot.com/-fC2vGRne-0Q/W3enR4CET2I/AAAAAAAA1ns/aMLwNECBYZE1nox_-cI_NymzwB-RTojgQCLcBGAs/s1600/Screen%2BShot%2B2018-08-17%2Bat%2B9.56.53%2BPM.png" />
</a>
<br/>
<a imageanchor="1" style="margin: 0"
href="https://1.bp.blogspot.com/-lfQHX1BaucM/W3emsQj0T1I/AAAAAAAA1ng/LvkYNj3h-58Ugf5jojIWTn7lNYp1W8dJQCLcBGAs/s1600/Screen%2BShot%2B2018-08-17%2Bat%2B9.54.30%2BPM.png">
<img border="0" data-original-height="500" data-original-width="420" width="195px"
src="https://1.bp.blogspot.com/-lfQHX1BaucM/W3emsQj0T1I/AAAAAAAA1ng/LvkYNj3h-58Ugf5jojIWTn7lNYp1W8dJQCLcBGAs/s1600/Screen%2BShot%2B2018-08-17%2Bat%2B9.54.30%2BPM.png" />
</a>
<a imageanchor="1" style="margin: 0"
href="https://1.bp.blogspot.com/-asivqkgW9Ww/W3eoQsqTraI/AAAAAAAA1n4/86Rq7DBisSkIZDs-rbiGZ-p0GpnlpYEXgCLcBGAs/s1600/Screen%2BShot%2B2018-08-17%2Bat%2B10.01.07%2BPM.png">
<img border="0" data-original-height="500" data-original-width="420" width="195px"
src="https://1.bp.blogspot.com/-asivqkgW9Ww/W3eoQsqTraI/AAAAAAAA1n4/86Rq7DBisSkIZDs-rbiGZ-p0GpnlpYEXgCLcBGAs/s1600/Screen%2BShot%2B2018-08-17%2Bat%2B10.01.07%2BPM.png" />
</a>
<a imageanchor="1" style="margin: 0"
href="https://3.bp.blogspot.com/-S5DhUTxU3nI/W3eouDogIwI/AAAAAAAA1oA/z7puSvpF29EqUVTTRW_Jwltzap9iqT-vACLcBGAs/s1600/Screen%2BShot%2B2018-08-17%2Bat%2B10.02.47%2BPM.png">
<img border="0" data-original-height="500" data-original-width="420" width="195px"
src="https://3.bp.blogspot.com/-S5DhUTxU3nI/W3eouDogIwI/AAAAAAAA1oA/z7puSvpF29EqUVTTRW_Jwltzap9iqT-vACLcBGAs/s1600/Screen%2BShot%2B2018-08-17%2Bat%2B10.02.47%2BPM.png" />
</a>
<br/>
<p>While the Broadcaster has the recognizable two pickup configuration, two knobs, and a three way selector, the wiring is very different from what would later become what is now considered normal Telecaster wiring. In these early models, the three selector switch toggled between the following settings. (Note, more details on this <a href="https://www.premierguitar.com/articles/The_Two_Pickup_Esquire_Wiring">original Broadcaster wiring can be found here</a>.) Here's what the different positions in a Broadcaster switch do:
<p>The position with the switch down towards the bridge includes the output of the bridge pickup, with no tone adjustment similar to this setting in the Esquire. However, rather than ignore the tone know, in this position, the "tone" knob is a "blend" control which adds in the output from the neck pickup. Turned one way, the neck pickup is all the way in, the other way it's all the way out. Next, the middle position includes the full output of only the neck pickup (no tone modification). The final position, up towards the neck, includes only the neck pickup with a capacitor that filters out the high frequencies. I found it fascinating that in the original Broadcaster wiring, there's no variable tone control, just pickup selection with one option being a fixed tone cut. The closest-to-bridge switch position is most similar to the middle position in modern Telecasters. Although, in a modern telecaster, there's a constant balance of output between the picksups when both are active.
<p>A good example of the tones that come from this wiring can be found in <a href="https://www.youtube.com/watch?v=r_UI0pjL1SI">this video</a>. Although this isn't an original Broadcaster, it demonstrates the different behaviors of this pickup switch. <a href="https://www.youtube.com/watch?v=Ya5LrfNTz5I&t=20">Here's another example</a>. For a video showcasing an actual 1950 Broadcaster, <a href="https://www.youtube.com/watch?v=SE_3ra_jSAs&t=6">check out this video from Norman's Rare Guitars</a>.
<h4>1951</h4>
Over the course of 1951, the Broadcaster would be renamed to the Telecaster. Aside from the name change, the guitars' design was essentially unchanged.
<h5>Broadcaster</h5>
<p>In early 1951, Fender continued making Broadcaster guitars. However, the Gretsch company notified Fender that the Broadcaster name on their guitar conflicted with their trademarked <a href="http://gretschdrums.com/drums/broadkaster">Gretsch Broadkaster drum set</a>. It doesn't sound like the two companies went to court over the name. I wonder how it would have gone had Fender decided not to change the name. Gretsch also produced electric guitars at the time, and continues to make and sell them today. In 1951, none of the <a href="https://www.gretschguitars.com/">Gretsch guitars</a> were named Broadcaster, though they do today sell a <a href="https://www.gretschguitars.com/gear/build/center-block/g6609tfm-players-edition-broadkaster-center-block-double-cut-with-string-thru-bigsby-and-flame-maple/2400700878">Broadkaster Guitar</a>.
<h5>Nocaster</h5>
<p>Following the notice from Gretsch guitars, Fender began producing their formerly-known-as-Broadcaster guitars with no model name on the decal. The headstock of the guitar was labelled only with the name Fender, hence guitars produced in their period are dubbed "Nocaster" guitars. Aside from the name change on the headstock, the Nocaster is visually similar to the Broadcaster that came before it. The body is painted a translucent Butterscotch Blond with a single-ply black pickguard:
<br/>
<a imageanchor="1" style="margin: 0"
href="https://1.bp.blogspot.com/-4B8oD7UeHYs/W3mAPbPQEFI/AAAAAAAA1uE/n_ucX0zs3tYOxOlm9euBbddSNIxmR9R1wCLcBGAs/s1600/Screen%2BShot%2B2018-08-19%2Bat%2B7.34.53%2BAM.png">
<img border="0" data-original-height="500" data-original-width="420" width="195px"
src="https://1.bp.blogspot.com/-4B8oD7UeHYs/W3mAPbPQEFI/AAAAAAAA1uE/n_ucX0zs3tYOxOlm9euBbddSNIxmR9R1wCLcBGAs/s1600/Screen%2BShot%2B2018-08-19%2Bat%2B7.34.53%2BAM.png" />
</a>
<a imageanchor="1" style="margin: 0"
href="https://2.bp.blogspot.com/-1F6AKlmdgs0/W3mG8x37GII/AAAAAAAA1uk/ttcfBhu4WIErXgzU92dW7EiwK2ske6chgCLcBGAs/s1600/Screen%2BShot%2B2018-08-19%2Bat%2B8.03.25%2BAM.png">
<img border="0" data-original-height="500" data-original-width="420" width="195px"
src="https://2.bp.blogspot.com/-1F6AKlmdgs0/W3mG8x37GII/AAAAAAAA1uk/ttcfBhu4WIErXgzU92dW7EiwK2ske6chgCLcBGAs/s1600/Screen%2BShot%2B2018-08-19%2Bat%2B8.03.25%2BAM.png" />
</a>
<a imageanchor="1" style="margin: 0"
href="https://2.bp.blogspot.com/-ap_sUoCv5Z0/W3mDCEHDEjI/AAAAAAAA1uQ/gVnUby8Ljdot_A_O-drVbpKYvP_kgBjYwCLcBGAs/s1600/Screen%2BShot%2B2018-08-19%2Bat%2B7.46.54%2BAM.png">
<img border="0" data-original-height="500" data-original-width="420" width="195px"
src="https://2.bp.blogspot.com/-ap_sUoCv5Z0/W3mDCEHDEjI/AAAAAAAA1uQ/gVnUby8Ljdot_A_O-drVbpKYvP_kgBjYwCLcBGAs/s1600/Screen%2BShot%2B2018-08-19%2Bat%2B7.46.54%2BAM.png" />
</a>
<br/>
<a imageanchor="1" style="margin: 0"
href="https://3.bp.blogspot.com/-f9SkO7-_how/W3mKCRgmA2I/AAAAAAAA1u8/aMAKsoJWHkkVSMTwtYoxEKJI7TkjDZXXQCLcBGAs/s1600/Screen%2BShot%2B2018-08-19%2Bat%2B8.16.12%2BAM.png">
<img border="0" data-original-height="500" data-original-width="420" width="195px"
src="https://3.bp.blogspot.com/-f9SkO7-_how/W3mKCRgmA2I/AAAAAAAA1u8/aMAKsoJWHkkVSMTwtYoxEKJI7TkjDZXXQCLcBGAs/s1600/Screen%2BShot%2B2018-08-19%2Bat%2B8.16.12%2BAM.png" />
</a>
<a imageanchor="1" style="margin: 0"
href="https://1.bp.blogspot.com/-f2lWmvD9dww/W3mISO4jD0I/AAAAAAAA1uw/Q_QAH-duUFgyNSHXbn5vrVpd0OFaD16WQCLcBGAs/s1600/Screen%2BShot%2B2018-08-19%2Bat%2B8.09.13%2BAM.png">
<img border="0" data-original-height="500" data-original-width="420" width="195px"
src="https://1.bp.blogspot.com/-f2lWmvD9dww/W3mISO4jD0I/AAAAAAAA1uw/Q_QAH-duUFgyNSHXbn5vrVpd0OFaD16WQCLcBGAs/s1600/Screen%2BShot%2B2018-08-19%2Bat%2B8.09.13%2BAM.png" />
</a>
<a imageanchor="1" style="margin: 0"
href="https://2.bp.blogspot.com/-NbWT8p7c1Yc/W3mGTVLQ-BI/AAAAAAAA1uc/GyDZjwyLezojr3Nx44MTMjJnbrzhMjTSgCLcBGAs/s1600/Screen%2BShot%2B2018-08-19%2Bat%2B8.00.41%2BAM.png">
<img border="0" data-original-height="500" data-original-width="420" width="195px"
src="https://2.bp.blogspot.com/-NbWT8p7c1Yc/W3mGTVLQ-BI/AAAAAAAA1uc/GyDZjwyLezojr3Nx44MTMjJnbrzhMjTSgCLcBGAs/s1600/Screen%2BShot%2B2018-08-19%2Bat%2B8.00.41%2BAM.png" />
</a>
<br/>
<p>These Nocaster guitars are quite rare as they were produced for only a partial year. By year's end, these guitars bore their new and final name.
<h5>Telecaster</h5>
<p>In late 1951, the guitar received the name that it is known by today: the Telecaster. Other than the new name on the headstock, these guitars were identical to those produced earlier in the year.
<br/>
<a imageanchor="1" style="margin: 0"
href="https://4.bp.blogspot.com/-aFVKKsh1uaU/W4om2zzZCRI/AAAAAAAA2Ko/W8BeDpTNEWg3erAo6u4gQuWHqaoWjfJcACLcBGAs/s1600/Screen%2BShot%2B2018-08-31%2Bat%2B10.42.02%2BPM.png">
<img border="0" data-original-height="500" data-original-width="420" width="195px"
src="https://4.bp.blogspot.com/-aFVKKsh1uaU/W4om2zzZCRI/AAAAAAAA2Ko/W8BeDpTNEWg3erAo6u4gQuWHqaoWjfJcACLcBGAs/s1600/Screen%2BShot%2B2018-08-31%2Bat%2B10.42.02%2BPM.png" />
</a>
<a imageanchor="1" style="margin: 0"
href="https://2.bp.blogspot.com/-F0pErFcxnNI/W4omPCiUTXI/AAAAAAAA2Kc/T7adBxKnZBMtvQL8gtBQkfWfDouAYyc7ACLcBGAs/s1600/Screen%2BShot%2B2018-08-31%2Bat%2B10.38.58%2BPM.png">
<img border="0" data-original-height="500" data-original-width="420" width="195px"
src="https://2.bp.blogspot.com/-F0pErFcxnNI/W4omPCiUTXI/AAAAAAAA2Kc/T7adBxKnZBMtvQL8gtBQkfWfDouAYyc7ACLcBGAs/s1600/Screen%2BShot%2B2018-08-31%2Bat%2B10.38.58%2BPM.png" />
</a>
<a imageanchor="1" style="margin: 0"
href="https://3.bp.blogspot.com/-rCComPZ6lJw/W4omPDvVoKI/AAAAAAAA2KY/FPBDKGfF7To9q64aMXgQ8UrXOndTRYbkACLcBGAs/s1600/Screen%2BShot%2B2018-08-31%2Bat%2B10.38.03%2BPM.png">
<img border="0" data-original-height="500" data-original-width="420" width="195px"
src="https://3.bp.blogspot.com/-rCComPZ6lJw/W4omPDvVoKI/AAAAAAAA2KY/FPBDKGfF7To9q64aMXgQ8UrXOndTRYbkACLcBGAs/s1600/Screen%2BShot%2B2018-08-31%2Bat%2B10.38.03%2BPM.png" />
</a>
<br/>
<a imageanchor="1" style="margin: 0"
href="https://4.bp.blogspot.com/-bqqeUYHGlCM/W4on0wUkR7I/AAAAAAAA2LE/vPnTI_CXZq4ucXt0el_Q-wJLJPYCXGCtgCLcBGAs/s1600/Screen%2BShot%2B2018-08-31%2Bat%2B10.46.29%2BPM.png">
<img border="0" data-original-height="500" data-original-width="420" width="195px"
src="https://4.bp.blogspot.com/-bqqeUYHGlCM/W4on0wUkR7I/AAAAAAAA2LE/vPnTI_CXZq4ucXt0el_Q-wJLJPYCXGCtgCLcBGAs/s1600/Screen%2BShot%2B2018-08-31%2Bat%2B10.46.29%2BPM.png" />
</a>
<a imageanchor="1" style="margin: 0"
href="https://4.bp.blogspot.com/--luwY9CBF3o/W4onUI7qGZI/AAAAAAAA2K0/LWI_pF44CzEej3AlBIAPymK9ztQq_M8QQCLcBGAs/s1600/Screen%2BShot%2B2018-08-31%2Bat%2B10.44.13%2BPM.png">
<img border="0" data-original-height="500" data-original-width="420" width="195px"
src="https://4.bp.blogspot.com/--luwY9CBF3o/W4onUI7qGZI/AAAAAAAA2K0/LWI_pF44CzEej3AlBIAPymK9ztQq_M8QQCLcBGAs/s1600/Screen%2BShot%2B2018-08-31%2Bat%2B10.44.13%2BPM.png" />
</a>
<a imageanchor="1" style="margin: 0"
href="https://4.bp.blogspot.com/-DYNulVenYto/W4onUDxarKI/AAAAAAAA2Kw/Ho71NVntz7g_bpfuABQn6-rxhnFFU5-NgCLcBGAs/s1600/Screen%2BShot%2B2018-08-31%2Bat%2B10.43.27%2BPM.png">
<img border="0" data-original-height="500" data-original-width="420" width="195px"
src="https://4.bp.blogspot.com/-DYNulVenYto/W4onUDxarKI/AAAAAAAA2Kw/Ho71NVntz7g_bpfuABQn6-rxhnFFU5-NgCLcBGAs/s1600/Screen%2BShot%2B2018-08-31%2Bat%2B10.43.27%2BPM.png" />
</a>
<br/>
<p>While these guitars now bear their modern name, the wiring of the pickups is significantly different than what they carry today. Modern style pickup wiring was introduced in the late 1952.
<h5>Esquire</h5>
<p>Fender continued to produce Esquires as well in 1951. In addition to the "Butterscotch Blond" color, the Esquire was also available in a "Blond" color which was a translucent white. The finish on these guitars tend to yellow significantly as they age, so most old guitars have a noticable yellow tint to them. Here are a few pictures:
<br/>
<a imageanchor="1" style="margin: 0"
href="https://4.bp.blogspot.com/-VET0VSbv6fs/W3g6lqAPbXI/AAAAAAAA1og/d5vc7qb_gBoFp26_12SgJRovxRq9JDbNACLcBGAs/s1600/Screen%2BShot%2B2018-08-18%2Bat%2B8.23.48%2BAM.png">
<img border="0" data-original-height="500" data-original-width="420" width="195px"
src="https://4.bp.blogspot.com/-VET0VSbv6fs/W3g6lqAPbXI/AAAAAAAA1og/d5vc7qb_gBoFp26_12SgJRovxRq9JDbNACLcBGAs/s1600/Screen%2BShot%2B2018-08-18%2Bat%2B8.23.48%2BAM.png" />
</a>
<a imageanchor="1" style="margin: 0"
href="https://3.bp.blogspot.com/-jJz_gkoYIng/W3g7ayWTlOI/AAAAAAAA1ow/3zeccTnPrZkytHH6zaZp71zCTM558NjrQCLcBGAs/s1600/Screen%2BShot%2B2018-08-18%2Bat%2B8.28.57%2BAM.png">
<img border="0" data-original-height="500" data-original-width="420" width="195px"
src="https://3.bp.blogspot.com/-jJz_gkoYIng/W3g7ayWTlOI/AAAAAAAA1ow/3zeccTnPrZkytHH6zaZp71zCTM558NjrQCLcBGAs/s1600/Screen%2BShot%2B2018-08-18%2Bat%2B8.28.57%2BAM.png" />
</a>
<a imageanchor="1" style="margin: 0"
href="https://3.bp.blogspot.com/-rabpWDYWhrE/W3g5DFkV-gI/AAAAAAAA1oQ/q6XVvkwbyFEPH-op9g-F57RTTzmWLCs7gCLcBGAs/s1600/Screen%2BShot%2B2018-08-18%2Bat%2B8.18.31%2BAM.png">
<img border="0" data-original-height="500" data-original-width="420" width="195px"
src="https://3.bp.blogspot.com/-rabpWDYWhrE/W3g5DFkV-gI/AAAAAAAA1oQ/q6XVvkwbyFEPH-op9g-F57RTTzmWLCs7gCLcBGAs/s1600/Screen%2BShot%2B2018-08-18%2Bat%2B8.18.31%2BAM.png" />
</a>
<br/>
<a imageanchor="1" style="margin: 0"
href="https://2.bp.blogspot.com/-kslvUTo-NfQ/W3g8saOUs3I/AAAAAAAA1o8/yORGzFFHu6srYZEDXEzLwaoxRBZaT9HlwCLcBGAs/s1600/Screen%2BShot%2B2018-08-18%2Bat%2B8.34.32%2BAM.png">
<img border="0" data-original-height="500" data-original-width="420" width="195px"
src="https://2.bp.blogspot.com/-kslvUTo-NfQ/W3g8saOUs3I/AAAAAAAA1o8/yORGzFFHu6srYZEDXEzLwaoxRBZaT9HlwCLcBGAs/s1600/Screen%2BShot%2B2018-08-18%2Bat%2B8.34.32%2BAM.png" />
</a>
<a imageanchor="1" style="margin: 0"
href="https://3.bp.blogspot.com/-mB8pbGWDjwA/W3g6jLopAuI/AAAAAAAA1oc/8jZOpp7CcnYwG8QGNOycFHAPFuPzBRzrQCLcBGAs/s1600/Screen%2BShot%2B2018-08-18%2Bat%2B8.25.24%2BAM.png">
<img border="0" data-original-height="500" data-original-width="420" width="195px"
src="https://3.bp.blogspot.com/-mB8pbGWDjwA/W3g6jLopAuI/AAAAAAAA1oc/8jZOpp7CcnYwG8QGNOycFHAPFuPzBRzrQCLcBGAs/s1600/Screen%2BShot%2B2018-08-18%2Bat%2B8.25.24%2BAM.png" />
</a>
<a imageanchor="1" style="margin: 0"
href="https://1.bp.blogspot.com/-Dd4JxHDkI2c/W3g-OSFFd1I/AAAAAAAA1pI/k7G2TV5n7PET7lpCP342U0h06b1T0GdqQCLcBGAs/s1600/Screen%2BShot%2B2018-08-18%2Bat%2B8.40.59%2BAM.png">
<img border="0" data-original-height="500" data-original-width="420" width="195px"
src="https://1.bp.blogspot.com/-Dd4JxHDkI2c/W3g-OSFFd1I/AAAAAAAA1pI/k7G2TV5n7PET7lpCP342U0h06b1T0GdqQCLcBGAs/s1600/Screen%2BShot%2B2018-08-18%2Bat%2B8.40.59%2BAM.png" />
</a>
<br/>
Few other instruments have been in continuous manufacture as the humble Telecaster and it still plays a major role in modern music. Here's to the next 70 years.Jeff Scudderhttp://www.blogger.com/profile/13002167096451875802noreply@blogger.com1tag:blogger.com,1999:blog-33260599.post-30074563161554002232018-06-22T18:03:00.000-07:002018-06-22T18:03:02.720-07:00Developing in GitHub using Cloud Shell<p>If you're not familiar with <a href="https://cloud.google.com/shell/">Google Cloud Shell</a>, it's a great tool for doing command line development in a Linux environment. I've been using it as an always-on development environment for web focused projects. Whichever machine I happen to be using, my dev environment is always available.
<p>One of the ways I'm using Cloud Shell is as a development environment for my open source projects. Cloud Shell comes with loads of developer tools pre-installed, including git which is quite handy if you are hosting projects on Github. Head over to <a href="https://console.cloud.google.com/cloudshell/editor">https://console.cloud.google.com/cloudshell/editor</a> to start using Cloud Shell.
<p>Here's how you can set up your own open source development environment with Github in Cloud Shell, in three easy steps!
<h4>Set up your git environment</h4>
<p>First, you'll need to have the git client available. Easy, git is already installed (yay!)
<p>Next, <a href="From: https://help.github.com/articles/set-up-git/">set up your git environment</a> with the email address and name that your changes will be published under:
<pre><code>git config --global user.name "YOUR NAME"
git config --global user.email "YOUR EMAIL ADDRESS"</code></pre>
<p>If you are using two factor auth for your GitHub account, you'll need to <a href="https://help.github.com/articles/creating-an-access-token-for-command-line-use/">generate an access token</a>. Once created, you'll use the hexidecimal string instead of your GitHub account password. For example, the generate password might look something like
<pre><code>4e6f742061207265616c206b6579203b2d29</code></pre>
<h4>Clone a repo from GitHub to Cloud Shell</h4>
<p>With command line credentials in hand, you can now clone the repository from GitHub into your Cloud Shell environment to start making changes. Step three!
<p>For example:
<pre><code>git clone https://github.com/jscud/jsBytes.git</code></pre>
<p>Now the files are available in your local Cloud Shell environment and you can change them to your heart's content. There is a simple text editor available in Cloud Shell which you can launch from the command line with a command like
<pre><code>cd jsBytes
edit README</code></pre>
<h4>Commit and publish your changes</h4>
<p>After editing a file or two, commit your changes to your local repository and then publish them on GitHub. Remember that when prompted for the password, use the access token you generated earlier instead of your GitHub password.
<pre><code>git status
git commit -a -m 'Add one usage example to README.'
git push origin master</pre></code>
<p>There you have it, an easy way to work on your GitHub project using Google Cloud Shell as your development environment.Jeff Scudderhttp://www.blogger.com/profile/13002167096451875802noreply@blogger.com0tag:blogger.com,1999:blog-33260599.post-90808198801035920852017-02-24T20:45:00.002-08:002017-04-17T09:14:12.108-07:00Arduino Programming in ChromeOSAre you ready to turn your Chromebook into a lean mean Arduino programming machine? No? Maybe? Great! <br />
<br />
I've recently gotten into microcontroller programming, chasing dreams of electric guitar fueled audio bliss. Several microcontrollers have played the role of distortion effects prototype, and I haven't settled on one yet, but I can say the easiest I've found to use so far are the ones produced by Arduino. In fact, you can set up a Chromebook as development environment for programming an Arduino.<br />
<br />
Here are the steps you'll need complete this amazing Chromebook transformation. Note that there are some risks in tweaking the setup of your machine.<br />
<br />
First you'll need to enter developer mode, hold down escape and refresh while pressing the power button. Then on the warning boot screen, press ctrl+d.<br />
<br />
Then, install <a href="https://github.com/dnschneid/crouton">Crouton</a>. Here's a helpful download link: <a href="https://goo.gl/fd3zc">https://goo.gl/fd3zc</a><br />
<br />
Then run Crouton setup by entering the terminal, which is done by hitting ctrl+alt+t then run shell (type shell followed by enter). I ran my setup like this: <code>sudo sh ~/Downloads/crouton -r trusty -t xfce</code>.<br />
<br />
To run once installed, use <code>sudo startxfce4</code><br />
<br />
From time to time, as Chrome OS is updated, it may be necessary to update the Crouton installation. I've updated by running <code>sudo sh ~/Downloads/crouton -r trusty -t xfce -u</code><br />
<br />
Now its time to get the development environment for Arduino. There are some helpful instructions here: <a href="http://playground.arduino.cc/Linux/Ubuntu">http://playground.arduino.cc/Linux/Ubuntu</a><br />
<br />
I've set up a couple of Chromebooks with the Arduino dev environment and as time has gone on, the approach has changed a bit. In my first setup, I did the following to install it:<br />
<code>sudo apt-get update && sudo apt-get install arduino arduino-core </code>
<br />
I then tried running arduino as root (<code>sudo ./arduino</code>
), but had the following error:<br />
<br />
<code>error while loading shared libraries: libtinfo.so.5: cannot open shared object file: No such file or directory</code><br />
<br />
Ah, there was a missing dependency, which I was able to install as follows:<br />
<br />
<code>sudo apt-get install libncurses5-dev</code><br />
<br />
In a later version of Arduino's software, I got the following after downloading the Arduino IDE and running <code>sudo ./install</code>
then <code>sudo ./arduino</code>:<br />
<br />
<code>Exception in thread "main" java.lang.UnsatisfiedLinkError: /home/.../arduino-1.6.13/java/lib/i386/libsplashscreen.so: libX11.so.6: cannot open shared object file: No such file or directory</code><br />
<br />
I resolved a sequence of errors by installing the following<br />
<code>sudo apt-get install libX11-6:i386</code><br />
<code>sudo apt install libxext6:i386</code><br />
<code>sudo apt-get install libxrender1:i386</code><br />
<code>sudo apt-get install libXtst6:i386</code><br />
<code>sudo apt-get install libXi6:i386</code><br />
<code>sudo apt-get install libstdc++6:i386</code><br />
<br />
I also edited the audino file, which is an executable script, and removed the reference to GTKLookAndFeel. This allowed me to run the Arduino IDE without having to replace my installation of Java.<br />
<br />
From there I've been able to compile programs and upload them to the Arduino to my hearts content. Happy coding!
Jeff Scudderhttp://www.blogger.com/profile/13002167096451875802noreply@blogger.com5tag:blogger.com,1999:blog-33260599.post-14653439637071486792015-07-22T23:11:00.003-07:002015-07-22T23:13:54.135-07:00Teaching Kids to Program - Part 1This summer, I've been teaching my two oldest kids to program. They're ages sever and four and a half so I'm tailoring our lessons to what I imagine they can grasp in what can be a very abstract field of study. I've been super impressed with what they've learned so far!<br />
<br />
The first challenge was thinking how to make programming interesting and compelling. Something too abstract feels like it would be challenging, there needs to be immediate feedback. Type this in, see what changes on the screen. How about we set out to make a game? That was one of the first pursuits that got me into programming in my teenage years.<br />
<br />
The second consideration was balancing simplicity and ease of use. When programming, I always felt more confident when I could understand at a pretty low level what was going on. For this reason I wanted to make sure they gained an understanding of the fundamentals. We'd start with a view of a computer as a very simple machine. Even if this means there is some extra coding needed to get the desired effect on the screen. It's better (IMHO) to add abstractions later once they have an underlying understanding than to try to understand a powerful but complicated library that initially gets quick results.<br />
<br />
I'm planning to post what we covered each week. We spend 30-60 minutes in a once a week session though some weeks we're taking off. It is summer after all!<br />
<br />
Here's what we covered in our first lesson.<br />
<br />
1. You can tell a computer what to do!<br />
<br />
We opened up the terminal and I told them to type<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">print "Hello [name]"</span><br />
<br />
Here it is, immediate feedback with the simplest possible "program." To get this working, I added a bash alias print=echo. Seems like print is a more common name across programming languages for "write something to stdout."<br />
<br />
This went over pretty well, both kids typed some things.<br />
<br />
Time to introduce some programming concepts. I explained that this was calling a <i>function</i> named print. The print function writes out whatever you tell it to write. I hope purist will forgive my painting with a broad brush.<br />
<br />
Next I explained that the words that you give to the function to put on the screen are an <i>argument</i>, er, well, a <i>parameter</i>. The looks on their faces when I called these arguments made it pretty clear that they were thinking of what transpires out in the sandbox.<br />
<br />
So here we'd covered the main ideas I wanted to teach them in the first lesson. You can tell a computer what to do! The "what to do" is specified using a <i>function</i> and the <i>parameters</i> that you pass to the function to tell it what or how you want things done.<br />
<br />
Time for more fun.<br />
<br />
Our four and a half year old can read basic words, but I imagined typing and reading might get tedious pretty fast. So next we turned to something just as simple that doesn't require reading from the screen, and not surprisingly was quite a bit of fun: the Mac say program.<br />
<br />
If you've never played with this, in the Mac terminal there is command "say" which works like echo except it speaks whatever you give it in a computerized voice. We started with<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">say "Hello [name]"</span><br />
<br />
Great fun! From there I asked them what parameters we should give the say function next. This filled the rest of our time. By far the biggest hit was <span style="font-family: Courier New, Courier, monospace;">say "[Baby's name] are you pooping?"</span><br />
<br />
Yup, teaching kids to program.Jeff Scudderhttp://www.blogger.com/profile/13002167096451875802noreply@blogger.com0tag:blogger.com,1999:blog-33260599.post-18362786360699760412013-05-15T00:05:00.000-07:002013-05-15T00:14:34.503-07:00Easy Raspberry Pi Setup (Using Windows)So there I was, new <a href="http://www.raspberrypi.org/">Raspberry Pi</a> in hand. Now to set it up. One small setback, I don't exactly have a monitor, keyboard, and mouse handy. How did I end up with so many laptops?<br />
<br />
Turns out setting it up and getting to a command line was a breeze, no monitor (etc.) required. All it took was an Ethernet cable and my router.<br />
<br />
Here's what I did.<br />
<br />
First, I wrote the operating system disk image to an SD card using the instructions on the <a href="http://www.raspberrypi.org/quick-start-guide">Raspberry Pi Quick Start Guide</a>.<br />
<ul>
<li>Downloaded the latest image from <a href="http://www.raspberrypi.org/downloads">raspberrypi.org/downloads</a></li>
<li>Extracted it and found the .img file</li>
<li>Installed <a href="http://sourceforge.net/projects/win32diskimager/">Win 32 Disk Imager</a></li>
<li>Plugged in the SD card</li>
<li>Used the disk imager to write the .img file to the drive for the SD card</li>
</ul>
Second, I started up the Raspberry Pi to connect to it.<br />
<br />
I plugged the Raspberry Pi into the router using that Ethernet cable, then powered it up!<br />
<br />
The next step will depend on your router but some routers will show you a list of the devices that are connected to the network from the admin screen. Here's an example<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-G7hiaduSd4w/UZMnqhxZwXI/AAAAAAAABC0/xpyOVs0-EGY/s1600/raspberrypi-router-address.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="274" src="http://1.bp.blogspot.com/-G7hiaduSd4w/UZMnqhxZwXI/AAAAAAAABC0/xpyOVs0-EGY/s320/raspberrypi-router-address.png" width="320" /></a></div>
<br />
Armed with the IP address, you can ssh into the Raspberry Pi machine. (I used <a href="http://www.putty.org/">PuTTY</a>.)<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-dirwpcZgl7Q/UZMovgYciqI/AAAAAAAABDA/2wJ10hbm5Ww/s1600/raspberrypi-putty.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="239" src="http://4.bp.blogspot.com/-dirwpcZgl7Q/UZMovgYciqI/AAAAAAAABDA/2wJ10hbm5Ww/s320/raspberrypi-putty.png" width="320" /></a></div>
<br />
There you have it. From the command line you can configure whatever else is needed and you'll never have to scrounge up one of those pesky keyboards.Jeff Scudderhttp://www.blogger.com/profile/13002167096451875802noreply@blogger.com225tag:blogger.com,1999:blog-33260599.post-65596332112945888852012-07-19T07:12:00.000-07:002012-07-19T07:12:50.597-07:00waitFor JavaScriptIn the spirit of building the simplest thing that could possibly work, I revisit the concept in <a href="http://blog.jeffscudder.com/2010/06/javascript-tricks-to-speed-up-your-site.html">another of my posts</a>: simple asynchronous JavaScript.<br />
<br />
Time and time again I see web developers relying on the order that JavaScript loads in a page to ensure that the site will work. This keeps the mental model simple, "all the stuff above this code will be available here", but it means that people trying to speed up browsers and JavaScript interpreters have their hands tied. Why not instead load and execute as much JavaScript in parallel as possible, like a mutlithreaded application, and wait for your dependencies to load or preconditions to be met before your code runs.<br />
<br />
You could do it all in just a few lines:<br />
<br/>
<div style="background-color: white; font-family: 'Courier New', Courier, monospace;">
function waitFor(condition, callback) {<br />
function waiter(condition, callback) {<br />
return function() {<br />
var condMet = false;<br />
try {<br />
condMet = condition();
<br /> } catch (e) {}<br />
<br /> if (condMet) {<br />
callback();<br />
} else {<br />
setTimeout(waiter(condition, callback), 5);<br />
}<br />
};<br /> }<br />
<br /> waiter(condition, callback)();<br />
}</div><br />
Using it looks a bit like this<br />
<br />
<div style="background-color: white; font-family: 'Courier New', Courier, monospace;">
waitFor(<br />
// condition<br />
function() {return window.dependency;},<br />
// callback <br />
function() {<br />
// do things using dependency.<br />
}<br />
);</div><br />
For example, here's how you might set this up to check if jQuery has been loaded and that a particular element on the page has been loaded in the DOM.<br />
<br />
<div style="background-color: white; font-family: 'Courier New', Courier, monospace;">
waitFor(function() {return $('#msgid');}, function() {<br />
$(document).ready(function(){<br />
$('#msgid').html('jQuery says "hi"!');<br />
});<br />
});</div>
<br />
Now it doesn't matter what order your script tags are in. Of course, you'll get the best performance if jQuery gets loaded before this waitFor call is made. The wait and retry loop adds some cost. If browsers had an event model available for script loading or conditions then we wouldn't have to poll using setTimeout/Interval. But for existing browsers all the way back to IE 6, this simple helper function will work.<br />
<br />
For managing JavaScript dependencies there's also <a href="http://requirejs.org/">require.js</a> which does quite a bit more (and is larger). I wrote this to be lighter weight and it is more general and flexible than a framework like require.js. Using waitFor, you could set up logic that is triggered if and when certain arbitrary conditions become true.<br />
<br />
One little improvement, if you are waiting for lots of things then you would probably want to replace multiple timers with a single timer that will check all conditions. Like this:<br />
<br />
<div style="background-color: white; font-family: 'Courier New', Courier, monospace;">
function waitFor(condition, callback) {<br /> waitFor.waitingFor.push([condition, callback]);<br /> waitFor.check();<br /> }<br /> <br /> waitFor.waitingFor = [];<br /> <br /> waitFor.check = function() {<br /> var stillWaitingFor = [];<br /> for (var i = 0; i < waitFor.waitingFor.length; i++) {<br /> var condMet = false;<br /> try {<br /> condMet = waitFor.waitingFor[i][0]();<br /> } catch (e) {}<br /> if (condMet) {<br /> waitFor.waitingFor[i][1]();<br /> } else {<br /> stillWaitingFor.push(waitFor.waitingFor[i]);<br /> }<br /> }<br /> <br /> waitFor.waitingFor = stillWaitingFor;<br /> if (stillWaitingFor.length > 0) {<br /> setTimeout(waitFor.check, 5);<br /> }<br /> };</div><br />
Here's a minified version. I added some newlines for formatting which you can take out.<br />
<br />
<div style="background-color: white; font-family: 'Courier New', Courier, monospace;">
function w(c,b){w.w.push([c,b]);w.c()}<br /> w.w=[];w.c=function(){for(var s=[],b=0;b<w.w.length;b++)<br /> {var d=!1;try{d=w.w[b][0]()}catch(e){}<br /> if(d)w.w[b][1]();else s.push(w.w[b])}w.w=s;0<s.length<br /> &&setTimeout(w.c,5)};var waitFor=w;</div><br />
Happy coding!Jeff Scudderhttp://www.blogger.com/profile/13002167096451875802noreply@blogger.com0tag:blogger.com,1999:blog-33260599.post-24906142238369721042012-05-11T18:22:00.000-07:002012-05-11T18:36:04.194-07:00JavaScript Caching: appendChild vs document.writeI found myself trying to prefetch some data which would appear in an iframe. I wanted to see if requesting the same JSON in the parent page and then in the iframe would cause the second request, made in the iframe, to hit the browser's cache in all cases. It turns out that for Internet Explorer and Web Kit based browsers it depends on how you request the JSON in the parent page.<br />
<br />
If you use <code>appendChild</code> in IE the identical JS request will hit the browser cache.<br />
If you use <code>document.write</code> in IE it will not hit the cache.<br />
<br />
However, in Chrome and Safari if you <code>appendChild</code> in the parent, you will miss the cache. Using <code>document.write</code> in the parent page causes a cache hit.<br />
<br />
Here are the results I gathered. <br />
<table>
<tbody>
<tr>
<td><b>Cache Hit?</b></td>
<td>both <code>document.write</code></td>
<td>parent <code>document.write</code><br />
iframe <code>appendChild</code></td>
<td>parent <code>appendChild</code><br />
iframe <code>document.write</code></td>
<td>both <code>appendChild</code></td>
</tr>
<tr>
<td>Internet Explorer</td>
<td>miss</td>
<td>miss</td>
<td>hit</td>
<td>hit</td>
</tr>
<tr>
<td>Firefox</td>
<td>hit</td>
<td>hit</td>
<td>hit</td>
<td>hit</td>
</tr>
<tr>
<td>Chrome</td>
<td>hit</td>
<td>hit</td>
<td>miss</td>
<td>miss</td>
</tr>
<tr>
<td>Safari</td>
<td>hit</td>
<td>hit</td>
<td>miss</td>
<td>miss</td>
</tr>
<tr>
<td>Opera</td>
<td>hit</td>
<td>hit</td>
<td>hit</td>
<td>hit</td>
</tr>
<tr>
<td>Android</td>
<td>?</td>
<td>?</td>
<td>?</td>
<td>?</td>
</tr>
<tr>
<td>iOS</td>
<td>?</td>
<td>?</td>
<td>?</td>
<td>?</td>
</tr>
</tbody></table>
<br />
All versions of IE behaved the same, I didn't check different versions of the other browsers.<br />
<br />
To test this I wrote a test web application called <a href="http://code.google.com/p/json-caching-exploration/">json-caching-exploration</a>. It's a simple web app that runs on App Engine.<br />
<br />
<a href="http://code.google.com/p/json-caching-exploration/source/browse/main.py">Server and HTML</a><br />
<a href="http://code.google.com/p/json-caching-exploration/source/browse/lib.js">JavaScript</a><br />
<br />
I haven't run this against mobile browsers yet. If you give it a try please let me know what you find.<br />
<br />
It's a shame that these browsers behave differently, especially given the differences in browser behavior between loading JavaScript using <code>document.write</code> and <code>appendChild</code>.Jeff Scudderhttp://www.blogger.com/profile/13002167096451875802noreply@blogger.com0tag:blogger.com,1999:blog-33260599.post-10271424682582335252011-05-28T01:35:00.001-07:002011-06-09T00:29:55.031-07:00Go on App Engine Example - Part 1The <a href="http://code.google.com/appengine/">App Engine</a> team recently <a href="http://blog.golang.org/2011/05/go-and-google-app-engine.html">announced</a> support for <a href="http://golang.org/">Go</a> as a runtime for use in apps. Summary up front, the <a href="http://code.google.com/p/googleappengine/downloads/list">App Engine SDK</a> for the Go runtime is the easiest way I've found yet to get started with Go. As I change my code, it is recompiled in the background when I make a request to my app, so it feels very much like developing in a scripting language.<br /><br />I've been excited about the Go language for some time now (specifics on why will have to wait for another post) so I was eager to try it out in one of my favorite platforms: App Engine. I wanted to start with something small, so I wrote a simplified version of a web app that I've been itching to write lately, a site for hosting plain text content. Specifically, I want something that preserves whitespace, allows me to line up columns of text, and supports non-English characters (Unicode). Those are the kinds of things I need to share and talk about code. Also there is a great deal more you can do with plain old monospaced text, maybe you'll find this useful as well.<br /><br />With that objective in mind I give you <a href="http://plaintextmachine.appspot.com/">the Plain Text Machine</a>. This little app lets you enter a small amount of text, somewhere around 2,000 characters, and gives you a link that others can visit to see an HTML reproduction of your writing. I mentioned I wanted to keep this simple, so here's the odd little bit, this app doesn't store your text anywhere. The URL that is generated contains the text, hence the somewhat low limit on message length. It certainly keeps the app simple, the most complex logic is that which converts the text from the URL into HTML.<br /><br />A request starts by hitting the <code>Init</code> function:<pre>func init() {<br /> http.HandleFunc("/", handle)<br /> http.HandleFunc("/show", show)<br />}</pre>The main page, at <code>/</code>, is just static content, we're just interested in the <code>/show</code> handler. It looks like this:<pre>func show(w http.ResponseWriter, r *http.Request) {<br /> w.Header().Set("Content-Type", "text/html; charset=utf-8")<br /> // Get the message from the URL.<br /> PrintHtml(utf8.NewString(r.FormValue("msg")), w)<br />}</pre>The above does two things, sets the content type of our response so that the browser will know it is HTML, and reads the message URL parameter from the request to convert it to HTML.<br /><br />The PrintHtml method prints out some boilerplate HTML then reads the message one character at a time and converts each character to its HTML-safe equivalent. There's a tiny bit of complexity to make sure that the whitespace is preserved instead of being collapsed as would normally be done with repeated spaces in HTML. Here's the code:<pre>func PrintHtml(text *utf8.String, out http.ResponseWriter) {<br /> spaces := false<br /> <br /> fmt.Fprint(out, textHeader, middle)<br /> for i := 0; i < text.RuneCount(); i++ {<br /> currentChar := text.At(i)<br /> <br /> if currentChar == 32 && !spaces {<br /> // A first space.<br /> fmt.Fprint(out, " ")<br /> spaces = true<br /> } else {<br /> if currentChar == 32 {<br /> // Space following another space<br /> fmt.Fprint(out, "&nbsp;")<br /> } else if currentChar == 10 {<br /> // Newline<br /> fmt.Fprint(out, "<br>")<br /> } else if currentChar == 9 {<br /> // Tab<br /> fmt.Fprint(out, "&nbsp;&nbsp;&nbsp; ")<br /> } else if currentChar == 38 {<br /> // &<br /> fmt.Fprint(out, "&amp;")<br /> } else if currentChar == 60 {<br /> // <<br /> fmt.Fprint(out, "&lt;")<br /> } else if currentChar == 62 {<br /> // ><br /> fmt.Fprint(out, "&gt;")<br /> } else if currentChar < 31 || currentChar == 128 {<br /> // Skip control characters.<br /> } else if currentChar < 127 {<br /> fmt.Fprintf(out, "%c", currentChar)<br /> } else {<br /> fmt.Fprintf(out, "&#%d;", text.At(i))<br /> }<br /> spaces = false<br /> }<br /> }<br /> fmt.Fprint(out, footer)<br />}</pre>The <code>textHeader</code>, <code>middle</code>, and <code>footer</code> variables are string constants containing the wrapper HTML which gives style information.<br /><br />If you're interested in the full source code for this tiny little app, you can find it in the <a href="http://code.google.com/p/plain-text-machine/">Plain Text Machine open source project</a>. Hopefully this example provides an easy to understand picture of what Go code for App Engine looks like.<br /><br />I had quite a bit of fun putting together this app. By keeping it simple I was able to go from idea to done in less time than it took me to write this blog post. As an added bonus, having an app with no persistent storage brings up some interesting philosophical questions. For example, if a message is created but no one stores the link to it, does it still exist?Jeff Scudderhttp://www.blogger.com/profile/13002167096451875802noreply@blogger.com2tag:blogger.com,1999:blog-33260599.post-57168642713324783172011-05-09T13:21:00.000-07:002011-06-04T01:37:09.279-07:00Setup OAuth2 for Google APIsToday I'm at <a href="http://www.io-bootcamp.com/">I/O Bootcamp</a> and helping out with a walkthrough on how to get starting using Google APIs in a variety of languages.<br /><br />One of the things I appreciate about the Google APIs is the authorization mechanism which lets me see which applications I've granted access for my data and allows me to revoke access. As an application developer, there are some things that I need to do to identify my application so that Google knows which app is requesting access so that it can show the user more information about my app. The first step, then, in writing an application that uses OAuth2 is registering your app.<br /><br />You can begin the registration process on the <a href="https://code.google.com/apis/console/">Google API console</a> by creating a project:<br /><br /><a href="http://4.bp.blogspot.com/-NvMboJYRPSU/TchTHHpJ0eI/AAAAAAAAAnA/pO9C6hkv0mU/s1600/Screen%2Bshot%2B2011-05-09%2Bat%2B1.47.39%2BPM.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 255px;" src="http://4.bp.blogspot.com/-NvMboJYRPSU/TchTHHpJ0eI/AAAAAAAAAnA/pO9C6hkv0mU/s400/Screen%2Bshot%2B2011-05-09%2Bat%2B1.47.39%2BPM.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5604821118038430178" /></a><br /><br /><a href="http://1.bp.blogspot.com/-CQVe0NCqKPs/TchTgynXkFI/AAAAAAAAAnI/WEX7fRP9zsk/s1600/Screen%2Bshot%2B2011-05-09%2Bat%2B1.49.51%2BPM.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 172px;" src="http://1.bp.blogspot.com/-CQVe0NCqKPs/TchTgynXkFI/AAAAAAAAAnI/WEX7fRP9zsk/s400/Screen%2Bshot%2B2011-05-09%2Bat%2B1.49.51%2BPM.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5604821559070396498" /></a><br /><br />Now that you have an application, you'll need to configure it for use with OAuth2 and get the secret tokens that your application will use in its requests. For that create an OAuth2 client ID.<br /><br /><a href="http://2.bp.blogspot.com/-fXaXeBIif0g/Tchcsxr8WCI/AAAAAAAAAnQ/tWWprMXb7BQ/s1600/Screen%2Bshot%2B2011-05-05%2Bat%2B10.54.24%2BAM.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 176px;" src="http://2.bp.blogspot.com/-fXaXeBIif0g/Tchcsxr8WCI/AAAAAAAAAnQ/tWWprMXb7BQ/s400/Screen%2Bshot%2B2011-05-05%2Bat%2B10.54.24%2BAM.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5604831660584228898" /></a><br /><br />The most vital decision to make during the sign up flow is if your application is a "web application" or an "installed application". If you're a site accessed in a browser and you're able to send the users to a Google web page for authorization and then have the broswer redirect back to your app, then you want web application. For an installed application, the user will still need to authorize your app by visiting a web page, but once authorization is complete, the secret token will be sent to the app either using a redirect to a local running web server or by having the user copy and paste the secret into your application.<br /><br />For the command line samples I've been playing with I choose installed application.<br /><br />After creating the client ID you should see information something like this<br /><br /><pre>Client ID: #######.apps.googleusercontent.com<br />Client secret: Amzz5Yip2SJPqqq5Jx<br />Redirect URIs: urn:ietf:wg:oauth:2.0:oob<br /> http://localhost</pre><br /><br />You'll need to put this information into your application so that it can use the client ID and secret when making requests to get an authorization token from the user. This can be as simple as copying and pasting these strings into your code.<br /><br />The one other thing that needs to be done before you begin using OAuth2 with one of the Google APIs is to turn on the API for your application. This can be done on the developer console "Services" section.<br /><br />Let's say that I wanted to access the URL Shortener API. First I would need to enable it for my application.<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/-_aQhfvEiVg0/TchsR7eCJRI/AAAAAAAAAnY/nw5C9BJMpK0/s1600/Screen%2Bshot%2B2011-05-05%2Bat%2B10.53.12%2BAM.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 74px;" src="http://4.bp.blogspot.com/-_aQhfvEiVg0/TchsR7eCJRI/AAAAAAAAAnY/nw5C9BJMpK0/s400/Screen%2Bshot%2B2011-05-05%2Bat%2B10.53.12%2BAM.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5604848791539819794" /></a><br /><br />Then I would need to specify the URL Shortener's API scope when I request authorization from a specific user. The scopes that are requested by my app are turned into a list of APIs that the user must grant access to when they authorize my application.<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/-lKH4Ym7oqSM/Tcht_Lc23iI/AAAAAAAAAng/F5KqGpqsg00/s1600/Screen%2Bshot%2B2011-05-09%2Bat%2B3.42.32%2BPM.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 248px;" src="http://1.bp.blogspot.com/-lKH4Ym7oqSM/Tcht_Lc23iI/AAAAAAAAAng/F5KqGpqsg00/s400/Screen%2Bshot%2B2011-05-09%2Bat%2B3.42.32%2BPM.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5604850668435594786" /></a><br /><br />The scope for an API can be found in the API documentation under authorization.<br /><br />For an example that brings all of these settings together, see the <a href="http://code.google.com/p/google-api-python-client/source/browse/samples/urlshortener/urlshortener.py">urlshortener.py</a> example:<br /><br /><pre><br /> FLOW = OAuth2WebServerFlow(<br /> client_id='433807057907.apps.googleusercontent.com',<br /> client_secret='jigtZpMApkRxncxikFpR+SFg',<br /> scope='https://www.googleapis.com/auth/urlshortener',<br /> user_agent='urlshortener-cmdline-sample/1.0')<br /> ...<br /> credentials = run(FLOW, storage)<br /> ...<br /> http = httplib2.Http()<br /> http = credentials.authorize(http)<br /></pre><br /><br />Python may not be your bag, but no worries, there are client libraries for the Google APIs in a variety of languages, and even better, there is an <a href="http://code.google.com/apis/explorer/">API Explorer</a> that lets you try out the underlying protocol without any language specific stuff getting in the way.<br /><br />For example, here is getting details and stats about a short URL:<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/-RQUc2DHdNLc/Tch5CqKoJTI/AAAAAAAAAno/rGX0pA8ajkg/s1600/Screen%2Bshot%2B2011-05-05%2Bat%2B10.40.40%2BAM.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 200px;" src="http://1.bp.blogspot.com/-RQUc2DHdNLc/Tch5CqKoJTI/AAAAAAAAAno/rGX0pA8ajkg/s400/Screen%2Bshot%2B2011-05-05%2Bat%2B10.40.40%2BAM.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5604862822848144690" /></a><br /><br />And here is creating a new short link:<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/-dgYXdVcyI7U/Tch7EzPWHlI/AAAAAAAAAoA/g7aK4Wk442A/s1600/Screen%2Bshot%2B2011-05-09%2Bat%2B4.38.21%2BPM.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 112px;" src="http://4.bp.blogspot.com/-dgYXdVcyI7U/Tch7EzPWHlI/AAAAAAAAAoA/g7aK4Wk442A/s400/Screen%2Bshot%2B2011-05-09%2Bat%2B4.38.21%2BPM.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5604865058666847826" /></a><br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/-03ubdyt9MUc/Tch5C_7mmiI/AAAAAAAAAnw/aX8AkPGbSKA/s1600/Screen%2Bshot%2B2011-05-05%2Bat%2B10.45.17%2BAM.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 239px;" src="http://4.bp.blogspot.com/-03ubdyt9MUc/Tch5C_7mmiI/AAAAAAAAAnw/aX8AkPGbSKA/s400/Screen%2Bshot%2B2011-05-05%2Bat%2B10.45.17%2BAM.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5604862828690709026" /></a><br /><br />For all the details on using these APIs, take a look at the documentation. For example here are the <a href="http://code.google.com/apis/urlshortener/v1/getting_started.html">URL shortener docs</a>. The common first step for almost all of the Google APIs that access user information is the registration step we started with. For more details on <a href="http://code.google.com/apis/accounts/docs/OAuth2.html">OAuth2 with Google APIs</a>, there is some excellent documentation <a href="http://code.google.com/apis/accounts/docs/OAuth2.html">here</a>.Jeff Scudderhttp://www.blogger.com/profile/13002167096451875802noreply@blogger.com0tag:blogger.com,1999:blog-33260599.post-33422461720767186092011-03-08T07:19:00.000-08:002011-03-09T14:17:24.473-08:00Free Verse #397Sipping a late,<br />writing a free verse poem.<br />Hey look, a haiku!Jeff Scudderhttp://www.blogger.com/profile/13002167096451875802noreply@blogger.com0tag:blogger.com,1999:blog-33260599.post-68190481792650997022011-01-23T22:12:00.000-08:002011-01-24T23:17:58.959-08:00Mercurial in Five CommandsCompleting any sort of significant programming project can be nearly impossible without version control. For a class project, I recently collaborated with a small group on a large programming assignment. To keep all of our changes in sync while working miles away from each other, we used a centralized version control system.<br /><br />Since I've been working quite a bit with <a href="http://mercurial.selenic.com/">Mercurial</a> lately, we went with a free private project on <a href="https://bitbucket.org/">bitbucket</a>. It was the first time my teammates had used Mercurial so I gave a crash course that I thought would be helpful for others as well. A distributed version control system has a large number of commands and features, but 90% of the time, you're just dealing with the basics. When working with a team you can get by with just these five Mercurial commands: clone, commit, push, pull, and update.<br /><br /><h4>Setting up the Project</h4><br />As I mentioned, we were using a hosted repository on bitbucket, so getting a working copy of the repository on our machines started with each of us executing <code>hg clone</code>. It looked a little something like this:<pre>hg clone https://your-username@bitbucket.org/your-username/project</pre>This will create a local repository with a copy of each file and you're now free to make changes. You can edit files locally and Mercurial will track the changes for you. If you want to add new files or remove existing files, make sure to use <code>hg add</code> and <code>hg remove</code>. (Bonus commands!). Once you're happy with your changes and you want to gather them up in a logical unit it's time for:<br /><br /><h4>Local Snapshots</h4><br />To save a set of changes locally, you use <code>hg commit</code>. Be sure to write an informative description of this change set since you and others will want to remember what this set of changes was all about. There are a few arguments to the commit command that come in handy, often I do:<pre>hg ci -u your-username -m 'Reduces codebase entropy. All tests pass!'</pre>For more options on the commit command and any other Mercurial command you can use <code>hg help <command></code>. You can also see a diff of your current files compared to the most recent snapshot using the <code>hg diff</code> command. (Bonus times two!)<br /><br />Pinning your changes locally is a fantastic feature of distributed version control systems. As I work I tend to take a local snapshot several times an hour. These revisions just exist in your local copy, so you don't need to worry about clashing with other people's code at this point or making sure that all changes are usable. Sometimes when I decide I've gone down the wrong path I'll take a snapshot of the ill conceived changes before I roll them back, just in case I decide later on that some of the ideas weren't so bad after all.<br /><br />Once you have something that's ready for others to use, it's time to:<br /><br /><h4>Share</h4><br />To get your changes into the hands of others, you can push them back up to the central repository. You do this with the <code>hg push</code> command. Since we created our local repository using clone, your local copy knows where to send the changes. Also, if you'd like to do something different, like push your changes to a different location than where we cloned from, you can take a look at more options of the push command using <code>hg help push</code>.<br /><br />The push command will upload all of your local commits, along with those handy descriptions, for the rest of your team to see. <br /><br />Now others on your team are pushing up their changes too and it would be great to get their changes so you are all working on the same code. What's that saying, "It's better to give than to...?"<br /><br /><h4>Receive</h4><br />To get the changes others have posted to the repository into your local copy, you use <code>hg pull</code>. Running this command copies the change sets that you haven't received yet to your local repository, but it doesn't edit your files or apply the changes just yet. Since you might want to be selective about what changes you apply, Mercurial splits applying the changes into two steps. First you pull, then you use <code>hg update</code>. When called with no additional arguments like that, <code>hg update</code> applies all of the changes.<br /><br />I recommend pulling and updating often. In our group, since there were just a few of us, we'd post in a chat room when we pushed changes so others would know to pull. If you push before you pull in other people's changes, you might need to use <code>hg merge</code>. Also, you can see all of the changes which are in your repository with the <code>hg log</code> command. (Triple bonus, hey a hat-trick!)<br /><br />There you have it!<br /><br /><h4>Want more?</h4><br />I tried to keep this simple and focused, the bare minimum to work on a project with a small team. Mercurial has more to offer. I haven't touched branches yet, or looking at diffs, or creating your own local repository from scratch, or sharing your changes by running your own server locally. All of these are just single commands! For further reading take a look at <a href="http://hgbook.red-bean.com/read/">Mercurial: The Definitive Guide</a>.<br /><br />There are a few services which offer hosting of Mercurial repositories. For open source, <a href="http://code.google.com/p">Project Hosting on Google Code</a> is an option as well as bitbucket which I used for the first time this past week. Any other Mercurial hosting providers that you recommend?Jeff Scudderhttp://www.blogger.com/profile/13002167096451875802noreply@blogger.com0tag:blogger.com,1999:blog-33260599.post-92220633609235421092010-09-10T22:56:00.000-07:002010-09-11T01:42:59.001-07:00GreekishI've long been fascinated with other alphabets. All of these strange and unusual symbols, it's almost like a code. This love of secrets was one of the reasons that I studied Ancient Greek. After reading and writing quite a bit of Greek, reading the alphabet became second nature. I even began taking notes using the Greek alphabet but using English words (since my Greek vocabulary is sadly inadequate). Performing simple character substitution sounded like a perfect one-hour project so I whipped up a <a href="http://www.jeffscudder.com/greekish">simple web page</a> to convert English text into a Greek alphabet equivalent. I call it <a href="http://www.jeffscudder.com/greekish">Greekish</a>. For example, the phrase<pre>So long and thanks for all the fish.</pre>becomes<pre>Σο λονγ ανδ θανκσ φορ αλλ θε φισh.</pre>which would be quite confusing to a Greek speaker but perfectly natural to an English speaker who knows the Greek alphabet.<br /><br />Note that some English characters do not have direct equivalents in Greek. A c would be a κ, a σ, or a χ for ch. The h is one of the more interesting stories. For a leading h before a vowel Greek uses a <a href="http://en.wikipedia.org/wiki/Greek_diacritics#Breathings">breathing mark</a>. When combined with a consonant, special characters are used, like θ for th, χ for ch, and φ for ph. I chose to use φ only for the English f, not ph, since ph does not make the f sound in some English contexts. The word u<em>ph</em>ill is one example. Also, I didn't bother to handle the special case of s at the end of word, for which ς is used instead of σ.<br /><br />Now that you know more than you ever wanted to about the Greek alphabet, what is a simple project that you can tackle in an hour? Don't just think of one, go do it!Jeff Scudderhttp://www.blogger.com/profile/13002167096451875802noreply@blogger.com1tag:blogger.com,1999:blog-33260599.post-16535185409457324372010-06-22T01:24:00.000-07:002010-07-03T00:53:22.439-07:00A Simple Testing Library for CTo prepare for a recent post graduate computer science class, I wrote a small library in C which aids in the creation of lightweight, unit-test-like programs. The code can be found <a href="http://code.google.com/p/c7e3/source/browse/#hg/testing">here</a>, and using it looks a bit like this:<pre>#include"asserts.h"<br /><br />int main(void)<br />{<br /> c7e3_assert(1 == 1, "1 should equal 1");<br /> c7e3_assert(2 == 2, "2 should equal 2");<br /> c7e3_report();<br /> return 0;<br />}</pre>The design follows the <a href="http://en.wikipedia.org/wiki/KISS_principle">KISS principle</a> and I think it is a nice fit to the simplicity of C. While there is not much to it, I wrote numerous tests using it over the past couple of months and all of that testing certainly <a href="http://twitter.com/jscud/status/17233896676">paid off</a>.Jeff Scudderhttp://www.blogger.com/profile/13002167096451875802noreply@blogger.com0tag:blogger.com,1999:blog-33260599.post-63829764842210239702010-06-18T00:30:00.000-07:002010-06-22T01:10:08.183-07:00JavaScript Tricks to Speed up Your SiteOne of the techniques which makes the web so powerful is the ability to load code, images, and other resources from all over the Internet. So often though, the process of loading these resources and ensuring that all of the required pieces are in place leads to a slow experience for visitors. With the ability to include so much code from across the web, visiting a site could potentially be like installing a new program when it comes to the amount of stuff that needs to be downloaded.<br /><br />With this in mind, there are a couple of nifty tricks that can help make your app more responsive and I've written up an example site and testing server that shows some ideas for speeding up the user experience when you need to wait for the DOM to load or for additional JavaScript to be fetched and run. We'll begin with document operations.<br /><br />Often the JavaScript running on a page manipulates the DOM, using <code>document.getElementById</code> here and <code>document.createElement</code> there. In order to ensure that all the pieces of the page are in place, web programmers often take advantage of the onload callback. It might be used like this<pre><body onload="runMyCodeNow()"></pre>Using this technique ensures that all of the things your code might want to read and write from the page are in place. All images have been downloaded, CSS rules have been applied, the layout is all there. However, all of this comes with a cost, your code doesn't run until every last resource has been fetched and rendered. Even the little footer at the bottom of the page, for example, that your code doesn't care about.<br /><br />There is a another way, we could request that resources be loaded in parallel and start executing our code before the page is fully loaded. Chances are, your code doesn't need the complete page to be loaded before it starts running, and running before <code>onload</code> will reduce the delay for your users. Before I dive into how this can be accomplished, lets look at an example which uses the old fashioned way.<br /><br />Lets say you have a web page, a little HTML which includes five JavaScript files. One may be a library used to do animation, another one for loading the users data. In any case, all of these files need to be loaded and some of them depend on others.<br /><br />The biggest bottleneck for your users is almost certainly having all of these resources load. Network latency is a killer, and something that is often overlooked during development. To create a simulated network environment which can give a more realistic (or even pessimistic) view of the cost of loading these resources, I wrote a "slow server" which can introduce a delay to the file requested. Here is the code for my testing server (designed to run on <a href="http://code.google.com/appengine/">App Engine</a>):<pre>def FilePath(path):<br /> """The requested path into a local file path."""<br /><br /> return os.path.join(os.path.dirname(__file__), 'files', path[1:])<br /><br /><br />class SleepyRenderer(webapp.RequestHandler):<br /> """Serves the requested page with a client configured delay.<br /><br /> Delay is given as a URL parameter in hundredths of a second to delay.<br /> For example, 200 means wait 2 seconds before responding.<br /><br /> Example request:<br /> http://localhost:8080/hi.html?delay=300&contenttype=text/html<br /> """<br /><br /> def get(self):<br /> path = self.request.path<br /> delay = self.request.get('delay')<br /> content_type = self.request.get('contenttype') or 'text/html'<br /> if delay:<br /> time.sleep(int(delay)/100)<br /> http_status = 200<br /> requested_file = None<br /><br /> try:<br /> requested_file = open(FilePath(path))<br /> self.response.out.write(requested_file.read())<br /> requested_file.close()<br /> except IOError:<br /> http_status = 404<br /><br /> self.response.set_status(http_status)<br /> self.response.headers['Content-Type'] = content_type<br /><br /><br />def main():<br /> application = webapp.WSGIApplication([('/.*', SleepyRenderer)],<br /> debug=True)<br /> util.run_wsgi_app(application)<br /><br /><br />if __name__ == '__main__':<br /> main()</pre>With the above code we can introduce a delay on each individual file. To see this in action with our example, here is some HTML which shows a traditional approach, include script includes and an onload callback when everything has loaded.<pre><html><br /> <head><br /> <script src="/testa.js?delay=500&contenttype=text/javascript"></script><br /> <script src="/testb.js?delay=400&contenttype=text/javascript"></script><br /> <script><br /> function init() {<br /> document.getElementById('output');<br /> output.innerHTML = [<br /> 'a is ' + a,<br /> 'b is ' + b,<br /> 'c is ' + c,<br /> 'd is ' + d,<br /> 'e is ' + e<br /> ].join('<br>');<br /> }<br /> </script><br /> <script src="/testc.js?delay=300&contenttype=text/javascript"></script><br /> </head><br /> <body onload="init()"><br /> <script src="/testd.js?delay=200&contenttype=text/javascript"></script><br /> <div id="output"></div><br /> <script src="/teste.js?delay=100&contenttype=text/javascript"></script><br /> <script src="/testa.js?delay=500&contenttype=text/javascript"></script><br /> </body><br /></html></pre>With the above, the page takes several seconds to load and when the very last script has loaded, the 'output' div gets its contents. In many cases, the code really doesn't need to wait for all resources to load, only the ones that are necessary for the code to run. In this case, since the information is added to the output div, we need the output div to exist in the DOM, but we may not need the entire page to load.<br /><br />If you look at this loading process in a profiler you might see something like this:<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_54HtFT6yBFI/TB_fhm_iT8I/AAAAAAAAAgk/tMxvwK8_qmM/s1600/Picture+37.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 228px;" src="http://2.bp.blogspot.com/_54HtFT6yBFI/TB_fhm_iT8I/AAAAAAAAAgk/tMxvwK8_qmM/s400/Picture+37.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5485348639656267714" /></a>Now for our first nifty trick. One way to check to see if the necessary prerequisites are present, is by polling the DOM or the JavaScript environment, to see if conditions are right for the code to run. Here is an example of how this code might be rewritten when using some polling helper functions:<pre> <script><br /> loader.whenNodePresent('output',<br /> function() {<br /> var output = document.getElementById('output');<br /> loader.whenReady(function() {return window['a'];},<br /> function() {<br /> output.innerHTML += 'a is ' + a + '<br>';<br /> }); <br /> loader.whenReady(function() {return window['b'];},<br /> function() {<br /> output.innerHTML += 'b is ' + b + '<br>';<br /> }); <br /> loader.whenReady(function() {return window['c'];},<br /> function() {<br /> output.innerHTML += 'c is ' + c + '<br>';<br /> }); <br /> loader.whenReady(function() {return window['d'];},<br /> function() {<br /> output.innerHTML += 'd is ' + d + '<br>';<br /> }); <br /> loader.whenReady(function() {return window['e'];},<br /> function() {<br /> output.innerHTML += 'e is ' + e + '<br>';<br /> }); <br /> })<br /> </script></pre>The code to track the prerequisites and poll is quite simple:<pre>loader.waiting = [];<br /><br /><br />loader.whenReady = function(testFunction, callback) {<br /> if (testFunction()) {<br /> callback();<br /> } else {<br /> loader.waiting.push([testFunction, callback]);<br /> window.setTimeout(loader.checkWaiting, 200);<br /> }<br />};<br /><br /><br />loader.checkWaiting = function() {<br /> var oldWaiting = loader.waiting;<br /> var numWaiting = oldWaiting.length;<br /> loader.waiting = [];<br /> for (var i = 0; i < numWaiting; i++) {<br /> if (oldWaiting[i][0]()) {<br /> oldWaiting[i][1]();<br /> } else {<br /> loader.waiting.push(oldWaiting[i]);<br /> }<br /> }<br /><br /> if (loader.waiting.length > 0) {<br /> window.setTimeout(loader.checkWaiting, 200);<br /> }<br />};<br /><br /><br />loader.whenNodePresent = function(nodeId, callback) {<br /> loader.whenReady(function () {<br /> return document.getElementById(nodeId);<br /> }, callback);<br />};</pre>In the above we use the <code>whenReady</code> function which takes a couple of functions, one to return a truthy or a falsey value, and one to call back when the first function evaluates to true. If the condition function isn't true when this first call is made, we check back every so often to see if it is ready.<br /><br />With these changes, we shave several seconds off of the user perceived loading time. Specifically we no longer need to wait for the duplicate load (of the <code>testa</code> script) at the end of the body. The page also appears to be more responsive because the later script's messages appear just after they load but before the page is complete.<br /><br />Now that we've seen a way to work around the need for an onload callback, lets look at another place we can tweak the browser's behavior to make a web page more responsive: dynamic script loading.<br /><br />The most straightforward way to include new code in your page is to use a script tag, something like:<pre><html><br /><head><br /><script src="some_great_sites_javascript"><br />...</pre>When the browser's JavaScript interpreter encounters this script src, it stops whatever it's doing and fetches that resource. It doesn't do any more rendering or executing of code until it's finished. This behavior varies a bit in different browsers and is likely an artifact of an old design in which this kind of single threaded behavior was the only option. Since some sites might depend on this linear behavior to get a script's dependencies all in order, this quirk might be with us for a long time. Most of this time, waiting like this is a really silly idea. How often do the scripts that you include depend on one another?<br /><br />There are a few parts to this trick. The first is to not put all of script includes in the HTML, you could have JavaScript add new script elements to the page which will cause new code to be loaded as needed. In this way, you could load only the resources that are needed at the moment, perhaps some resources would not end up being requested at all. Including a new script could be done in two ways:<pre>document.write('<script src="somefile.js"></script>');</pre>or<pre>var newScript = document.createElement('script');<br />newScript.src = 'somefile.js';<br />document.body.appendChild(newScript);</pre>Each of the above is appropriate in different situations. Document write adds HTML directly into the page at the point where the page is being loaded, it should only be used for script tag inclusion if the page is not yet loaded. If that page is loaded, using <code>document.write</code> to add the script tag will wipe out the existing body entirely. I've seen this issue in the wild, if you assume <code>document.write</code> is always safe, you'll be bitten when using it after the page has loaded.<br /><br />Instead you can perform a check to see if <code>document.body</code> exists, if it does then use <code>document.body.appendChild</code>. If it does not yet exist, use <code>document.write</code>. The code for this loader logic might look something like this:<pre>loader.loadScript = function(url) {<br /> if (document.body) {<br /> var newScript = document.createElement('script');<br /> newScript.type = 'text/javascript';<br /> newScript.src = url;<br /> document.body.appendChild(newScript);<br /> } else {<br /> document.write('<scr' + 'ipt type="text\/javascript" src="' +<br /> url + '"><\/scr' + 'ipt>');<br /> }<br />};</pre>Now we can request that new JavaScript code be loaded on the fly and it works when the page has not yet finished loaded as well as after it has. <br /><br />There is one more trick we can add to this loader. Some browsers will interpret the JavaScript in the order in which the scripts were requested, not the order in which they finished loading. That means that a fast loading script further down the list won't be run until a slower script, which appears above it, is loaded. One way we could defeat this delay, is to break the script includes out of linear execution in the JavaScript. If you use setTimeout to introduce a delay in adding the script include to the page, then the code which sets up the script requests can finish quickly and the browser will get back to the script requests later without the same linear constraints. In our code, we wrap the section of <code>loader.loadScript</code> in a short timeout as follows:<pre>loader.loadScript = function(url) {<br /> <strong>window.setTimeout(function() {</strong><br /> if (document.body) {<br /> var newScript = document.createElement('script');<br /> newScript.type = 'text/javascript';<br /> newScript.src = url;<br /> document.body.appendChild(newScript);<br /> } else {<br /> document.write('<scr' + 'ipt type="text/javascript" src="' +<br /> url + '"><\/scr' + 'ipt>');<br /> }<br /> <strong>}, 1);</strong><br />};</pre>With the above changes in place, our example page from before now loads like this when profiled (note that the messages appear in the order that the scripts were loaded, we don't have to wait for everything before we edit the page):<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_54HtFT6yBFI/TB_g-rV9bxI/AAAAAAAAAgs/-DJ53U2zw4s/s1600/Picture+38.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 228px;" src="http://1.bp.blogspot.com/_54HtFT6yBFI/TB_g-rV9bxI/AAAAAAAAAgs/-DJ53U2zw4s/s400/Picture+38.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5485350238551895826" /></a>Through the course of this post, I've written a small library for using these tricks when loading JavaScript dynamically in the page as well as a server for trying it out. These are available <a href="https://code.google.com/p/c7e3/source/browse/#hg/slowserver">here</a> as open source code. There are some improvements that could be made here. Off the top of my head, the checkWaiting function could eventually time out if a condition continues to not be met. Also the loader could do more to check to see if a requested script has already been loaded. Any more ideas?Jeff Scudderhttp://www.blogger.com/profile/13002167096451875802noreply@blogger.com2tag:blogger.com,1999:blog-33260599.post-79770495076054194972010-03-12T20:26:00.001-08:002010-03-22T21:29:19.715-07:00Quite a View<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_54HtFT6yBFI/S5u6Qa19M3I/AAAAAAAAAfE/ucQ0PV3NJJU/s1600-h/2010-03-09+11.08.21+(1).jpg"><img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 240px; height: 320px;" src="http://4.bp.blogspot.com/_54HtFT6yBFI/S5u6Qa19M3I/AAAAAAAAAfE/ucQ0PV3NJJU/s320/2010-03-09+11.08.21+(1).jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5448152965481050994" /></a>I recently had the privilege of working out of an office near the beach. The sun, the ocean breeze, the pounding of the surf. Laptop makers should really come up with a way to sand-proof these machines.<br /><br />I fully expect that this will draw some inside jokes from a few of you in the <a href="http://webchat.freenode.net/?channels=googleajaxapis">#googleajaxapis IRC channel</a>.Jeff Scudderhttp://www.blogger.com/profile/13002167096451875802noreply@blogger.com0tag:blogger.com,1999:blog-33260599.post-38987837424766468712010-02-08T22:51:00.001-08:002010-03-07T09:49:17.141-08:00New Blog TemplateWith the growing popularity of mobile phones and lower resolution netbooks, a fixed width blog format is looking less and less appealing. I decided to work on a new look for this blog. The main feature I was looking for was a set of CSS rules that would allow the main content to scale with the viewer's browser window width. If the window is too narrow, the less important content on the sidebar should flow down below the main content.<br /><br />I began with an existing theme for Blogger, Tekka, that pushes the right sidebar down beneath the main content when the window is narrow. I then made some CSS changes to tweak the look to fit my tastes.<br /><br />First things first, the default fonts must go! I drew much of my inspiration from <a href="http://blog.notdot.net/">Nick Johnson's blog</a>, specifically the way that serif fonts are used in some places for accent while sans-serif is used for most of the content. This is a technique that I experimented with a bit in a graphic design class in college.<br /><br />For titles I added:<pre>h1, h2 {<br /> ...<br /> font-family: Georgia, 'Times New Roman', Times, serif;<br />}<br /><br />h3 {<br /> ...<br /> font-family: Trebuchet MS, Verdana, Sans-serif;<br />}</pre>To change the font used for the main text in the page, I set a template variable as follows:<pre><Variable name="bodyFont" description="Text Font"<br /> type="font" <br /> default="normal normal 100% 'Lucida Grande', <br /> Verdana, Helvetica, sans-serif" <br /> value="normal normal 100% 'Lucida Grande', <br /> Verdana, Helvetica, sans-serif"></pre>Next I set about changing the style of the title link. You see, when someone is viewing a single post, the blog title becomes a link to the main blog page. So, the blog's title is styled like a link and I found the default link styles a bit jarring. This might seem like a minor change but so often it's the little things that matter. I set this style using<pre>h1 a:visited {<br /> ...<br /> color: #505050;<br />}</pre>Now that the text styling is done, the layout could use a bit of adjustment. I changed the margins on the main content to the following:<pre>#content-wrapper { <br /> margin-top: 20px;<br /> margin-$endSide: 30px;<br /> margin-bottom: 30;<br /> margin-$startSide: 35px;<br /> }</pre>I removed the padding from the <code>h1</code> title style and the date header. I also removed the style rule entirely for the description.<br /><br />We're nearing the end! The sidebar wasn't quite to my liking so I changed the border style. Lastly, in order to get the sidebar to flow down beneath the main content I set a minimum width. Here is the final style for the sidebar:<pre>#sidebar {<br /> text-transform:none;<br /> background-color: $sidebarBgColor;<br /> color: $sidebarTextColor;<br /> padding-$startSide: 20px;<br /> width: 30%;<br /> min-width: 215px;<br /> float: $endSide;<br /> font: $bodyFont;<br /> border-$startSide:1px solid $mainTextColor;<br /> word-wrap: break-word;<br /> overflow: hidden;<br />}</pre>I debated about posting the whole template here, but I'm not sure that it would be very readable. If you would like the whole thing, leave a comment and I can email it to you.Jeff Scudderhttp://www.blogger.com/profile/13002167096451875802noreply@blogger.com1tag:blogger.com,1999:blog-33260599.post-3540909367921183132010-01-13T23:45:00.000-08:002010-02-08T23:06:27.610-08:00DOM Manipulation in JavaScript, a UtilityIn my latest addition to the <a href="http://code.google.com/p/q12/">q12 JavaScript library</a>, I have added a simple function to construct a nested document structure. I grew tired of writing repetitive and difficult to follow code like this <pre>var div = document.createElement('div');<br />div['id'] = 'outer-div';<br />var link = document.createElement('a');<br />link.href = 'http://blog.jeffscudder.com';<br />link.appendChild(document.createTextNode('my blog'));<br />div.appendChild(link);</pre>Using the new tree function this would become:<pre>var div = tree([<br /> 'div', {<br /> id: 'outer-div'}, [<br /> 'a', {<br /> href: 'http://blog.jeffscudder.com'}, [<br /> 'my blog']]]);</pre>In the process of writing this utility function, I came across another small oddity in editing HTML using JavaScript related to the style attribute. Most HTML attributes are simple text properties, however when editing the CSS style of a node, you cannot set the full content of the style attribute. <pre>// You cannot do this:<br />div.style = "color:red; font-weight:bold";</pre>Instead, you set each sub item in the style attribute:<pre>// This works:<br />div.style.color = 'red';<br />div.style['font-weight'] = 'bold';</pre>The tree function that I've written handles this nested style structure as well. Here's an example:<pre>['div', {<br /> 'id': 'foo', <br /> 'style': {'color': 'red', 'font-weight': 'bold'}}, <br /> 'This works too!']</pre>Now that you have an idea of how to use this utility, here's the code. Minus the comments it's only about twenty-one lines.<pre>/**<br /> * Creates a DOM tree from a simple list.<br /> * The structure of the tree passed in is as follows:<br /> * ['elementTag', <br /> * {attribute1: value,<br /> * attribute2: value,<br /> * style: {property1: value,<br /> * property2: value}},<br /> * 'child text node',<br /> * ['elementTag',<br /> * {property: value},<br /> * 'grandchild text node'],<br /> * 'third node']<br /> * The above will result in a DOM node which has three child nodes, the<br /> * first and third will be text nodes because the values were strings.<br /> * The second child node will be a DOM node as well.<br /> *<br /> * @param {Array} t The tree's structure as a collection of strings, lists,<br /> * and simple objects. The structure is as follows<br /> * ['elementTag', {attributes}, child, child, child, ...]<br /> * @return {Element} Returns a new DOM element.<br /> */<br />function tree(t) {<br /> // Create the node using the tag which is first in the list.<br /> var domNode = document.createElement(t[0]);<br /> // Add all HTML attributes to the node.<br /> for (var key in t[1]) {<br /> // The style attributes get special treatment.<br /> if (key == 'style') {<br /> for (var styleAttribute in t[1].style) {<br /> domNode.style[styleAttribute] = t[1].style[styleAttribute];<br /> }<br /> } else {<br /> domNode[key] = t[1][key];<br /> }<br /> }<br /> // Iterate over all child nodes, converting them to either text or HTML<br /> // nodes.<br /> for (var index = 2, child; child = t[index]; index++) {<br /> if (typeof(child) == 'string') {<br /> domNode.appendChild(document.createTextNode(child));<br /> } else {<br /> // Buid recursively.<br /> domNode.appendChild(tree(child));<br /> }<br /> }<br /> return domNode; <br />}</pre>What do you think, is there anything you would add?<br /><br />On a realted note, if you're interested in a more powerful templating system, you might want to try <a href="<br />http://code.google.com/closure/templates/">Closure Templates</a> which were <a href="http://googlecode.blogspot.com/2009/11/introducing-closure-tools.html">recently open sourced</a>.Jeff Scudderhttp://www.blogger.com/profile/13002167096451875802noreply@blogger.com1tag:blogger.com,1999:blog-33260599.post-67823764237782606542009-10-22T16:00:00.000-07:002009-11-09T22:24:53.478-08:00The joys of onKeyDownI recently found myself in need of a way to detect when a user presses enter when typing in a text input box and happened upon one of the <a href="http://www.quirksmode.org/js/keys.html">quirkiest</a> of browser features, key press detection in JavaScript. Searching the Internet provided a few ideas but nothing that quite fit what I was looking for, so I thought maybe I should get the word out about what I've learned.<br /><br />Lets assume that we have a form with an input box and we want to perform some special action when the user presses the enter key while focus is on the text input box. We begin by adding an onKeyDown event to the input box (you might also consider onKeyUp, but onKeyPress seems like it might be somewhat quirkier).<pre><form><br /> <input type="text" id="my-input"><br /></form><br /><div id="output"></div><br /><script><br /> document.getElementById('my-input').onkeydown = function(e) {};<br /><script></pre>Now the first hurdle is that in IE, Safari, and Chrome you can access the ASCII character code for the key which was pressed in <code>window.event.keyCode</code> but in FireFox you'll need to get the event object and look at the <code>which</code> member.<pre><script><br /> document.getElementById('my-input').onkeydown = function(e) {<br /> var keyCode = 0;<br /> if (window && window.event && window.event.keyCode) {<br /> keyCode = window.event.keyCode;<br /> } else if (e && e.which) {<br /> keyCode = e.which;<br /> } else {<br /> alert('fail');<br /> }<br /> document.getElementById('output').innerHTML = 'You pressed ' + keyCode;<br /> };<br /><script></pre>Now there is one gotcha with what we've written so far. Each key that we press when focus is on the desired input causes our code to be run, but the browser also performs the default behavior for that key. If our input is a simple text box, the characters pressed will show up in the text box. If the input is part of a form with a submit button, pressing enter will cause the form to be submitted. If the form is submitted then the browser is sent to a different page which in this case is not what we want.<br /><br />There are a few ways to prevent the key presses from also triggering the default behavior and do only our behavior. One of the simplest ways is to return false from the <code>onKeyDown</code> function. If we change our handler to the below, characters will not show up in a text input box because our handler consumes them.<pre> document.getElementById('my-input').onkeydown = function(e) {<br /> var keyCode = 0;<br /> if (window && window.event && window.event.keyCode) {<br /> keyCode = window.event.keyCode;<br /> } else if (e && e.which) {<br /> keyCode = e.which;<br /> } else {<br /> alert('fail');<br /> }<br /> document.getElementById('output').innerHTML = 'You pressed ' + keyCode;<br /> return false;<br /> };</pre>With the above, the last key press is displayed in the output, but in most cases we probably do want the user to see the chracters they've typed showing up in the input box. We just want to prevent the form submit when the user presses the enter key. To accomplish this behavior, we can return false when we don't want the key press to propoage and return true when the default behavior should also be performed.<pre> document.getElementById('my-input').onkeydown = function(e) {<br /> var keyCode = 0;<br /> if (window && window.event && window.event.keyCode) {<br /> keyCode = window.event.keyCode;<br /> } else if (e && e.which) {<br /> keyCode = e.which;<br /> } else {<br /> alert('fail');<br /> }<br /> document.getElementById('output').innerHTML = 'You pressed ' + keyCode;<br /> if (keyCode == 13) { // 13 is the key code for the enter key.<br /> return false;<br /> } else {<br /> return true;<br /> }<br /> };</pre>There you have it, a way to detect when the enter key is pressed in our input box while also preventing the form from being submitted.Jeff Scudderhttp://www.blogger.com/profile/13002167096451875802noreply@blogger.com3tag:blogger.com,1999:blog-33260599.post-88900032367058863252009-09-28T22:16:00.000-07:002009-09-28T22:37:27.841-07:00JournalingThis evening I found my long lost journal. In dusting it off and cracking it open I learned that my last entry had been over a year ago. With the exception of this last year long hiatus, I've regularly kept a journal since sometime in 1999 or 2000. I've found writing my thoughts helps me crystallize them and I tend to deal with thoughts and emotions internally, mulling them for hours or days. This is one of the reasons I think I've stuck with blogging.<br /><br />Keeping a private journal is a completely different feeling than keeping a blog. When I write here I'm intensely (sometimes even paralyzingly) conscious of my audience. Not that it's a large one. Here I tend to focus on software related discoveries and creations. It is one creative outlet, but one decidedly different from when I journal. <br /><br />It was refreshing to scratch blank pages with pen, writing for an audience which understands me better than most.<br /><br />Okay now how many of you, when you saw the title, thought that I was going to talk about a <a href="http://en.wikipedia.org/wiki/Journaling_file_system">file system</a> or <a href="http://labs.google.com/papers/bigtable-osdi06.pdf">database</a>? :-) How about you, do you keep a private journal?Jeff Scudderhttp://www.blogger.com/profile/13002167096451875802noreply@blogger.com2tag:blogger.com,1999:blog-33260599.post-54222016807823977772009-08-26T23:49:00.000-07:002009-08-27T07:19:25.871-07:00A Matrix Sim in JavaScriptDo you ever find yourself working on a large project with a long lead-in time before you have visible results to show? I had been frustrated by this feeling recently. I had been focusing on a personal project which will likely be a long time in the making, so I decided to pick up a short, simple, and quick project to keep things lively and fresh. So our story begins.<br /><br />During high school, I was wowed by the movie The Matrix. The special effects were mind blowing (for their day) and the story line was something I could really get behind (not so with the sequels, but I digress). I imagine this is how my elders felt when Star Wars was first released.<br /><br />One of the most memorable visuals in the movie is the code of the matrix zipping by vertically on the screen in a retro green on black. Cypher, makes a statement, which seems to be a favorite among programmers, that he no longer sees the code itself, but what it represents. He has become fluent to the point of transcendence - a geek nirvana experience.<br /><br />At this point in my life I had written a few moderately complex programs, mostly using Turbo C, and I thought: "Why, I could make my computer look like the matrix." It was one of the more involved programs I had written at the time and I was quite pleased with the result. I brought it in to the computer lab at school, loaded it onto all of the machines, and had the whole lab running it at once. I'm pretty sure that <a href="http://twitter.com/leebenjp">Ben</a>, Yed, and Roman G. remember it. Sadly I doubt the code would run on the DOS emulator that ships with Windows XP and higher. I recall vaguely that Roman ported it to Win32 or something in our high school computer science class. Now that I think about it, I guess you could say that this was my first open source experience. <br /><br />In thinking of something quick and easy to create with some immediate visual payoff, I decided to recreate my little DOS matrix sim, but this time in the browser. Behold: <a href="http://www.jeffscudder.com/matrix">The matrix in JavaScript</a>.<br /><br /><!--<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.jeffscudder.com/matrix"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 257px;" src="http://4.bp.blogspot.com/_54HtFT6yBFI/SpaT_6DoTHI/AAAAAAAAAcI/gylHk_PxWWI/s320/matrix_sim.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5374645931438787698" /></a>-->It turns out that the CSS rules needed to keep columns at a fixed width and height was actually quite complex and took longer than expected to get right. The vertical line height was still elusive in Chrome and Safari, but worked in Firefox and Opera. I don't think that this works yet in Internet Explorer. Though if past traffic is any indication, none of you would have noticed had I not said something :-)<br /><br />Many thanks to <a href="http://scudmissile.net/">Scudmissile</a> for his mighty CSS kung fu. Oh, and that whirring sound that you hear may be your CPU fan trying to take flight. Apparently rendering a vertical text flow like this using DOM manipulation, CSS, and Math.random may be a bit more processor intensive than my obsolete C code.Jeff Scudderhttp://www.blogger.com/profile/13002167096451875802noreply@blogger.com0tag:blogger.com,1999:blog-33260599.post-45048443841944448212009-08-01T00:38:00.000-07:002009-08-03T07:42:38.877-07:00A Test Client for App EngineI created a <a href="http://code.google.com/p/scud-cms/source/browse/#svn/trunk/app_engine_http">simple utility library</a> in Python to help anyone debug their App Engine application. Many of the App Engine apps that I've seen use HTTP, HTML form posts, and the <a href="http://code.google.com/appengine/docs/python/users/overview.html">Users API</a> and the easiest way to test these features is to fire up the web browser and click through the web pages generated by the app. However this can be a bit slow and repetative and it is difficult to determine exactly what is being sent over the wire (though this is greatly helped by using <a href="http://www.wireshark.org/">wireshark</a>, <a href="http://www.fiddler2.com/fiddler2/">fiddler</a>, <a href="http://www.tcpdump.org/">tcpdump</a>, or antoher network packet sniffing tool).<br /><br />Enter <a href="http://code.google.com/p/scud-cms/source/browse/trunk/app_engine_http/http.py">my little App Engine HTTP module</a>. It provides a simple interface for making arbitrary HTTP requests and will print the full request and response to the terminal (though you can turn the noisy printing off if you want). <a href="http://code.google.com/p/scud-cms/downloads/list">Download</a>, copy the <code>http.py</code> file to you working directory and try it out in your Python interpreter.<br /><br />For our first demonstration, let's try to visit the Google search page. <pre>import http<br />client = http.Client()<br />resp = client.request('GET', 'http://www.google.com')</pre>You should see your request and the server's response (with the HTML for the Google Search page) in your terminal window. This should work with just about any website out there.<br /><br />Other HTTP debugging tools can show you the request and response like this, but I find that this kind of simple Python client can be useful in writing end-to-end or integration tests which contact your App Engine app remotely. <br /><br />Along those lines, one of the things which standard HTTP debugging tools do not provide, is a way to sign in to an App Engine app with a Google Account so that the App Engine Users API can identify the current user. I wrote an extremely simple app which illustrates the Users API, try it out here:<br /><br /><a href="http://jscudtest.appspot.com/user">http://jscudtest.appspot.com/user</a><br /><br />After signing in, the page should simply say, "Hello <em>yourusername</em> (<em>yourusername</em>@<em>yourdomain.com</em>)" You'll notice that during the sign in process, you signed in on <code>www.google.com/accounts</code> and were asked to approve access to the app. This kind of interaction works great in a browser, but can be tricky when you are using a command line, browserless, client.<br /><br />It is possible however, to sign in to an App Engine app without using a browser. You can use the same technique used in <code>appcfg</code>, use <a href="http://code.google.com/apis/accounts/docs/AuthForInstalledApps.html">ClientLogin</a> and use the authorization token to obtain an app specific cookie which indicates the current user. This simple HTTP library can do this for you and all subsequent requests will use this cookie to tell the App Engine app who the current user is. Try it out by making the request to the simple user app that you visited earlier:<pre>import http<br />client = http.Client()<br />client.appengine_login('jscudtest')<br />resp = client.request('GET',<br /> 'http://jscudtest.appspot.com/user')<br />print resp.body</pre>You should see the following text displayed in the terminal:<pre>Hello, <em>yourusername</em> (<em>yourusername</em>@<em>yourdomain.com</em>)</pre>You can use the <code>appengine_login</code> method with your own app, just change the argument to the App ID of the app you want to access. <br /><br />Along with simplifying access to apps which use Google Accounts, I wanted this library to simplify the process of using another feature used by many web apps: HTML form posts. Now I'm certain you've used HTML forms before, here's a simple example: <br /><br /><a href="http://shoutout.appspot.com/">http://shoutout.appspot.com/</a><br /><br />The above app uses both the Users API and a simple form. As an alternative to visiting this page in the web browser, you can post your shout-out using the following:<pre>import http<br />client = http.Client()<br />client.appengine_login('shoutout')<br />client.request('POST', 'http://shoutout.appspot.com/',<br /> form_data={'who': raw_input('From: '),<br /> 'message': raw_input('Message: ')})</pre>If you've even wondered what gets sent across the wire to post on a form like this, look back in your terminal to see the request from your computer and the response from the server (this is of course just the HTTP layer, wireshark will show you traffic on the IP and Ethernet layer as well). <br /><br />That's really all there is to it. I designed this as just a simple script to use on the command line and I wrote it in less time than it's taken me to write this blog post about it (I borrowed <a href="http://code.google.com/p/gdata-python-client/source/browse/trunk/src/atom/http_core.py">atom.http_core</a> from the <a href="http://code.google.com/p/gdata-python-client/">gdata-python-client</a> as a foundation). With some tweaks to remove the interactive (getpass and raw_input) calls and replace them with parameters, I could see this module as a utility layer in a larger, more complex, App Engine client application. If you're creating on I'd love to hear about it ;-)<br /><br />For more information on how the <code>appengine_login</code> method works behind the scenes, see this presentation I gave a few months ago:<br /><br /><iframe src="http://docs.google.com/present/embed?id=dcb4p69x_7fgnfgx28" frameborder="0" width="410" height="342"></iframe><br /><br />Many thanks to <a href="http://twitter.com/tjohns">Trevor Johns</a> and <a href="http://twitter.com/nicksdjohnson">Nick Johnson</a> for helping me to understand how this ClientLogin-to-cookie exchange works.<br /><br />I'm sure that App Engine's Java runtime users would appreciate a port of this simple library to Java, if you feel so inclined.Jeff Scudderhttp://www.blogger.com/profile/13002167096451875802noreply@blogger.com3