Today, my youngest will attend school for the final day. For fifteen years, we have woken them, dressed them, fed them, and helped them get out the door. After today, we are done.
The bittersweet is overwhelming me.
Today, my youngest will attend school for the final day. For fifteen years, we have woken them, dressed them, fed them, and helped them get out the door. After today, we are done.
The bittersweet is overwhelming me.
Twenty five years ago, I was celebrating my 21st birthday with my college roommates. However, I received a call from my dad that abruptly ended the celebration. My cousin and her three young daughters had been murdered by their father; one of them in the arms of her grandmother who was trying to protect her. He had purchased a gun in Seattle and then drove down to Oregon and shot them in their front yard. The oldest had just come home from her first day of kindergarten.
My dad picked me up from my apartment, and we drove down in silence to my great-grandmother’s house. The extended family was gathering to be together and to try and understand what had happened. Twenty five years later and I’m still not sure any of us understand. Can you ever really understand something like that?
Today, an eighteen year old kid murdered twenty-one people in an elementary school, and those memories have flooded back to me. I can remember that night like it was yesterday. As I try to process this horribly tragic event, I am sickened by my emotions. They aren’t the emotions that I should be feeling. I’m not feeling anger; I’m feeling resignation. I’m feeling a disappointment in myself because I cannot muster the outrage that the murder of children should evoke.
I don’t want this to be normal in the world I live in. But I find that anymore I simply feel helpless. I know that deep within I still have intense feelings of anger, but over and over and over and over again that rage runs headlong into the hopelessness. It just hurts too much.
We should be better. But we aren’t.
I’m sorry Sarah, Rachel and April. We keep letting you down.
Ever since the incredibly awful fires/smoke that we encountered in Portland in September of 2020, I’ve been thinking a lot about the environment on a very local level. I fully admit that I was caught off-guard by my first climate related emergency, and I learned quite a bit about air quality terms like AQI. I also discovered some of the various monitoring networks with publicly available data, and sort of developed an itch to participate in some of them. One aspect in particular that surprised me was how awful the air quality inside my home became. I also realized that while the air quality networks could tell me what the outside AQI was, nobody could tell me what it was inside. So, I eventually purchased an Awair Element to put in my office to help me keep an eye on it. Of course, being a tinkerer, I couldn’t help notice that Awair provides an open API for connecting to and monitoring their devices. And so, what would eventually become AirAware was born!
So, after a couple weeks, I had what I felt was a pretty decent reusable framework for iOS to connect to and fetch data from Awair devices. But by then I had an itch. I felt like I had just scratched the surface of what could be done. So after a bit more Googling, I found a number of other devices and networks that allow connecting to their APIs, and I decided to pull them into AirAware as well. In the end, I decided to add support for an initial 5 devices/networks:
There are potentially other devices and networks that I would love to add support for in the future, but for an initial release, I felt like this was sufficient.
Now, I will stop here and say that I love making frameworks and libraries for other developers. I feel good when I make something and can put it out into the universe to potentially help other people. That being said, will anyone find this useful? Will it help anyone? I have no idea, but that’s ok! The point is that AirAware now exists and is available if anyone ever wants to add air monitoring functionality to their app, or if they just want to see a reference implementation for any of the supported devices/networks.
Technical Notes:
Last year, I posted an overview of the tools that Silverpine uses, and I thought it might be interesting to revisit our toolset and compare with where we are versus where we were. Many of the tools continue to be the same, but there are a few changes. Read on for the details!
Communication Tools
Without a doubt, Slack is the single most valuable tool for us as a distributed company. One thing that has changed over the past year, however, is that almost all of our clients have now adopted Slack as well. This has been a great improvement as we can now utilize shared channels between workspaces which greatly reduces clutter and overhead. This has allowed us to stay mostly within the Silverpine Slack workspace which makes everything simpler and cleaner in terms of organization and tracking conversations both internal, and external. If you’re new to Slack, or have yet to try it out, I have a few posts here and here to help you get going.
Looking back to where we were last year, it’s clear that teleconferencing technology and tools have rapidly improved. This is one of the few silver linings of Covid. I’ve never held video conferencing software in very high regard, but I can definitely say that the tools have gone from incredibly awful to “ok”. And to that end, Zoom has definitely moved the quality/easy of use bar further and faster than the competitors. We will see if Zoom can keep the crown in the coming year as Teams and other platforms try to leapfrog it. For now, however, Zoom is the best, easiest to use tool for video conferencing for our business.
Last year, we standardized on Dropbox Pro for file sharing and quite honestly, it’s been so seamless to our workflows that I sometimes forget about it. I’m still surprised that Apple or Google haven’t acquired Dropbox yet, but I have no complaints. It just works.
We use Gmail for our email, and thereby get all of Google Workspace (formerly known as G Suite). I said before that I’m not even sure where I would look to replace the email side of the tools, and that still applies. This past year, however, we have also started using more of the other Workspace tools (Sheets, Docs, etc) but we definitely haven’t standardized. Most of the tools are convenient simply because they are ever-present, but if you need to create a document with a significant amount of formatting, you’ll want to look elsewhere.
Development Tools
We have looked at a few alternatives to Github (like BitBucket) but at this point, GitHub is pretty much the de facto standard for source control systems. I will admit that I was a little nervous when Microsoft acquired them, but quite frankly, their service has improved to the point that we now use them for both source control and for our automated build system through GitHub Actions. Their cost model is also very helpful to us now that it’s seat based rather than project based.
The choice of a git tool can be fairly controversial, and we will never mandate a particular app/tool, but we have found that, overall, Tower is a very good, stable, and constantly improving product. They have versions for both Mac and Windows, and their licensing model makes it easy for us to provide seats to any of our engineers that want to use it. I wouldn’t say that it’s a perfect piece of software, but it’s definitely better than using the command line. We’re not barbarians!
Of all the tools on this list, MantisHub is the one that I’m the least confident that we will still be using a year from now. MantisHub is a fairly inexpensive, hosted, bug tracking system that’s based on the open source Mantis platform. It has replaced Lighthouse which we previously used. We made the decision to replace Lighthouse because it has fallen into abandonware status, and lately hasn’t been able to provide the workflow that we need. I wouldn’t say that I love MantisHub, but it’s not as heavy as Jira and definitely less expensive. We are continually looking to improve our bug tracking system so if you have one that you like, I’d love to hear about it.
Design Tools
Sketch has owned the “non-Photoshop” tool space for years, and it remains the default/standard for our designers. Sketch is a familiar, comfortable, design tool that does what it needs to do. The licensing and cost model work amazingly well for an agency and while I wish that their administrative tools were easier to use when managing seats, it’s not something we have to do often. While we were still a Sketch shop this past year, it’s possible that the winds of change are blowing. We’ve been having internal conversations recently about switching to Figma which has quickly emerged as the cool, new kid on the block. I’ve used Figma a bit and its collaboration tools blow Sketch out of the water (at least at the time of this writing.)
I believe I overlooked our use of Zeplin in my previous tool list. That is a fairly significant oversight on my part! We’ve been using Zeplin for years now and I don’t see that changing any time soon. Zeplin is a very robust tool that engineers and designers can use to easily export image assets out of Sketch (or Figma) and import directly into project workspaces. Zeplin provides that “last mile” in the asset pipeline and supports exporting for web, iOS or Android, each of which have differing format requirements. We love Zeplin!
A critical part of our development process with clients is our prototyping phase. We work extensively with them to help them understand how the UI that we are designing will translate into UX. Particularly when working on mobile platforms, the interface really needs to “feel” right, and InVision is the prototyping tool that we utilize.
Operational/Finance Tools
Like nearly every other small business in the U.S. we use Quickbooks to manage our finances. I don’t have a lot of good things to say other than the fact that our CPA prefers us to use Quickbooks.
Silverpine’s web content is fairly static, and in general our web traffic is very low. I think it’s mostly visited by people who are curious about who we are in the hopes of potentially partnering with us on a project. To that end, we don’t really need much in terms of web hosting, so we use Squarespace. One of the best things I can say about Squarespace is that it is easy to get a decent looking web page up, quickly. They have a plethora of templates and basic customization is very easy. If you start wanting to get fancy, though, it gets incredibly clunky, quickly. It’s also slightly expensive in comparison to some of its competitors. That being said, we’ve been using it for years now without too many complaints.
One new addition/change to our set of tools is that this past year we dropped Blinksale and replaced it with Harvest for invoicing clients. A lot of people use Harvest for time tracking, but it also has a good set of invoicing tools and reports. Both Blinksale and Harvest are good tools and are fairly similar in terms of cost, but Blinksale seems to cater its tools more towards freelancers and less towards agencies. Harvest seems to do a better job of catering to both groups, and it’s made our invoicing processes much easier this past year.
People like to get paid. That seems to be a nearly universal truth, and for us, Gusto is how that happens. We’ve been using Gusto for quite a while now and they have done a fantastic job at continuing to roll out new features and products that really complement their core offering, which is payroll. We use Gusto for both employees and contractors, and I haven’t heard a single issue about it. Gusto does a really good job at tracking taxes and tax reporting for federal, state and most local requirements and many times they will pro-actively alert us about upcoming changes. On top of that, their customer service is very responsive so when we do have questions about things, they get back to us quickly with real answers. Gusto is fantastic.
We received notification today that our trademark on “Silverpine” was registered with the USPTO. We first filed for application back in August, so it’s been a long time coming. While it’s certainly not critical to our business operations, it’s nice to have protection around our brand. I’ll have to get used to writing Silverpine® from now on though.
Disclaimer:
This post comes from my old blog back in 2004. I’m reposting it here so that I don’t lose the content. The source was hand-written HTML so the formatting probably appears a bit off.
About seven years ago I wrote some code to do Mu-Law and A-Law compression. About six years ago, I decided to publish an article along with the source code for it. You can find it here. Anyway, the other day I received an email from someone who had taken it and modified it for what he was doing. In doing so, he found a piece of misinformation that has been in my article since I originally published it. Not a big deal, and I intend to rectify the issue. However, as we chatted over email, I asked him what he was using Mu-Law/A-Law compression for. Here is a clip from our email:
> So if you don’t mind me asking, what are you working on that has 13 bit
> unsigned audio input?
Sure. I am designing a system that monitors lots of radio stations to capture and
detect Emergency Alert System activations – those ugly tones and occasional
voice messages you hear on the radio. The system has some rather incredible
shortcomings for a critical system in 2005. When the emergency management
office triggers an alert they have no way of knowing whether or not radio stations
actually broadcast the alert. Sometimes the system fails – too often. So our
system listens to the stations and sends a report back to Emergency HQ. In
most cases an exception report that shows which stations did not properly
send out the alert. So if the dam is breaking or the nuke is going critical they
can try again, use the phone, send a helicopter or something.
Whoa. Code that I originally wrote to compress audio in children’s games is now being used to help monitor Emergency situations. Talk about your unintended consequences!
-Jon
Disclaimer:
This post comes from my old blog back in 2004. I’m reposting it here so that I don’t lose the content. The source was hand-written HTML so the formatting probably appears a bit off.
No matter how careful of a programmer you are, there will always be times when a hardware exception will occur in your code. Perhaps it was a third party component that was the culprit. Perhaps, it was a fellow co-worker that broke something. Or maybe it was Microsoft itself not playing fair with its documentation and/or implementations. Whatever the case, it is often very useful to be able to capture a run-time exception that was generated by the CPU. Sure, you can use a catch(…) to be your fail-safe, but wouldn’t it be great to be able to convert that exception that was generated by the hardware into a C++ exception? I created this class in order to do that very thing. In fact, this class was the basis for my super assert that I created, because I found that I could cause a hardware exception any time I wanted, and by using this C++ hardware exception container, I could access each thread’s stack frame at run-time. This would eventually enable me to perform a stack trace inside of an assert, but I will explain that more in a different tutorial. Anyway, I hope that this is useful to someone. I spent a while digging around in the mire that is Microsoft’s documentation before I put this together. Perhaps this will save someone else time in the future. Enjoy. -BossHogg #ifndef HARDWARE_EXCEPTION #define HARDWARE_EXCEPTION 1 enum HWExceptionType { eIllegalMemoryAccess = EXCEPTION_ACCESS_VIOLATION, eUnexpectedBreakpoint = EXCEPTION_BREAKPOINT, eDataTypeMisalignment = EXCEPTION_DATATYPE_MISALIGNMENT, eSingleStepInstruction = EXCEPTION_SINGLE_STEP, eArrayBoundsExceeded = EXCEPTION_ARRAY_BOUNDS_EXCEEDED, eDenormalFloat = EXCEPTION_FLT_DENORMAL_OPERAND, eFloatDivideByZero = EXCEPTION_FLT_DIVIDE_BY_ZERO, eFloatInexactResult = EXCEPTION_FLT_INEXACT_RESULT, eFloatInvalidOperation = EXCEPTION_FLT_INVALID_OPERATION, eFloatOverflow = EXCEPTION_FLT_OVERFLOW, eFloatStackCorrupted = EXCEPTION_FLT_STACK_CHECK, eFloatUnderflow = EXCEPTION_FLT_UNDERFLOW, eIntDivideByZero = EXCEPTION_INT_DIVIDE_BY_ZERO, eIntOverflow = EXCEPTION_INT_OVERFLOW, ePrivelegedInstruction = EXCEPTION_PRIV_INSTRUCTION, eUncontinuableException = EXCEPTION_NONCONTINUABLE_EXCEPTION }; class HWException { public: HWException(HWExceptionType aType, EXCEPTION_POINTERS* pExp): itsCategory(aType), itsPointers(pExp), itsLocation(pExp->ExceptionRecord->ExceptionAddress) { } HWExceptionType GetCategory() const {return itsCategory;} DWORD GetLocation() const {return itsLocation;} EXCEPTION_POINTERS* GetSysPointer()const {return itsPointers;} protected: HWExceptionType itsCategory; DWORD itsLocation; EXCEPTION_POINTERS* itsPointers; }; static void HWTranslateException(unsigned int u, EXCEPTION_POINTERS* pExp) { throw HWException((HWExceptionType)u,pExp); } #endif /////////////////////////////////////////////////////////////////////// Example usage: /////////////////////////////////////////////////////////////////////// #include "windows.h" #include "HWException.h" int main() { //Note, setting the exception translator must be done //on a per thread basis. _set_se_translator(HWTranslateException); try { //This will cause an access violation char* ptr = NULL; *ptr = 5; } catch (HWException& e) { //We can now know both the type and the //memory location of the instruction that //caused the exception. Cool! HWExceptionType exceptionType = e.GetCategory(); DWORD address = e.GetLocation(); } catch (...) { //If we got here, then it was some other kind //of C++ exception... } return 0; } |
Disclaimer:
This post comes from my old blog back in 2004. I’m reposting it here so that I don’t lose the content. The source was hand-written HTML so the formatting probably appears a bit off.
CPU Detection Code
I dug this code up from a project that I worked on a long time ago. Unfortunately, it is woefully out of date, especially with any of the latest P4 processors. Also unfortunately, I don’t have a large suite of machines on which to test this, however, I have verified a large number of these, but not all. Also missing from the list are any AMD processors since my old companies didn’t explicitly support AMD. Oh, well. As always, this code is to be used at your own expense, and I guess with this particular set of code, that means a little more. Anyway, I hope someone finds this interesting, and if you have any questions, feel free to ask. -BossHogg
bool QueryCPUID(); bool Is8086() } bool Is80286() } bool Is80386() } bool QueryCPUID() } bool QueryMMX() } bool QueryHyperThreading() } void QueryVendorString(char* string) |