[{"content":"","date":null,"permalink":"https://brandon.dimcheff.com/tags/a2council/","section":"Tags","summary":"","title":"A2council"},{"content":"","date":null,"permalink":"https://brandon.dimcheff.com/authors/","section":"Authors","summary":"","title":"Authors"},{"content":"","date":null,"permalink":"https://brandon.dimcheff.com/authors/danielle-dimcheff/","section":"Authors","summary":"","title":"Danielle Dimcheff"},{"content":"This is a guest post by my ex-wife, Danielle. If you\u0026rsquo;d like more Ann Arbor City Council content, you should check out the a2council tag here.\nI moved with my parents to Ann Arbor in the mid-80s when I was just three years old. I attended Northside, King, Clague, Huron, and U-M. I have been a U-M employee for the past 17 years. Several years after college, I married my high school boyfriend who had bought a house in ward 4—the same house we live in together today. I guess you could say these are my townie credentials. I mention them because they inform how I saw—and now see—this great little city of ours.\nHere’s my confession: I was a NIMBY1. Not on purpose. I had never even heard the term until a couple of years ago. But, I was one.\nI liked Ann Arbor how it was because, you know, it was the Ann Arbor I had grown up in. I didn’t want new buildings or roads. Even as a teenager planning to go to U-M, I didn’t like move-in week or football traffic. Yes, I was cranky beyond my years, but the point is that I was resistant to change and only thinking of my own immediate convenience.\nI barely thought about my NIMBY-ism. I was busy with my life and would occasionally just remark “ugh, another luxury apartment building for students going up on campus” or “I hate traffic, I hate parking” or “tearing down old things is a shame.”\nWhen my husband was adamantly opposed to a ballot proposal to make a small (unfunded) park in downtown Ann Arbor instead of the multi-use building for which the space was intended, I didn’t get it. I said something like, “more people would mean more traffic.” And that was the first time anyone pushed me to think about whether I was being consistent with my own values—and whether I actually understood the consequences of my simplistic and reactionary opinions.\nIf you had asked me at any point, “Do you think people of all income levels, ages, and abilities should be able to live and thrive in Ann Arbor?” I would have said, “yes, of course I do!”\nIf you had asked me, “Do you really think a community that never progresses can somehow stay wonderful?” I would have said, “no, of course not.”\nAnd if you had asked me if I knew the first thing about how market-rate and subsidized housing, land use, transportation, and climate change were all intertwined and the unanticipated consequences of my NIMBY reflexes, I would have said—and did say—“I have no idea.”\nOnce I started to learn, started to talk to knowledgeable urban planners, started to think not only of the Ann Arbor I knew but the Ann Arbor I could know in the future, I let go of nostalgia, selfishness, and knee-jerk reactions. I asked better questions about the real impact of housing and transportation decisions. I became more grateful that this world-class university that gave me a great education and a fulfilling career continues to flourish in my backyard. I stopped thinking about what I’d lose and started thinking about what all of us could gain.\nHere are some of the ways I reconsidered my stance:\nI will never again take the university for granted. Sure, there are a lot of students and people coming to work every day, but on the other hand, there are a lot of students and people coming to work every day! That’s a great thing. U-M fills this city with interesting, diverse, brilliant people and lands opportunity right on our doorstep. Sometimes it will be an inconvenience (like on 8 Saturdays each fall) but the jobs, arts and culture, and medical care accessible to us more than outweigh any inconveniences. The students need someplace to live, and large apartment buildings right on campus are exactly where they should live. Build up, not out, so that students are close to everything they need and surrounding areas can remain permanent resident neighborhoods. And we can employ “gentle density” principles in our neighborhoods, like allowing townhouses, duplexes, and mixed-use buildings; one thing that excites me about “gentle density” is that it leads to vibrant, practical communities in which there are more shops, restaurants, services, and workplaces located in proximity to people’s homes (think of Kerrytown as an example). Everyone wants great stuff but very few people want higher taxes, which means we need to grow our tax base with new residents. Also, it is impractical to think that we can build enough low-income or publicly-owned housing to have that be our only strategy out of this housing crunch. For these reasons, I changed my mind about new development projects in the city. Not everything that is built is going to be exactly what I would have designed, but if it safely houses more people it’s a win. I live close to an apartment complex that took a long time to build, called The George. Sentiment about this building is divided but did you see what was there before? It was an abandoned strip mall on a brownfield. Now people live there and there’s a dog park and a playground. It’s on a bus route. What more could I ask for? Sure, my favorite urban architecture is Haussmann-style Paris but it doesn\u0026rsquo;t have to be my favorite architecture ever to still be an improvement. (Historical sidenote: Paris had a lot of NIMBYs in the 1800s with one legislator saying, “We weep with our eyes full of tears for the old Paris, the Paris of Voltaire, of Desmoulins, the Paris of 1830 and 1848, when we see the grand and intolerable new buildings, the costly confusion, the triumphant vulgarity, the awful materialism, that we are going to pass on to our descendants.”) More housing does not necessarily mean more cars, particularly when we build on transportation corridors. Many more people come in to the city for work each day than leave it. If there were available housing, many people would choose to live closer to their places of work. Additionally, we need to keep building infrastructure for safe biking and walking—in addition to supporting public transportation—so that these are viable methods of travel. If you’re ready to hold a mirror up to your own inner NIMBY, I want to encourage you to do it! There are tons of patient, knowledgeable, nonjudgmental people who can help you think about what Ann Arbor needs to do to grow sustainably. They will fill you with optimism for the future of our city and you will be able to see how living your values can manifest the kind of city we can all love.\nTo start, this August, join me in voting in favor of the bus millage and supporting these great candidates to lead our city: Mayor Taylor, Cynthia Harrison (Ward 1), Chris Watson (Ward 2), Ayesha Ghazi Edwin (Ward 3), Dharma Akmon (Ward 4), and Jenn Cornell (Ward 5).\nNIMBY stands for \u0026ldquo;Not In My Back Yard\u0026rdquo;. According to Oxford, a NIMBY is a person who objects to the siting of something perceived as unpleasant or hazardous in the area where they live, especially while raising no such objections to similar developments elsewhere.\u0026#160;\u0026#x21a9;\u0026#xfe0e;\n","date":"23 July 2022","permalink":"https://brandon.dimcheff.com/2022/07/how-i-stopped-being-an-incidental-nimby-and-started-living-my-values/","section":"Posts","summary":"I was a NIMBY. Not on purpose. I had never even heard the term until a couple of years ago. But, I was one. Here\u0026rsquo;s the story of how I changed my mind.","title":"How I stopped being an incidental NIMBY and started living my values"},{"content":"","date":null,"permalink":"https://brandon.dimcheff.com/tags/","section":"Tags","summary":"","title":"Tags"},{"content":"","date":null,"permalink":"https://brandon.dimcheff.com/categories/a2council/","section":"Categories","summary":"","title":"A2council"},{"content":"This is a statement that I read aloud at Council on Monday, July 18, 2022 announcing\nI\u0026rsquo;m here to announce a new community project to provide more accessible information about the actions of council. It\u0026rsquo;s available now at a2council.vote. Many recognize that Legistar is difficult to navigate, and it\u0026rsquo;s impossible to see a summary of the votes that took place at a council meeting. In fact, Councilmember Nelson has been providing summary information and voting charts for some time, but I think there are two problems with a sitting Councilmember being the provider of this service. First: being a Councilmember is not a permanent position, and at some point Councilmember Nelson will no longer be on council. This sort of service should outlive the term of any single councilmember. Second: even though the voting charts and reproduced agendas are factual, they serve as a funnel into the rest of her website, which is filled with propaganda, misinformation, and outright lies.\nFor instance, while attempting to look up the votes for a particular meeting, you might also be presented with such misinformation as:\ninsinuations of impropriety directed at a member of city staff, which she has been unwilling to retract even after being told that those insinuations are untrue and harmful to the staff member. justifications of her \u0026ldquo;no\u0026rdquo; vote on censuring councilmember Hayner for using racial slurs, saying that he merely had \u0026ldquo;used the phonetic sounds without euphemism\u0026rdquo;. Furthermore, she claims that she had received no communications about Hayner\u0026rsquo;s words being harmful, despite there being ample proof that she did. suggestions that her council colleagues might have been bribed since someone tried to bribe her, which was apparently alarming enough to use for propaganda purposes, but not alarming enough to actually report to the authorities insinuations that her opponent is participating in an illegal texting operation1, including instructions on how to report the texts to the FCC. (If this is truly illegal then you might as well report Governor Whitmer, Debbie Dingell, Planned Parenthood, and literally every other Democrat because wow do I get a lot of texts from campaigns) and she\u0026rsquo;s also made suggestions that if she loses her upcoming election, it\u0026rsquo;ll be because it was \u0026ldquo;bought\u0026rdquo;, and that voters are so uninformed and easily manipulated that the loss won\u0026rsquo;t be her fault. We don\u0026rsquo;t find it acceptable that people have to wade through that nonsense in order to access basic data on council actions. In an ideal world, the city would provide this information in a neutral, clear, easy to digest format. Unfortunately it doesn\u0026rsquo;t. Our intent is to fill that gap, giving people access to information about the workings of council without including propaganda. This will be open source, and anyone is welcome to contribute. I hope the city will take it over one day.\nYou can visit a2council.vote to see the voting chart, and just the voting chart, for tonight\u0026rsquo;s meeting. Expect to see more in the future; we\u0026rsquo;re just getting started! My contact information is on the site if you\u0026rsquo;d like more information or to get involved.\nIn a TikTok, Nelson accuses a different CM of buying an election, and claims her husband says texting is \u0026ldquo;fishy\u0026rdquo;. She later included this passage in a newsletter that implied they were illegal and told people how to report the texts to the FCC.\u0026#160;\u0026#x21a9;\u0026#xfe0e;\n","date":"17 July 2022","permalink":"https://brandon.dimcheff.com/2022/07/a2council.vote/","section":"Posts","summary":"\u003cp\u003eThis is a statement that I read aloud at Council on Monday, July 18, 2022 announcing\u003c/p\u003e\n\u003cp\u003eI\u0026rsquo;m here to announce a new community project to provide more accessible information about the actions of council. It\u0026rsquo;s available now at \u003ca href=\"https://a2council.vote\" target=\"_blank\" rel=\"noreferrer\"\u003ea2council.vote\u003c/a\u003e. Many recognize that Legistar is difficult to navigate, and it\u0026rsquo;s impossible to see a summary of the votes that took place at a council meeting. In fact, Councilmember Nelson has been providing summary information and voting charts for some time, but I think there are two problems with a sitting Councilmember being the provider of this service. First: being a Councilmember is not a permanent position, and at some point Councilmember Nelson will no longer be on council. This sort of service should outlive the term of any single councilmember. Second: even though the voting charts and reproduced agendas are factual, they serve as a funnel into the rest of her website, which is filled with propaganda, misinformation, and outright lies.\u003c/p\u003e","title":"a2council.vote"},{"content":"","date":null,"permalink":"https://brandon.dimcheff.com/authors/brandon-dimcheff/","section":"Authors","summary":"","title":"Brandon Dimcheff"},{"content":"","date":null,"permalink":"https://brandon.dimcheff.com/categories/","section":"Categories","summary":"","title":"Categories"},{"content":"A neighbor wrote this response to Kim Winnick\u0026rsquo;s endorsement of Anne Bannister. It\u0026rsquo;s mostly been circulating on Facebook but I\u0026rsquo;ve reproduced it here so that people without an account can view it more easily.\nIf you want to read my writing on the upcoming election, I suggest my endorsements post, and for a little fun, I wrote about conspiracy theories plaguing local politics.\nI’m a neighbor of yours, just around the corner on Minerva Road. Burns Park friends of ours saw your recent letter about why you’re voting for Anne Bannister for mayor in the coming August Primary, and were bothered by inaccuracies and falsehoods in the letter. They forwarded it to me, and I’d like to point out some issues that should give you pause to re-think. You’re an engineer, and I’m a technical translator and interpreter for leading German and Swiss power generation and energy engineering firms. We both deal with in-depth physical facts that demand thorough verification. The same rule should apply to the public policy-making you back. So please consider the following – and you’re welcome to a friendly beer on our front porch to discuss these matters.\nFirstly, when still on City Council, Anne Bannister and her faction conspired to and then fired our highly popular, world-class City Manager Howard Lazarus for no reason other than he wanted to prepare a budget according to standing Council policy. Lazarus was implementing the legislation in force. Bannister wanted him to bend to the wishes of her faction, although we all learned in 8th Grade Civics Class that Council has to negotiate, approve and adopt legislation before it is implemented by city administration. They couldn’t force him to cut approved funding for climate action and pedestrian safety: so they fired him, at great financial cost to the city, and to this city’s national reputation. This was a major fiasco noted nationally.\nSecondly, you perpetuate the lie that Mayor Christopher Taylor is pushing “rapid…virtually unrestricted growth in a crude, unsophisticated manner”, that he is somehow a pied piper bringing hordes of outsiders to Ann Arbor. Are you not aware of how low Ann Arbor’s growth rate is? In the last 20 years, the city’s population has grown by 8.5% – well below 1% per year. It’s not about population growth: it’s about where and how people live within the city limits. Not everyone can live in a single-family home in Burns Park, and many people nowadays no longer want a house in faraway suburbs. And – fully contrary to your statement – it is NOT higher density housing within the city that creates more traffic, but rather flat suburban sprawl. Traffic congestion on Washtenaw Avenue, Plymouth Road and I-94 is in part the direct result of not in my backyard.\nI lived and worked 28 years in tight urban environments in Europe, and I can assure you that Mayor Taylor is pursuing a balanced, nuanced combination of densifying while also conserving the city’s beloved character. He and City Council have no say in University of Michigan student body numbers, and must adapt to and accommodate such change. University of Michigan strategic and financial policy-making pays faculty and staff salaries, ensures retirement benefits, and implements Michigan’s now highly lauded financial support for low-income students. The student body numbers directly reflect the university’s needs and goals. So if you have an issue with student body growth and its impacts on Ann Arbor, you need to take it up with your former employer.\nThirdly, you perpetuate the nonsensical, sophomoric, black-and-white type-labels of “defenders/protectors” versus “disrupters/strivers” that have no basis in fact. With every vote, every action, each and every one of us plays all four of these roles simultaneously. It’s basic physics: change happens, no matter what. Not in my backyard means change happens where you can’t steer it – and then it comes back with a vengeance to haunt you.\nRegarding the numbered bullet points in your letter:\nRoads: Yup, the roads need improving – as they do all across the United States. You saw the extensive roadworks all last summer all across the city, with even more ongoing right now. Older maintenance schedules don’t work under the massively increased stress loads created by heavier trucks, 4-wheel-drive SUVs, higher numbers of vehicles and trips, and – you should know as an engineer – improved tire technology: today’s tire-grip rips up roads 4 times as fast as in the 1970s. So, how much more are you and Anne Bannister willing to pay in property taxes to fix the roads? The City Council members are not suing each other. Actually, it was Anne Bannister who sued the city over the Library Lot and pretextually over the manner of contracting practice that has occurred multiple times every year since the 1950s (on contracts including the purchase of Gallup Park), and many times later during her tenure on Council. She dropped the case, of course, but the case remains a huge blemish. The lawsuit over water and sewer rates is NOT likely to succeed. It was already dismissed once, and the lawyer has tried another tactic. City rates are meticulously calculated by water management professionals – not by the Mayor. I strongly suggest you put yourself into a wheelchair and experience taking the train from our current train station to Chicago. If you want to reduce the daily commuter road traffic coming to your employer University of Michigan, then public transportation by train is the answer. Your fleet of engineering instructors at the U of M can’t afford to live in Burns Park, many having to commute e.g. from Ypsilanti. The commuter stops in Ypsi-DepotTown and the new station at the Michigan Medicine complex would revolutionize commuting for U of M faculty, instructors and staff. Anne Bannister wants to curb development by protecting “mature trees.” We already have protection for “landmark trees” that have been identified by experts on city staff – the same experts who identify and remove diseased trees from our streets, protecting our houses. The unintended and un-thought-out consequences of what she proposes would mean that if you want to add a deck to your house, and that would destroy a “mature tree,” you would not get a permit to do it. The State Street reconstruction at the DIAG is about to be implemented. Long in the planning, it will create an amazing space. The issue of littering by students is an eternal, universal one. Ask the people now benefiting from affordable housing in Ann Arbor if it makes a difference to them. Yes, Kerrytown is a wonderful area to shop and stroll through, as are other low-rise old-brick districts in Ann Arbor. But these areas are not less “super-expensive” to live or operate a business in – rather, the opposite. Many of those cooks and waitresses serving you in these quaint little shops, cafes and restaurants have to commute from afar to find affordable housing. If you want a cross-section of the workforce there to serve you, then there has to be some density. The city is pursuing the Gelman plume issue as hard as it can, and more. Anne Bannister should have thought of this when she fired City Administrator Howard Lazarus who, as an expert-engineer with technical experience in this very field, was working overtime to seek resolution. Bannister and her allies nearly derailed the case in state court. Now that the case is in stasis after the judge issued his order for more cleanup and monitor wells, the City is moving forward asking EPA’s help. EPA is not a silver bullet here. Even if they take the case, a plan and cleanup will take decades. Also, they usually decline to intervene when there is a known polluter and a State authority engaged in the cleanup. EPA is a long-shot at best. Today’s plume is a long-term problem that arises as a result of Governor Engler’s gutting of Michigan pollution laws back pre-2000. The development at Lowertown was planned and zoned by a previous developer. It was not practical in 2006, when passed, and even more impractical in 2018 when re-zoned. It was never going to be built – a mirage. We’re in a housing crisis and Council re-zoned to permit housing and to effect much needed environmental cleanup near the river. That’s what happened in Lowertown. Some residents sued and lost. Lastly, I and another neighbor on Minerva Road – Owen Jansson – worked for two years on Ann Arbor’s Pedestrian Safety and Access Task Force to research and define recommendations to improve walkability and bikeability in Ann Arbor, which I’m sure you appreciate as a cyclist. The protected cycle highways in downtown Ann Arbor are a direct result of our work. Anne Bannister convinced her colleagues, who were then defeated in the last election, to turn down state money to build a sidewalk to Northside School. As a result, the state will no longer work with the city and we are barred for a number of years from future Safe Routes To School grants. Our daughter walked and cycled to Burns Park Elementary, Tappan Middle School, and Pioneer High School. For me, anyone like Anne Bannister who blocks funding for sidewalks and crosswalks to schools has no place in our city government.\nAgain, I’d welcome any chance to discuss these issues with you, and you should not take this response to your letter as a personal attack. This is a neighborly response to get the facts right.\nBest regards,\nTony Pinnell\n","date":"9 July 2022","permalink":"https://brandon.dimcheff.com/2022/07/open-letter-to-a-burns-park-neighbor/","section":"Posts","summary":"\u003cp\u003eA neighbor wrote this response to \u003ca href=\"https://www.bannister4mayor.com/kim-winick-letter\" target=\"_blank\" rel=\"noreferrer\"\u003eKim Winnick\u0026rsquo;s\u003c/a\u003e endorsement of Anne Bannister. It\u0026rsquo;s mostly been circulating on \u003ca href=\"https://www.facebook.com/joan.lowenstein/posts/pfbid02gZNXvnwX9sG72LtNt4dQrePb9oD8Zi4Xen3iKibkxefyVdTN7V28eaYbuWSDRkRAl\" target=\"_blank\" rel=\"noreferrer\"\u003eFacebook\u003c/a\u003e but I\u0026rsquo;ve reproduced it here so that people without an account can view it more easily.\u003c/p\u003e","title":"Open Letter to a Burns Park Neighbor"},{"content":"","date":null,"permalink":"https://brandon.dimcheff.com/tags/politics/","section":"Tags","summary":"","title":"Politics"},{"content":"","date":null,"permalink":"https://brandon.dimcheff.com/authors/tony-pinnell/","section":"Authors","summary":"","title":"Tony Pinnell"},{"content":"Two years ago, I wrote a post describing a vision for the future of Ann Arbor. It\u0026rsquo;s two years later, election season, and time to check in on our progress.\nRecap #To save you from reading my previous post, my point was effectively that Ann Arbor has a housing shortage and we need to do something about it. On this point, I honestly think there is broad consensus in our community—I have heard very few people express the belief that it\u0026rsquo;s easy to find good housing at a reasonable price. I asked you to vote for those who would most effectively work to solve our housing problem\u0026hellip; and you did! We\u0026rsquo;re in far better hands now than we were two years ago. But we\u0026rsquo;re just getting started. It takes time to build housing and to see the positive effects of policy changes, and while we\u0026rsquo;ve made progress and started applying force in the right direction, there are still many roadblocks to overcome—from simple inertia to active opposition and, of course, increasing construction costs. I am asking you to say \u0026ldquo;yes, and\u0026rdquo; to what we\u0026rsquo;ve accomplished over the last two years, and to vote for good governance and a better future for the city. Please vote to reelect Mayor Taylor, and vote for Cynthia Harrison (Ward 1), Chris Watson (Ward 2), Ayesha Ghazi Edwin (Ward 3), Dharma Akmon (Ward 4), or Jenn Cornell (Ward 5).\nI have adopted the use of \u0026ldquo;progressive\u0026rdquo; and \u0026ldquo;conservative\u0026rdquo; to describe the factions, as in the Damn Arbor Endorsements as I think those are reasonable enough monikers as described in the linked post, and we might as well use a common vocabulary. Good Governance #I know there\u0026rsquo;s been turnover recently at city hall, some of which I discuss in my post about conspiracy theories popular in certain corners of town. While it may be your natural instinct to blame incumbents, I absolutely believe that Mayor Taylor in particular has been a stabilizing force during these tumultuous times. When there were credible allegations of a toxic work environment at city hall, Taylor ordered an investigation. When that investigation revealed that there was, in fact, a problem, Taylor and the progressives on council acted to solve the problem, despite extreme vitriol and attacks from the conservative faction—from the same folks who had hired this city administrator after firing the previous one without cause and without public explanation.\nCity employees asked for help. Mayor Taylor had their backs. Punishing him for doing the right thing is absolutely not the message that we want to send. We should reelect him and show city employees that we, too, have their backs. We should also decline to reelect the conservatives—Bannister, Nelson, and Ramlawi in this election—who spent an enormous amount of time and energy trying to save a flawed city administrator from accountability after creating the problem in the first place. In the end, Mayor Taylor and the progressives were able to hire a great city administrator in Milton Dohoney, and I am confident the city is in good hands.\nThere was another investigation of allegations raised by an employee, which, in the end, exonerated the person accused of wrongdoing. However, the investigator reported that Nelson and Ramlawi interfered in that investigation1 by revealing information from a closed session of council, while the investigation was in progress. This would likely be a fireable offense at work, and is not something that we should tolerate from our elected officials:\nI was also troubled to learn during the course of this investigation that two members of City Council [later revealed to be Nelson and Ramlawi, by their admission] reached out to and met with Mr. Guajardo soon after he filed his complaint against Mr. Fournier. During that meeting, Council members disclosed to Mr. Guajardo some of what transpired in a closed-session Council meeting the evening prior—specifically, discussions related to legal advice being given to Council by the City Attorney’s office regarding whether John Fournier should be placed on administrative leave during the pendency of the investigation. Not only did Council members potentially disclose privileged and confidential communications from the closed session with this communication, but they did so to an employee whose complaint against another high-level City employee was the subject of a pending outside investigation.\nUnlike the conservative faction, Mayor Taylor and the progressives have acquitted themselves well throughout these difficult times. In each alleged instance, they immediately ordered an independent investigation, treated the complainants with respect, saw the investigation through, and acted on the results. This is what I expect and demand from our elected officials.\nProgress #As I mentioned earlier, there is a lot of work left to do, in many areas. Housing costs are still rising, and while that\u0026rsquo;s certainly not a problem unique to Ann Arbor, we must do our part to help. Ann Arbor is not actually growing that fast, and the housing we have built hasn\u0026rsquo;t kept up with the rising demand due to additional students and jobs. Eighty thousand2 people commute into the city every day—burning gas and increasing traffic—many of them because they can\u0026rsquo;t find affordable housing in town. Anne Bannister suggested recently that we might ask the University to send jobs and students to the Flint campus, instead of allowing for more friends and neighbors to live in Ann Arbor. We should live up to our reputation as a welcoming community, not put up a sign that says \u0026ldquo;Ann Arbor is full\u0026rdquo;.\nIn order to house more people, we need a holistic approach. Only building subsidized housing for low-income folks won\u0026rsquo;t work, as many folks won\u0026rsquo;t qualify for subsidized housing but still need an affordable place to live. We must build housing of all types, and enough of each kind that housing demand doesn\u0026rsquo;t force people out of their homes due to rising rent. We\u0026rsquo;re also nearly out of undeveloped land, so the only way we can add more housing within the city is to increase density. But it doesn\u0026rsquo;t have to be scary! We can use gentle density to house more neighbors in our existing neighborhoods without making \u0026ldquo;skyscrapers\u0026rdquo; everywhere, and we can build apartments and condos in areas that are appropriate for those sorts of developments. \u0026ldquo;Yes, and.\u0026rdquo; Dharma Akmon discusses this a bit in this interview and I think it\u0026rsquo;s spot on. This is the kind of thinking we need on council: work collaboratively to come up with the best solutions, don\u0026rsquo;t just point out problems and block progress. All of the progressive candidates recognize that housing is one of our most important issues, and I\u0026rsquo;m confident that all of them will work creatively to solve the crisis.\nCouncil and the community recognizes that market-rate housing will not work for everyone. Luckily council has made a ton of progress on subsidized, guaranteed-affordable housing in the last couple years. There are now five projects that include subsidized housing in various stages to be constructed on city lots. We should break ground on some of them soon, as their designs near completion. They will guarantee affordable rent to income restricted individuals and families that make under a certain percentile of the Area Median Income. City-owned properties are the only way we can do rent control in Ann Arbor, as the State prohibits us imposing rent control on private landlords. This must be part of our housing strategy, and it is.\nBut just as market-rate housing won\u0026rsquo;t work for everyone, it must also be part of the solution to the housing crisis. Nearly everyone reading this lives in market-rate housing, and there is no way that is going to change in the near future. Most middle-class families won\u0026rsquo;t qualify for housing subsidies, but they still need to be able to afford a place to live. Plus, thousands of high income people move into Ann Arbor every year; we can either allow new apartments and condos to be built for them, or else they will just buy up the housing stock that’s already here—there is no legal way to prevent it. The evidence shows that building new housing, even when it\u0026rsquo;s relatively expensive, stabilizes nearby prices.\nOne way to address housing affordability that I\u0026rsquo;m particularly excited about is the new TC-1 zoning that the Mayor and the progressive majority have recently started applying to parts of the city. It will allow us to build more walkable mixed-use buildings along transit corridors like down by Briarwood, out on West Stadium, and maybe Plymouth, Washtenaw, and Packard/Platt one day. The idea is to turn a bunch of strip malls, drive-thrus, and offices with huge asphalt parking lots into walkable stores and homes for people. I live near York and Anthony\u0026rsquo;s off of Packard, and I really like living in a place where I can walk to a few places like that. I would love more, and I would love if more people could live nearby as well. The mixed-use nature of TC-1 means that many folks will be able to avoid using a car in a car heavy area of the city, which will reduce traffic and help us meet our climate goals in addition to providing much-needed housing. Win-win.\nThe city has been working on TC-1 for at least 5 years (over a decade if you count from when it was mentioned in our last comprehensive land use plan) but it was delayed via a vote by the previous council that had Bannister, Nelson, and Ramlawi in the majority. I am excited that we\u0026rsquo;re finally applying this zoning to parts of town, and I\u0026rsquo;m concerned that if we elect Bannister in particular, her veto pen will slam on the brakes and we\u0026rsquo;ll end up falling even further behind on something pretty exciting. As of my writing this, three of her five endorsements listed on her campaign website are people thanking her for blocking housing projects. In fact, Bannister\u0026rsquo;s claim to fame is blocking the construction of housing on top of an underground parking structure in order to build a park. Four years later, it remains a surface parking lot. We should instead choose candidates that will use every avenue to solve our housing problem.\nValues #A friend of mine is fond of saying \u0026ldquo;budgets are a moral document\u0026rdquo;. Ann Arbor can claim to be the most enlightened, welcoming, liberal city in the world, but if we\u0026rsquo;re unwilling to expend any resources on our values, it\u0026rsquo;s all worthless talk. Thankfully, we\u0026rsquo;ve actually been able to commit some resources to address climate change, workers\u0026rsquo; rights, equity, and the like, despite attempts by the conservative faction to underfund or water down these initiatives. Our A2Zero carbon neutrality plan is good, and while the plan was successfully weakened during the previous conservative-controlled council of 2018-2020, we\u0026rsquo;ve made good progress towards achieving the remaining goals. In keeping with a pre-election promise, Taylor used his veto pen multiple times to prevent climate funding from being reallocated to other projects by the conservative faction. We need to commit to climate action, and the Taylor has shown that commitment. Jenn Cornell is a volunteer for A2Zero and a board member of the Ecology Center, and her expertise in those areas will be a great asset on council.\nWe\u0026rsquo;ve also made progress (including ever-critical funding) towards having an unarmed responder program that can respond to people in crisis without having the police show up with a gun. Several other cities have seen success with programs like this, providing better service to people in crisis, and relieving the police from having to respond to situations that are better served by mental health professionals. Cynthia Harrison is currently on the Independent Police Oversight Commission, and Ayesha Ghazi Edwin is chair of the Human Rights Commission, and their expertise and experience will be invaluable to have on council as we develop this program.\nVoters also recently overwhelmingly passed a charter amendment to allow us to choose contractors based on holistic value instead of mandating the city to choose lowest bidder. Lowest bidder policies have lead to shoddy work, often by allowing non-union shops from far away to come in and undercut higher-quality union labor. We can also make sure bidders are treating their employees well, and have good safety and quality records. In the long run, choosing higher-quality contractors should save us money. Mayor Taylor has been a champion of these changes, while Ramlawi in particular seems only concerned with the price tag of the project, regardless of whether there are serious issues with the lowest bidder. Last month he almost blew up a $4M road contract in order to posture about his fiscal conservatism, and eventually angrily took off his mask, held his nose and voted yes after Taylor pointed out that a \u0026ldquo;no\u0026rdquo; vote would have delayed that project for an entire year. At that point even the lowest bidder would have cost more, due to rising construction costs. The voters clearly want us to choose better contractors. It\u0026rsquo;s good for the workers, and it\u0026rsquo;s good for the city. Let\u0026rsquo;s elect folks who will uphold the will of the voters.\nSafety #Roads #43,000 people died in traffic crashes in the US last year. We kill or severely injure around two dozen people every year in Ann Arbor. That is absolutely unacceptable, and it\u0026rsquo;s avoidable. I want to be able to ride my bike, walk, and, yes, drive around town without being worried that I\u0026rsquo;m going to be hit by a two-ton machine. In order for that to happen, and for us to meet our Vision Zero goals of no severe injuries or deaths on our roadways, we need to be aggressive about making safety improvements. All of those traffic deaths are a policy choice, and we know how to fix it! There\u0026rsquo;s nothing unique about Ann Arbor that doesn\u0026rsquo;t apply to every other city that has successfully reduced traffic violence. We need people on council who will actually vote for safety, instead of merely saying that they are \u0026ldquo;safety advocates\u0026rdquo; but voting against common sense safety improvements.\nTen years ago, as a motorist, I used to hate a lot of the safety improvements that the city was making. \u0026ldquo;They\u0026rsquo;ll slow me down! Traffic is already bad!\u0026rdquo; Well, after seeing several successful road diets—remember when Packard was four lanes near downtown??—I\u0026rsquo;ve learned my lesson. I love them, even (maybe especially) as a driver. I hate driving on four-lane roads without turn lanes, dodging turning drivers who often don\u0026rsquo;t signal. It\u0026rsquo;s stressful and dangerous. The numbers prove this: crashes are reduced up to 50%, speeding is way down, and there is a negligible effect on travel times. I\u0026rsquo;ll take that any day.\nDuring the 2018-2020 conservative control of council, CMs Ramlawi, Bannister, and Nelson passed a resolution to make safety-increasing road configurations require extra process and approval by council. This is the exact opposite to the approach that we should take: we should have to instead justify, with data, why we should not be improving safety by default, with every project. Instead, the conservative councilmembers structurally prioritized the status quo over the safety of road users. Then, after passing this resolution, they voted against specific projects that would have decreased speeding and improved safety in the vicinity of King Elementary and Greenhills, among others. If we cannot support safe roads next to two schools, what are we even doing here?\nEarhart Safety Improvement Estimates on a project rejected by Bannister, Nelson, and Ramlawi Sidewalks #There are 144 miles of roads with missing sidewalks in the city. By (good!) council policy, we\u0026rsquo;ve committed to closing those sidewalk gaps, but it will take time. The prioritization algorithm that the city uses to determine the next project is sometimes imperfect, but it favors sidewalks near schools, parks, and other places where pedestrian access is particularly important. The bottom line is that, barring a policy change that I would strongly oppose, it\u0026rsquo;s not a matter of if a sidewalk will be constructed, but when. Prioritization discussions are reasonable before a project is ready to go, but blocking a viable sidewalk project is not.\nMayor Taylor and the progressives have all consistently supported these valuable sidewalk projects, whereas Bannister and the conservatives have carved out exceptions and crumbled at the first sign of a complaint from a nearby homeowner. In 2019, during the conservative majority, they voted against installing sidewalks to an elementary school, and turned down a $400k grant in the process.\nBannister is proud of resisting change, despite the high cost to safety and the housing crisis. In her own words, from an MLive interview:\n“During my time on council, I saw a lot of unhappy neighborhoods where people were having to hire lawyers and put their lives on hold to protect the community and try and make sure that we collectively did the right thing,” Bannister said, referring to instances when neighbors opposed new development or paying for new neighborhood sidewalks.\nWe need leaders who are committed to ensuring our kids have a safe way to get to school. Keeping kids from having to walk in the street is the bare minimum, and yet we have candidates who are unwilling to do even that. We can do better.\nConclusion #On August 2nd, we have the opportunity to drive home our demand for a brighter future for Ann Arbor. We took the first step two years ago, and we\u0026rsquo;re better for it. Mayor Taylor and the rest of the progressives led us through a global pandemic, cleaned up the mess in City Hall, and have put us in a great place to accelerate our commitment to good governance and sustainable progressive change. Let\u0026rsquo;s say \u0026ldquo;yes, and\u0026rdquo; again. Please vote to reelect Mayor Taylor, and vote for Cynthia Harrison (Ward 1), Chris Watson (Ward 2), Ayesha Ghazi Edwin (Ward 3), Dharma Akmon (Ward 4), and Jenn Cornell (Ward 5). Full speed ahead.\nVoting information, including how to register, request an absentee ballot, and find your polling place, is available at the City Clerk\u0026rsquo;s Election Page and the Michigan Voter Information Center\nPage 11, under Additional Observations\u0026#160;\u0026#x21a9;\u0026#xfe0e;\nPage 10\u0026#160;\u0026#x21a9;\u0026#xfe0e;\n","date":"5 July 2022","permalink":"https://brandon.dimcheff.com/2022/07/full-speed-ahead/","section":"Posts","summary":"Let\u0026rsquo;s keep heading in the right direction. Vote for Mayor Taylor and one of Cynthia Harrison, Chris Watson, Ayesha Edwin, Dharma Akmon, or Jenn Cornell.","title":"Full Speed Ahead"},{"content":"","date":null,"permalink":"https://brandon.dimcheff.com/tags/a2qouncil/","section":"Tags","summary":"","title":"A2qouncil"},{"content":"Genesis #Back in February last year I tweeted #a2Qouncil, a portmanteau of the #a2council hashtag and QAnon, making fun of a popular conspiracy theory that CM Ramlawi repeated. The theory is that someone someone has been hiring paid agitators to attack the enemies of The Mayor and His Allies. There is no evidence of this; it is pure innuendo and conjecture. Little did I know that was just the tip of the conspiracy iceberg. This post attempts to document and mock a few of the conspiracy theories that have been circulating in Ann Arbor.\nOf course, just as with all conspiracies, it\u0026rsquo;s effectively impossible to prove a negative, and Brandolini\u0026rsquo;s Law dictates that the amount of effort needed to refute bullshit is an order of magnitude larger than what is needed to produce it. I will, however, show that the conspiracies lack evidence and are implausible enough to be reasonably disregarded by rational folks. And maybe we\u0026rsquo;ll have a little fun in the process.\nThe Mayor And His Allies (aka the Evil Mayor conspiracies) #Many of the local conspiracy theories seem to trace their roots to the concept of an Evil Mayor who is pulling the puppetmaster strings behind the scenes and causing all sorts of nefarious things to happen. It\u0026rsquo;s particularly silly because, with a weak mayor system, the mayor doesn\u0026rsquo;t actually have a lot of power. The mayor and council set policy, but the day-to-day is controlled by the City Administrator, who effectively is the CEO of the city. Council and the Mayor can fire the Administrator (as we’ll see later) but the Mayor is roughly analogous to the chair of the board of directors at a company.\nThis isn\u0026rsquo;t a conspiracy theory per se, as much as it is the tendency to blame the Mayor personally for anything that happens in the city. Think \u0026ldquo;Thanks Obama!\u0026rdquo; but at the local level. As such, I\u0026rsquo;m not going to try to disprove this one. It\u0026rsquo;s just important to understand that this forms the base of most of the conspiracy theories I\u0026rsquo;ve seen.\nAs an aside, our current Mayor is one of the nicest people I\u0026rsquo;ve ever met, so the thought of him being a secret evil overlord is particularly hilarious to me. I certainly don\u0026rsquo;t always agree with every vote or policy choice that he\u0026rsquo;s made, but the thought that he\u0026rsquo;s a huge toxic influence on local politics is laughable. For example, the man thanks every public commenter, even those that spew incredibly hostile personal attacks at him, where a response of \u0026ldquo;go fuck yourself\u0026rdquo; would be eminently reasonable.\nNevertheless, conspiracies persist that the Mayor is attempting to engineer some sort of dystopian future for Ann Arbor, never revealing his true self via any of his outwardly observable actions. My guess is that folks don\u0026rsquo;t feel like they can disagree on the merits, so this sort of innuendo is the only objection they can raise, since good faith policy arguments won\u0026rsquo;t work.\nThe Media is out for Hayner And His Allies #Councilmember Hayner has been mad at the media for coverage of his poor behavior for years. It culminated in a recall campaign after he chose to use a homophobic slur while expressing displeasure at media coverage of the unpermitted addition he\u0026rsquo;s been putting on his house. Much digital ink has been spilled over Hayner\u0026rsquo;s issue with bigoted language at this point, which I won\u0026rsquo;t reproduce here, but CM Hayner in particular has a problem with the media.\nthis is #a2council cm hayner\u0026#39;s latest attack on our free press. this time singling out college students and the @michigandaily.\ntell us what you know, jeff. then kindly fuck off and resign. you\u0026#39;re a disgrace. pic.twitter.com/ngLEvzIM7I\n\u0026mdash; Violin Monster (@ViolinMonster) July 19, 2021 He\u0026rsquo;s never presented any evidence of what he means. He has been asked about it on multiple occasions, but he never responds with anything concrete. Big #FakeNews energy.\nThe #a2Qouncil crew came out in force to defend CM Hayner throughout these incidents. They seem to somehow believe this is an elaborate attempt to seize CM Hayner\u0026rsquo;s seat on council by\u0026hellip; tricking him into saying the n-word a couple times to a reporter? idk.\nAnyhow, former CM Bannister (and 2022 Mayoral candidate) called in (at least!) three times to council in order to say that Hayner was being unfairly treated for being criticized using slurs, one time quoting Bob Marley to do so, while claiming that criticizing his use of n-bombs was \u0026ldquo;white privilege\u0026rdquo;. What?\nBut things came fully unglued at the 8/4 special Council session on the Rule 12 ethics complaint: \u0026quot;I\u0026#39;m calling in to express my disappointment in the council members who voted yes for this shameful, hateful, vindictive, and evil resolution.\u0026quot; https://t.co/rbjw4oUXgK\n\u0026mdash; Daniel Adams (@danielnickadams) May 10, 2022 CM Ramlawi went as far as saying that we were treating CM Hayner \u0026ldquo;worse than the Nazis\u0026rdquo;. Come on man.\nHere’s a tape from the Admin Committee meeting where he complained, several times, that Council was treating his buddy CM Hayner—who council censured for using slurs on social media and in an Mlive interview—worse than the Nazis. Whatever that means. https://t.co/UttIcN3uyz\n\u0026mdash; Daniel Adams (@danielnickadams) June 21, 2022 The truth is, nobody really likes the media coverage of them all the time. They don’t always get it 100% right, and despite their commitments to unbiased reporting, reporters are humans too. Nobody’s out to get Hayner in particular, he just keeps doing absurd things that get him in the news. It shows a lack of courage and integrity when Hayner\u0026rsquo;s allies jump to his defense and spin conspiracy theories when he\u0026rsquo;s quite obviously behaving poorly and has no interest in changing. They could have told their buddy to cut it out, but instead they lashed out against the only people who were willing to hold him accountable.\nThe City Administrator, Act I: Lazarus #Many of the conspiracy theories over the last few years have been related to the City Administrator position. The previous \u0026ldquo;bad\u0026rdquo; council fired Howard Lazarus, then City Administrator, without cause. They also signed a nondisparagement clause, and thus can\u0026rsquo;t explain their reasons for firing him without getting sued. That didn\u0026rsquo;t stop (now former CM) Jack Eaton and CM Nelson from alluding to mysterious secret reasons that they fired him with enough frequency that Lazarus sent a cease and desist letter to them.\nTo be clear: it is absolutely true that council has the power to fire the City Administrator for any reason it wants, suddenly and with no public transparency. Likewise, the voters have the power to fire the councilmembers involved. Thankfully that is what they did.\nAs a result of the lack of transparency, rumors and speculation continue to this day. This was totally within the previous council\u0026rsquo;s power to avoid–by not signing an NDA—but they chose to do it this way. When people called them on it, they chose to respond with innuendo that got them a cease and desist. It was horribly irresponsible, lacking in transparency, and they paid the price at the polls. Good riddance.\nSince they can’t provide evidence for the true reasons they fired Lazarus, I’m forced to follow Occam’s Razor here: they just didn’t like him and wanted someone they thought they’d be able to influence more. It was undeniably within their power to do. It was just a bad decision. They lost the election. No conspiracies necessary.\nThe City Administrator, Act II: Crawford #After the previous council fired Lazarus, they had to find a replacement. Former CM (and 2022 Mayoral candidate) Bannister had an idea, which in this case might actually be evidence of a conspiracy:\n\u0026#39;Council Member Anne Bannister, D-1st Ward, asked if the city even needed to have a search, or if it could instead “just stick with our existing plan” and stay with Crawford.\n“You reference a plan and I’m not aware of any plan,” Mayor Christopher Taylor responded.\u0026#39;#a2council https://t.co/wPkwxdWmko\n\u0026mdash; Rob Utterback (@robutterback) June 30, 2020 Plan or no, council approved a wider-reaching search instead of just promoting Crawford immediately, but in the end they went with Crawford. Trust the plan, I guess.\nUnfortunately, according to an independent investigation, Tom Crawford created a hostile work environment for folks at city hall, and this Council (sans several of the members who voted to fire Lazarus and hire Crawford) had no choice but to fire him. (Note: Crawford technically resigned, but I will use \u0026ldquo;fired\u0026rdquo; colloquially here.) Glad they stuck with that plan, 💯.\nThis time, the city released a lot of information about what happened, including a mostly unredacted report and Tom Crawford\u0026rsquo;s response. However, despite a profoundly increased level of transparency, the conspiracy theories are 📈.\nFor instance, via Vivienne Armentrout:\nTaylor is indeed succeeding with the strategy of “Move fast and break things.” The dismissal of Tom Crawford clears the way for him to solidify his power base and to accomplish the major rearrangement of our community that he has promised. He is now making some moves to eliminate inconvenient Councilmembers. Students of history will recognize all the classical elements of the palace coup. To some extent, the voters of Ann Arbor may yet exert a weak influence, but he very nearly has his power base secure. He should be smiling again before long.\nyeah OR Tom Crawford said some insensitive shit while leading a progressive city and did so immediately after a councilmember decided to use homophobic and racial slurs, and Council\u0026rsquo;s hands are tied here. People were threatening to quit if Crawford wasn\u0026rsquo;t fired. Nobody has presented actual evidence that people didn’t like Crawford or wanted him gone. He just said some dumb shit and got fired.\nMore egregiously, CM Nelson also published the following to her blog:\nJustification for this week’s decision to terminate (Agenda Response to DC-7) was co-written by a member of City Staff who is likely to apply for the job of City Administrator: the same person currently acting as Interim City Administrator.\nCM Nelson is advancing a conspiracy theory that the interim city administrator (John Fournier?) orchestrated the allegations against Tom Crawford to get his job. This is some sick shit. Nelson is not fit to serve on council. #a2council https://t.co/VdjZKzbSlV pic.twitter.com/8jQYywf2oa\n\u0026mdash; KareninAA (@AaKarenin) July 25, 2021 Come on. It is highly irresponsible for a councilmember to suggest, with no evidence, that the interim City Administrator is framing Tom Crawford in some sort of Klingon-style power play. Fournier had to write an email to all the CMs assuring them that he wasn\u0026rsquo;t up to anything. This isn’t a simple disagreement on policy, it’s a fake narrative to distract from reality.\nLet me be crystal clear here: the turmoil that has clouded the City Administrator position in recent years was set into motion by the previous council by firing Howard Lazarus. The current council majority is cleaning it up, and they\u0026rsquo;re doing the best job that they can under the circumstances, despite the #a2Qouncil folks doing their best to make the job more difficult. If the old council would have been in charge, we would still have an Administrator with serious allegations of impropriety in charge of the city.\nThe Salvatore Report #The #a2Qouncil caucus really didn\u0026rsquo;t want to let Crawford go, even though the report was pretty overwhelmingly indicative of a problem. So what did they do? Did they own up to their mistake and accept that there needed to be a change in management at City Hall? Nope! They interfered with an investigation instead!\nIn those observations, two CMs appear to have both interfered with the investigation and done harm to the complainant in the process, and also potentially disclosed information from a closed session to the complainant. The CMs are Nelson and Ramlawi, by their admission.\n\u0026mdash; brandon aka @bdimcheff@hachyderm.io 🌻 (@bdimcheff) December 10, 2021 When they got caught, they attacked the well-respected independent investigator, spouting off conspiracy theories such as \u0026ldquo;the mayor and the investigator graduated law school in the same year\u0026rdquo;. Cool.\nAnyone watching #a2council tonight be prepared for a heavy dose of #a2Qouncil conspiracy theories.\nI\u0026#39;ll just say in advance that there\u0026#39;s a 0% chance that Jennifer Salvatore is willing to ruin her reputation to stage a conspiracy to remove a couple CMs from a couple committees.\n\u0026mdash; brandon aka @bdimcheff@hachyderm.io 🌻 (@bdimcheff) December 6, 2021 And they just won\u0026rsquo;t let it die, all the while complaining that people keep being mean to Tom Crawford.\nhere we go with the #a2Qouncil stuff #a2Council https://t.co/miNym3avH6\n\u0026mdash; brandon aka @bdimcheff@hachyderm.io 🌻 (@bdimcheff) February 23, 2022 This has gotten bad enough that I doubt that Jennifer Salvatore will ever take a job with the city again. Way to burn a bridge with one of the most qualified investigators around.\nQ-A2 #In response to this innuendo flying around town, Mayor Taylor published a post on Facebook that started:\nNo matter what irrational, corrosive Q-A2 nonsense you read or hear, this separation is the exclusive, proper, and unavoidable result of the employee’s inappropriate statements.\nNot as catchy as #a2Qouncil imo, but I suppose I\u0026rsquo;m biased. Regardless of your preferred term, this suggestion has fully enraged the folks who are peddling in the aforementioned conspiracies, as you\u0026rsquo;d expect. They’ve suggested that those accusing them of peddling misinformation and conspiracies are trying to silence their opponents, but entertaining bad faith arguments based on fabricated narratives isn’t productive. I often think of this tweet in these situations:\n🛑 Stop pretending bad faith is good faith for the purposes of “politeness” or “dialogue.”\n\u0026mdash; Popehat (@Popehat) October 16, 2020 The \u0026ldquo;C\u0026rdquo; in TC-1 Stands for \u0026ldquo;Corruption\u0026rdquo; #Attempts to bring transit-oriented development to Ann Arbor have been in progress since at least the last comprehensive planning process a decade ago, where it is mentioned (but not described in detail) as something the city should investigate to help meet its goals. It\u0026rsquo;s effectively attempting to create satellite downtowns where there\u0026rsquo;s already a bit of activity, but where we can turn strip malls and parking lots into something more exciting. After some delays created by the last council, council finally approved a TC-1 zoning district last July. During that meeting, CM Griswold effectively accused her council colleagues of accepting bribes, suggesting that they\u0026rsquo;re trying to increase density along transit corridors for nefarious reasons. Presumably these reasons go back at least a decade, since that\u0026rsquo;s when planning started for all of this. At this point in the story, we hadn\u0026rsquo;t even applied the zoning to any properties, it just created the ability to do it later that had already spawned conspiracy theories. Again, when you don\u0026rsquo;t have a good policy objection to something, your only remaining strategy is to make stuff up.\nFast forward to April and #a2Qouncil goes to 11. Now that we had the TC-1 zoning designation, the city had to actually apply it to some parcels. One obvious choice is to do it by the mall. There\u0026rsquo;s a lot of uninteresting stuff there now, the infrastructure is developed, busses are frequent, and there\u0026rsquo;s not a lot of other residential in the area so it seemed to me like there wouldn\u0026rsquo;t be much objection. Boy was I wrong. It turns out that people think that for a $2000 campaign donation you can get the mayor to spend over a decade working on a zoning district that personally benefits you! He even wrote about it years ago, and told residents he supported such zoning changes far in advance. Such corruption!\nOne resident of Lower Town went as far as to suggest that funding public transit is an attempt to enrich wealthy landlords. What? Big Bus Conspiracy My answer here is of course to apply this zoning to more transit-rich corridors if you\u0026rsquo;re worried about it being too localized. The city has just recently started on the next corridor, and I look forward to seeing what sort of conspiracy theories crop up from that.\nThis is what actual public corruption looks like. Making good on campaign promises is not.\na2Qouncil Shitposting #In an effort to stop pretending that bad faith is good faith, some of us decided to just parody the unhinged conspiracies. Check out the #a2Qouncil hashtag for more fun, and feel free to join in.\nMayor Taylor removed the weather shields the second we arrived at the pool and now it’s mass chaos of screaming kids and blown-over deck chairs. And the pool can’t open until 2:30 because they saw lightning. 😢 #a2qouncil\n\u0026mdash; Shannon Hughes Hautamaki (@SMHred) August 9, 2021 You’re strolling through Kerrytown to go shop at the inestimable Sparrow’s Market when you see a David Zinn drawing on the ground. You stop to admire it when—blast!—a trap! #MayorTaylorAndHisAllies drop a piano right on your head from the clock tower!\n#A2Qouncil #a2council\n\u0026mdash; Margot McGowan Staebler Arno (@probably_margot) August 7, 2021 Mayor Taylor and His Allies made me sit in one position for too long and now my leg is asleep! Unacceptable! Resign! #a2council #a2Qouncil\n\u0026mdash; brandon aka @bdimcheff@hachyderm.io 🌻 (@bdimcheff) August 6, 2021 Taylor gets kickbacks from Big Development™ and Men\u0026#39;s Wearhouse. Why do you think he\u0026#39;s always wearing that blue blazer? Check it. #A2Qouncil #a2council pic.twitter.com/ca6bh4OviY\n\u0026mdash; Jaime Magiera (@jaime4a2) August 7, 2021 But not everyone was amused:\n#A2Council In case you missed CM Hayner\u0026#39;s opinion of the #A2Qouncil hashtag: pic.twitter.com/TRhfEbBeXP\n\u0026mdash; 𝕁𝕒𝕞𝕖𝕤 𝕁 ℙ𝕪𝕜𝕖 (@fleshytimeclock) August 9, 2021 🙄\nMy Hope #I hope this little trip down the #a2Qouncil rabbit hole was illuminating.\nThis is all I really want, though, which I read to council last year:\nHi this is Brandon Dimcheff from the 4th ward.\nI just want to say that I think nobody is happy to be in the position that we’re in with respect to the City Administrator right now, and I want to thank council for their work handling this difficult issue when I’m sure everyone would rather be working on policy.\nI will also say that I wish we could approach disagreements with facts and sound arguments instead of innuendo and suggestions of conspiracy, and I appreciate those council members who have shared what facts they can without wild speculation and unfounded accusations. I would ask those on and off council who are peddling conspiracy theories for political gain to consider that those theories are harmful to staff and the community at large. We have a lot of work ahead of us, let’s not make it harder.\nThanks, and have a good night.\nSince then, Council has hired a great interim City Administrator who has recently accepted a full-time offer here. City Hall is stabilizing, no thanks to the #a2Qouncil caucus, and I am extremely thankful that the rational folks held a majority during this time. I have absolutely no doubt we\u0026rsquo;re in a much better position than we would have been if the folks who started all this turmoil were still in charge.\nThe future #As I mentioned before, I strongly believe that these conspiracies arise out of a lack of having real policy positions, so nonsense is the only thing that remains. It\u0026rsquo;s similar to how things are going nationally—the GOP has nothing but the culture war because they have no solutions to actual problems. Likewise, these folks are just mad about not being able to block good policy that they don\u0026rsquo;t like, and they lash out by making up conspiracies instead of trying to work towards benefitting the city and its residents. Folks like that should not be allowed to govern.\nThe primaries are on August 2nd. Please vote to reelect Mayor Taylor, and vote for Cynthia Harrison (Ward 1), Chris Watson (Ward 2, uncontested), Ayesha Ghazi Edwin (Ward 3, uncontested), Dharma Akmon (Ward 4), and Jenn Cornell (Ward 5). I\u0026rsquo;ve gotten to know all of these candidates, and I\u0026rsquo;ve been impressed with each of them. I\u0026rsquo;m confident that they will make excellent councilmembers who will govern with integrity and transparency. We\u0026rsquo;re so close to having rational adults running the city, let\u0026rsquo;s finish the job. Absentee ballots are available starting this week.\n","date":"21 June 2022","permalink":"https://brandon.dimcheff.com/2022/06/a2qouncil/","section":"Posts","summary":"A brief overview of the conspiracy theories that have been floating around Ann Arbor in recent years.","title":"A2Qouncil"},{"content":"I sent the email below to City Council after I became frustrated that what seemed like a broad condemnation of hateful, inappropriate speech turned into a factional fight instead of a unanimous rebuke of the poor behavior that plagues our local politics here in Ann Arbor.\nFirst, some background for those new to this particular area, and a content warning: my letter does not contain slurs, but some of the articles and tweets I have linked contain homophobic slurs.\nThe best long-form summary of what\u0026rsquo;s going on is probably this Michigan Daily article, but tl;dr Hayner posted a quote from Hunter S. Thompson\u0026rsquo;s Fear and Loathing in Las Vegas that contains a homophobic slur, ostensibly to attack the local press for coverage of him that he didn\u0026rsquo;t like. When people were upset by his actions, he dug in his heels and refused to apologize for a while, and then finally issued a short pseudo-apology with no real details or commitment to do better.\nCM Hayner has a history of being an edgelord on twitter that predates his term on council, which The Daily has also covered. This is a pattern of bad behavior, and it has gone on for too long. It is time to stop tolerating it.\nGreetings, Ann Arbor City Council.\nI would like to briefly address CM Hayner\u0026rsquo;s offensive public comments and DC-5. Well, actually I don\u0026rsquo;t enjoy this at all. I would prefer to use this email to discuss my excitement about our efforts around housing and non-motorized infrastructure coming to fruition in CA-2 through 5, C-1, and C-2, but unfortunately CM Hayner\u0026rsquo;s behavior has forced me to address council on this unpleasant topic.\nFrom what I can tell, every Councilmember agrees that the statements that CM Hayner made were inappropriate, particularly for someone holding elected office in Ann Arbor. The question, then, is what is the appropriate response from council?\nIf this was CM Hayner\u0026rsquo;s first time exhibiting such behavior, I\u0026rsquo;d be inclined to consider a public apology a reasonable response. Unfortunately, CM Hayner has shown an escalating pattern of hostility towards other members of council, the press, and members of the community who disagree with him. When confronted with criticism of these attacks, he has repeatedly refused to accept responsibility for his actions.\nIn this particular case, he defended his post, has lied about how long it was up, said that people just \u0026ldquo;want to be offended\u0026rdquo;. His defense amounted to \u0026ldquo;I\u0026rsquo;m not attacking the LGBTQ community, I\u0026rsquo;m attacking the press,\u0026rdquo; which is also not a reasonable position for a public official to take. After significant community pressure, he has released a very short apology, which many of his constituents and community members cannot view because he has blocked them on social media. His apology does not convince me that he understands the ways his actions were harmful, nor does it convince me that he has committed to repairing the damage and ensuring that something similar won\u0026rsquo;t happen again.\nAgain, this is far from the first time that CM Hayner has exhibited this sort of behavior. He refused to accept responsibility for his inflammatory and misogynistic tweets from before he was elected and instead has continued inflammatory posts on social media. Instead he has attacked those who have pointed them out. He has refused to accept responsibility for his troubles with the building department, instead choosing to attack those who discovered his unpermitted addition and vaguely threatening people who approach his house.\n\u0026ldquo;To have better behavior, we simply need to behave better. It should not be that hard, and it should not require more rules,\u0026rdquo; said CM Hayner a couple months ago. He clearly hasn\u0026rsquo;t taken his own advice, so it\u0026rsquo;s up to Council to take action. Please listen to advocates, particularly those from communities that CM Hayner has harmed, and act. Council clearly has the authority to implement the actions in DC-5, as council has broad discretion to remove committee members for cause. Please use that authority to show the community that this behavior will not be tolerated.\nI know there have been some concerns around the First Amendment, but if that\u0026rsquo;s the case then Congress and the Board of Regents would also have been in violation for removing Marjorie Taylor Greene and Ron Weiser from their committee assignments. Nobody has seriously suggested that those actions violate the Constitution. You have the authority to act, and Ann Arborites will not accept excuses about lack of authority as anything other than an attempt to defend this use of bigoted language.\nI\u0026rsquo;d like to particularly address CMs who may be hesitant to act here due to political alliances: please put City over Party. The members of Congress who were recently willing to cross party lines and do the right thing will be remembered for their courage, while those who didn\u0026rsquo;t were rightly criticized for having misaligned priorities. Sending a message that Ann Arbor rebukes intolerance will be more powerful if conveyed unanimously. That is what our community demands and deserves.\n","date":"18 April 2021","permalink":"https://brandon.dimcheff.com/2021/04/consequences/","section":"Posts","summary":"Councilmember Hayner used a homophobic slur to attack the local press, and I think he should face consequences as a result.","title":"Consequences"},{"content":"","date":null,"permalink":"https://brandon.dimcheff.com/tags/covid/","section":"Tags","summary":"","title":"Covid"},{"content":"At the City Council meeting on February 16, 2021, Ann Arbor City Council approved a resolution allowing Conor O\u0026rsquo;Neill\u0026rsquo;s to use Main St. to provide outdoor seating for St. Patrick\u0026rsquo;s Day. It provoked a pretty immediate negative reaction from a lot of people around town, and the mayor ended up vetoing it. I personally think that indoor dining is a much larger problem than this would have been, but we shouldn\u0026rsquo;t be doing any of this stuff, particularly now.\nIf you\u0026rsquo;re trying to get a covid vaccine in Michigan right now, check out VaccineMI, where we\u0026rsquo;re trying to compile Michigan vaccine availability all in one place.\nHere\u0026rsquo;s what I sent to City Council after the veto:\nThanks for reconsidering restarting outdoor dining for St. Patrick\u0026rsquo;s day. While the initial visceral reactions were stronger than the severity of the risk introduced by this particular event, I think it was the right call to cancel it. Outdoor transmission has occurred (remember the Rose Garden?) it\u0026rsquo;s just less likely than indoors. Even if the event itself is relatively safe, the loosening of restrictions anywhere may cause people to take fewer precautions in other areas of life. \u0026ldquo;Oh people are eating outdoors on Main St., we might as well have a barbecue\u0026rdquo;, etc.\nI know everyone is suffering from pandemic fatigue, but now is a particularly terrible time to increase spread. Early in the pandemic, when it was unclear if or when there would be a vaccine, it made sense to flatten the curve to avoid overwhelming medical facilities, even if the same number of people would inevitably become sick eventually, particularly when it was obvious we were not going to control it at a national level. Now that we have effective vaccines, the benefit of slowing the spread is more acute. We\u0026rsquo;re no longer simply delaying people\u0026rsquo;s illnesses and deaths, we\u0026rsquo;re preventing them entirely. Every case we can delay until after someone is vaccinated is (effectively) a case avoided. For every ~100 cases we avoid, we save a life. We should be doing everything possible to delay cases until we can get enough shots into arms.\nWe\u0026rsquo;ve been at this for nearly a year now. In a few more months, if all goes well with the vaccine rollout, we\u0026rsquo;ll be able to get back to a much more normal life. The end is in sight. As they say after you land on a plane: \u0026ldquo;please remain seated with your seatbelt fastened until the aircraft is at the gate and the captain turns off the seatbelt sign.\u0026rdquo; Get up too early and you\u0026rsquo;re likely to end up with a bloody nose.\nPlease consider future policy changes in this context. We have an opportunity to save a ton of lives, and we should take it. I know the support from the State and Federal governments hasn\u0026rsquo;t been great, and we can\u0026rsquo;t singlehandedly implement a zero-covid policy like Australia or New Zealand, but we should do what\u0026rsquo;s in our power at the local level to save as many lives as possible over the next few months. I understand that we can\u0026rsquo;t control everything, and some things move risk from one place to another, but minimizing overall risk is the most important thing we can do. Honor the 250 lives we\u0026rsquo;ve lost in Washtenaw County by preventing more unnecessary deaths.\nOne thing is abundantly clear to me: we should not be doing indoor dining right now. There is no virtue to indoor dining, it is simply high-risk fun. If we can replace indoor dining with outdoors, that is a net risk reduction, but supplementing indoor dining with outdoor dining increases overall risk. Carryout is nearly zero-risk. I know restaurants are hurting but let\u0026rsquo;s convince everyone to get carryout, tip well, and eat at home, just for a few more months. Encourage people to take a masked walk with friends around gallup if they want in-person human contact for at least a 20x less risky in-person activity.\nFor more on this topic, I highly recommend this the Osterholm Update podcast generally, and this week\u0026rsquo;s episode is particularly relevant. I think it\u0026rsquo;s a huge mistake to allow nonessential, in person, unmasked activities just as cases are finally falling and we have a new variant taking off. Just like Dr. Osterholm, I hope I\u0026rsquo;m wrong, but I think things are about to get a lot worse before they finally get better as we get more people vaccinated.\nI\u0026rsquo;ve found Microcovid to be very useful, and it has guided me in composing this letter: it has a risk calculator that allows you to input various scenarios to see how risky they are. Their math is aiming to keep your likelihood of catching covid under 1% per year, and allows you to see how much each activity \u0026ldquo;spends\u0026rdquo; your covid budget. It\u0026rsquo;s obviously not perfect, but it gives you a good idea of relative risks. It\u0026rsquo;s adjusted for county numbers periodically, so the numbers below are what applies on February 21, 2021 and may change if you visit these links later. For example:\nOutdoor dining for 90min in Washtenaw County is 100% of your weekly covid budget. A 6h plane ride with middle seats empty is only 80% of your weekly budget. Going to the grocery store for an hour is about 40% as risky, if properly masked. 🚨 Indoor dining with only 6 people within 15 feet of you is 8x your weekly covid budget. 🚨 Going for a masked walk in Gallup with a couple of friends is nearly risk-free. Picking up carryout afterwards is also nearly risk-free, and with curbside pickup it effectively is zero-risk. Stay healthy,\nBrandon Dimcheff, Ward 4\n","date":"21 February 2021","permalink":"https://brandon.dimcheff.com/2021/02/covid-and-dining/","section":"Posts","summary":"Where I argue that we should in-person dining closed until people are vaccinated, particularly indoor dining.","title":"Covid and Dining"},{"content":"","date":null,"permalink":"https://brandon.dimcheff.com/tags/broccoli/","section":"Tags","summary":"","title":"Broccoli"},{"content":"","date":null,"permalink":"https://brandon.dimcheff.com/tags/casserole/","section":"Tags","summary":"","title":"Casserole"},{"content":"","date":null,"permalink":"https://brandon.dimcheff.com/tags/chicken/","section":"Tags","summary":"","title":"Chicken"},{"content":"","date":null,"permalink":"https://brandon.dimcheff.com/tags/recipe/","section":"Tags","summary":"","title":"Recipe"},{"content":"","date":null,"permalink":"https://brandon.dimcheff.com/categories/recipes/","section":"Categories","summary":"","title":"Recipes"},{"content":"Adapted from The University of Michigan to simplify it and make it slightly saucier. Go Blue.\nIngredients # 1lb broccoli, chopped fresh or frozen 1T or so cooking oil 1lb Chicken Breasts, diced 3T butter 1 small onion, diced 3T flour 1c chicken broth 3/4c Sour Cream 1c heavy cream 1/2t salt pepper to taste 1/4c grated Parmesan Cheese 1/4c Bread Crumbs Method # Steam broccoli for a few minutes in the microwave or on the stove, undercooked a little. In a relatively deep saute pan, saute the diced chicken in vegetable until browned and mostly cooked through. Set aside. In the pan over medium heat, melt butter and sauté onions until translucent. Add flour and cook, stirring constantly for 1-2 minutes. Add chicken broth slowly, scraping up browned bits and evenly hydrating the roux while you whisk. Once the broth is added, add sour cream and heavy cream. Gently simmer mixture for 5 minutes. Taste and adjust seasoning. Gently fold in the cooked chicken meat and the cooked broccoli. Top with combined bread crumbs and Parmesan cheese. Spray the top with some cooking spray to help the bread crumbs brown. Bake for 20min in a 325-degree oven until the top is lightly browned and mixture is bubbly and the chicken is cooked. Serve over rice. ","date":"26 November 2020","permalink":"https://brandon.dimcheff.com/recipe/umich-chicken-broccoli-bake/","section":"Recipes","summary":"Dorm food isn\u0026rsquo;t traditionally regarded as good, but this dish is almost everyone\u0026rsquo;s favorite from the dorms at Michigan. Hint: butter and two kinds of cream helps.","title":"University of Michigan Dorm Chicken Broccoli Bake"},{"content":"Adapted from Cooks Illustrated, Alton Brown, and for a pressure cooker.\nIngredients # 1 pound small red beans (about 2 cups), rinsed and picked over 4 slices bacon (about 4 ounces), chopped fine 1 medium onion, chopped fine (about 1 cup) 1 small green bell pepper, seeded and chopped fine (about 1/2 cup) 1 celery rib, chopped fine (about 1/2 cup) 3 medium garlic cloves, minced or pressed through garlic press (about 1 tablespoon) 1 teaspoon fresh thyme leaves 1 teaspoon sweet paprika 2 bay leaves ¼ teaspoon cayenne pepper Ground black pepper 4 cups low-sodium chicken broth 12oz pickled pork (see alton brown\u0026rsquo;s recipe) 8 ounces andouille sausage, halved lengthwise and cut into 1/4-inch slices (see note) Method # Dissolve 3 tablespoons salt in 4 quarts cold water in large bowl or container. Add beans and soak at room temperature for at least 8 hours and up to 24 hours. Drain and rinse well. Heat bacon in pressure cooker set to high, stirring occasionally, until browned and almost fully rendered, 5 to 8 minutes. Add onion, green pepper, and celery; cook, stirring frequently, until vegetables are softened, 6 to 7 minutes. Stir in garlic, thyme, paprika, bay leaves, cayenne pepper, and 1/4 teaspoon black pepper; cook until fragrant, about 30 seconds. Stir in beans, pickled pork, and broth. Set pressure cooker to 20 minutes on high. Allow pressure to release for 20 minutes naturally, then release the rest. Set pressure cooker to saute low and bring to a boil. Add andouille and cook for about a half hour, stirring occasionally, until beans are thick and creamy. Serve on rice (cook it first) ","date":"26 November 2020","permalink":"https://brandon.dimcheff.com/recipe/pressure-cooker-red-beans-and-rice/","section":"Recipes","summary":"A popular Louisiana creole dish, ruined by a yank.","title":"Pressure Cooker Red Beans and Rice"},{"content":"","date":null,"permalink":"https://brandon.dimcheff.com/tags/pressurecooker/","section":"Tags","summary":"","title":"Pressurecooker"},{"content":"Background #There is a meeting of the Michigan Board of State Canvassers on Monday, November 23, 2020 at 1pm where they are duty-bound to certify the election results from the November 3rd presidential election in Michigan. After the Wayne County board briefly failed to certify the county results, there is some concern that the State board will do the same. This is an unwelcome attack on a fair election, and an attempt to disenfranchise Michiganders.\nThere are public comment opportunities, both written and via zoom, that you can participate in via filling out this surveymonkey form.\nFor more details on what happened in Wayne County, check out @beyond_process\u0026rsquo;s thread and this NYT article. You may have seen Ned Staebler\u0026rsquo;s viral commentary on MSNBC, The Late Show, The Daily Show, etc.\nI chose to write a letter, since I\u0026rsquo;m no Ned, which is below. If you\u0026rsquo;re a Michigander and have a sec to write a letter, or have time on Monday to be on a zoom for hours, I encourage you to do so.\nLetter #Michigan Board of State Canvassers,\nI\u0026rsquo;m writing to ask that you please certify the election results without delay and political posturing. There are no signs of irregularity besides a handful of clerical errors that occur at every election and are inconsequential to the final result. Risk-limiting audits have been performed by the Secretary of State and they showed no irregularities.\nThe voters of Michigan have spoken, and attempting to undermine the election results is unwelcome and unamerican. These attempts will almost certainly fail, but the delays and uncertainty are going to cost American lives and erode our national security. Eroding faith in the results of a fair election is the stuff of tin-pot dictators, not a democratic republic that obeys the rule of law.\nPut country over party, and over the demands of one man who is afraid to accept reality. It is your patriotic and legal duty to certify the results. History will remember what you do today.\n- Brandon Dimcheff\n","date":"22 November 2020","permalink":"https://brandon.dimcheff.com/2020/11/letter-to-the-michigan-board-of-state-canvassers/","section":"Posts","summary":"This is a letter I wrote to the canvassers to encourage them to accept the results of the 2020 presidential election, since it seems that may not automatically happen.","title":"Letter to the Michigan Board of State Canvassers"},{"content":"We have a problem in Ann Arbor: more people want to live here than there is available housing. When housing demand exceeds supply, prices go up and as a result only rich people can afford to move here. As long-time residents sell their homes, more and more affluent people buy them, gentrifying neighborhoods. Low vacancy rates cause landlords to raise rents, forcing people to look for housing elsewhere. \u0026ldquo;Thank you essential workers\u0026rdquo; signs should read \u0026ldquo;Thank you essential workers, but sorry, Ann Arbor is full. Hope your commute isn\u0026rsquo;t too long!\u0026rdquo;. If you disagree that this is a problem, you might as well stop reading now, because the rest of this is premised on agreeing on this fact.\nThat brings us to the question: how do we solve this problem? Sometimes I\u0026rsquo;m not sure if people are kidding, but I have heard people suggest that we stop building more housing in order to make housing more affordable. I\u0026rsquo;m not sure how that would possibly work without a concerted effort to make Ann Arbor horribly unwelcoming, so clearly doing nothing isn\u0026rsquo;t the answer. Despite the desires of some people on Nextdoor, we can\u0026rsquo;t freeze Ann Arbor the way it was when they bought their house in the 80s. People are gonna move here, we gotta adapt or it\u0026rsquo;ll only be the most affluent who can afford to be our neighbors. It\u0026rsquo;ll also push gentrification further into Ypsi and surrounding communities, and further increase pollution due to longer commutes and more traffic. That\u0026rsquo;s not ok with me.\nWe have built a little bit more housing, but housing demand still outstrips supply. A few \u0026ldquo;dense projects\u0026rdquo; here and there isn\u0026rsquo;t going to get us out of this mess, and a history of blocking and delaying viable projects downtown and on transit lines doesn\u0026rsquo;t fill me with confidence that the current council majority has the desire to do what we need to help make Ann Arbor a more diverse and welcoming community. We certainly shouldn\u0026rsquo;t be arguing for years and then in the end not building anything, which is exactly what happened at least 3 times in recent memory, costing taxpayers $5-10M in the process, not including lost tax revenues from new taxpayers.\nWe also must solve our housing shortage from all angles. I often hear objections to a particular housing plan because it doesn\u0026rsquo;t solve literally every housing problem immediately. Should we instead do nothing? Of course not! We need more market rate housing, but market rate housing is not sufficient. We need more subsidized housing, but subsidized housing is not sufficient. We need creative solutions, vision, and flexibility to try new things. Sure, use the process to make projects better, but concern trolling a project or idea until it goes away (or turns into 16 by-right McMansions instead of hundreds of denser homes) as we have seen recently is not the way. We spend far too much time getting to \u0026ldquo;no\u0026rdquo; or making projects worse rather than working together to efficiently and productively get to \u0026ldquo;yes\u0026rdquo;.\nWe need to decrease barriers to building dense housing, and we need to fund affordable housing, and we\u0026rsquo;re way behind the ball. We need more housing of all kinds, except single family housing. There\u0026rsquo;s effectively no more room for single family homes, and it\u0026rsquo;s the least efficient use of the scarce land we have left inside the city.\nI know there are folks around town who are trying to scare everyone about density, but don\u0026rsquo;t be afraid. They\u0026rsquo;re threatening you with new neighbors, friends, colleagues, classmates, and more. I\u0026rsquo;m excited to welcome them to our community.\nWho can help? #Luckily we have great candidates who are willing to fight to make Ann Arbor a better place for all. Someone who convinces me they will work in good faith towards moving Ann Arbor forward will have my vote and support. To that end, I recommend voting for Lisa Disch in Ward 1, Linh Song in Ward 2, Travis Radina in Ward 3, Jen Eyer in Ward 4, and Erica Briggs in Ward 5. They are the leaders we need in Ann Arbor to make progress on our housing crisis before it gets even worse.\nDo these candidates agree with each other all issues under all circumstances? Do I agree with them on all issues? Of course not! But I trust them to act thoughtfully and diligently to make decisions in the best interest of the residents of Ann Arbor and our future neighbors. I trust them to have sound judgement and good values. They each bring skills and experience that will serve Ann Arbor well. They\u0026rsquo;re who we need on council.\nIn this post I have mostly spoken about housing, because it\u0026rsquo;s one of the things that is a particularly big problem that can be addressed by local government. There are obviously other issues that matter, and I also think that these candidates are well suited to act on them as well: clean water, policing, safe streets, and equity issues to name a few. For the same reason I expect that they will make good housing decisions, I trust their thoughtfulness and problem solving in other matters that matter to our community.\nPlease vote for a better future for Ann Arbor.\nA note about voting in a pandemic #Election day is Tuesday, August 4th. If you haven\u0026rsquo;t returned your absentee ballot yet, you must return it yourself, to the City Clerk\u0026rsquo;s office. Track your ballot and if it\u0026rsquo;s not there by Monday, go to City Hall before they close. If it\u0026rsquo;s not registered by the time the clerk\u0026rsquo;s closes on Monday, it\u0026rsquo;s my understanding that you have to go to your polling place and they can help you. I\u0026rsquo;m not 100% sure about that, but contact the clerk or show up at your polling place to ask a poll worker. If you have better details, let me know and I will update this post.\n","date":"2 August 2020","permalink":"https://brandon.dimcheff.com/2020/08/the-future-of-ann-arbor/","section":"Posts","summary":"Let\u0026rsquo;s solve our housing crisis. Vote for Lisa Disch, Linh Song, Travis Radina, Jen Eyer, or Erica Briggs.","title":"The Future of Ann Arbor"},{"content":"I originally wrote this to read aloud at city council, but it looks like my slot disappeared. Instead I sent it via email, even though it\u0026rsquo;s not really designed for written form.\nHi, my name is Brandon Dimcheff, and I live in the 4th ward. I want to talk about the collective bargaining agreement with the AAPD, and policing in Ann Arbor.\nIt\u0026rsquo;s easy to assume that we\u0026rsquo;re special, and thus immune to the systemic injustices built into American policing. Our police department is probably among the best by conventional metrics, and we live in a generally peaceful community. But we are very much not exempt from the problems of how policing and criminal justice are administered, and we should not act like we\u0026rsquo;re 30 square miles surrounded by reality, as people are fond of saying.\nFor every Aura Rosser, there are hundreds? thousands? of people who are threatened with violence unnecessarily but are luckily still alive. People with addiction problems that end up in the criminal justice system instead of being treated for their addiction. People in jail for minor offenses, catching a potentially fatal disease. In cases like these, no amount of oversight will result in justice, as the problems are not caused by individual officers, but by the system itself. We must stop using violence where it is unnecessary and counterproductive. This is Ann Arbor. We can do better.\nOversight (and ICPOC) are necessary but not sufficient. Accountability for officers is necessary but not sufficient. Transparency and availability of policing data is necessary but not sufficient. Contract changes may also be necessary, but are not sufficient.\nTo that end, I agree that the ICPOC-suggested changes to the contract are worthwhile, but even if they are approved, those changes must be only the beginning. Spend the political capital to change policing and law enforcement to truly protect our fellow citizens. Take easy wins where you can. Prioritize changes that will actually make a difference. Don\u0026rsquo;t think that changing the contract and empowering ICPOC is enough to offset hundreds of years of systemic racism.\nConsider, for instance:\nproviding social workers that can take the place of police interactions in situations that don\u0026rsquo;t require an armed response funding mental health and addiction treatment services so we can address the root causes of a lot of crime finding alternative enforcement options for civil infractions getting rid of laws that provoke unnecessary interactions with the police, particularly those that are disproportionately used on people of color and most importantly: listening to experts who have been working in this space for years, including those on ICPOC and local advocates How should we pay for it, you may ask? Well we spend $30M (or approximately 1/3 of our budget) on AAPD every year. Reallocate some of it to address the root causes of crime instead. Public safety will benefit overall, and we will make Ann Arbor a more just and equitable place.\nThank you for your time.\n- brandon\n","date":"6 July 2020","permalink":"https://brandon.dimcheff.com/2020/07/on-the-aapd-contract-renewal/","section":"Posts","summary":"a statement I intended to give at Ann Arbor City Council re: police contract negotiations and funding","title":"On the AAPD Contract Renewal"},{"content":"","date":null,"permalink":"https://brandon.dimcheff.com/tags/police/","section":"Tags","summary":"","title":"Police"},{"content":"","date":null,"permalink":"https://brandon.dimcheff.com/tags/bread/","section":"Tags","summary":"","title":"Bread"},{"content":"","date":null,"permalink":"https://brandon.dimcheff.com/tags/sourdough/","section":"Tags","summary":"","title":"Sourdough"},{"content":"Creating a Starter #So how do you get one of these magical starter cultures? You can ask me, and I\u0026rsquo;ll give you part of mine, but there is some satisfaction in doing it yourself. My best suggestion is to head over to The Perfect Loaf, one of my favorite places to learn about sourdough. Maurizio\u0026rsquo;s stuff is great, and he has a good procedure for starting a starter that\u0026rsquo;s pretty much as efficient as possible. Once you have one going, you have to name it. It is the law.\nTL;DR #Fundamentally all you do is mix flour and water and hope that the good bacteria and yeast win before the bad bacteria do. The odds are in your favor, though, since the good bois are producing things that make the culture hostile to pathogens.\nAll you gotta do to make a starter is:\nMix flour and water, put somewhere kinda warm, wait 24h. Throw half of it out, add equivalent weight of flour and water to the stuff you just threw out. Keep doing that for a week or so. One day it\u0026rsquo;ll look something like the featured image at the top of this post. or it\u0026rsquo;ll look and smell bad, in which case something has gone awry. Start over. 🎉 you have a starter. Definitely read the article I linked above, but a few tips to remember are:\nUse unbleached flour. Bleaching removes the good yeasties. Add some whole grain. Maurizio uses rye, I just used whole wheat. This gives you more good yeasties than white flour alone. I also just used regular King Arthur All Purpose flour and their Hard Red Winter (Whole) Wheat. It\u0026rsquo;s better than misc cheapo flour, but it\u0026rsquo;s not extremely high end hipster flour or anything. Keep it mostly clean. The first few days are a battle of exponential growths. You don\u0026rsquo;t want to get too much bad bacteria in there before the good stuff can take hold. You\u0026rsquo;re washing your hands anyways, right? Maintaining a Starter #The whole point in starter maintenance is to keep your wee culture happy and healthy, and to be able to use some of it to leaven some bread from time to time. It\u0026rsquo;s a little blob of yeast and bacteria that gradually consumes all of the food (mostly carbs, but proteins too) in the flour and in exchange produces some useful byproducts (CO₂, alcohol, lactic acid, other tasty bits). Once it has consumed all its food, it goes dormant, or eventually dies if you leave it too long. The byproducts are generally hostile to pathogenic bacteria, so as long as you keep it healthy and don\u0026rsquo;t dump anything really nasty in there, the natural environment prevents it from spoiling.\nThere\u0026rsquo;s a lot of lore around starters, and most of it has proven to be rumor and conjecture. All that really matters is that you feed it occasionally and nothing too gross gets into it. I happen to find a 12h feeding cycle convenient, because some recipes can be made from starter directly in the morning and some need a child starter (levain) to be started in the morning or evening, depending on your schedule. You can do a 24h feeding cycle instead, but it\u0026rsquo;s harder to adjust to your baking schedule when there\u0026rsquo;s only one opportunity per day to use the starter.\nIf you don\u0026rsquo;t want to bake for a while, NBD! Just store your starter somehow. It\u0026rsquo;s easy, and before the quarantine I usually did something like this weekend baking schedule. Nowadays since I\u0026rsquo;m home all day anyways, I\u0026rsquo;ve been continuously maintaining my starter as described below.\nI\u0026rsquo;ve streamlined my starter process a little bit. I basically do one of two things, depending on what my intent is over the next 24h.\nNot gonna bake in the next 24h # Wake up, make coffee. ☕️ important, or bad things happen. Discard all but a little smear of starter on the bottom of the jar, maybe 3-5g. nearly empty jar with just a little leftover starter Tare my scale, add 25g of regular old (unbleached, always) all-purpose flour. Measure 25g/ml of filtered (no chlorine, please) water and microwave it for 6s. Shooting for room temp. Mix it all up, put a loose lid on top of the jar, and stick it in my proofer set at 77ºF/25ºC. I just bought myself 12h (24 in a pinch). Now at ~9pm I do the same thing. This only consumes about 50g of flour and 4 minutes per day. If you forget one of them, nbd just do the same thing as always. It might be stressed, so you might want to leave a little more residual starter.\nGonna mix up a loaf in the next 24h # Wake up, make coffee. Still important. Figure out how long until I want to use the starter. These days during quarantine it\u0026rsquo;s something like 9am and I want to mix the starter into a batch of bread at around 6pm. For this example, 9h. Figure out how much starter I need. Lately it\u0026rsquo;s been 144g. My starter is 100% hydration so I need 72g of flour and 72g of water. Lets round up to 80g each to be safe. When I bake with my starter, I almost always use 1:1 ratio of All Purpose (AP) : Whole Wheat (WW), so 40g AP : 40g WW : 80g H₂O. That\u0026rsquo;s the easy math. Now the tricky part: figuring out how much starter to leave behind. I happen to know (from experience, and by design) that at 25ºC and ~8% leftover starter, that my starter will be ready in about 12 hours. I need it to be ready in 9h, so I have to adjust some variable to speed it up: higher temperature, higher hydration, increasing WW%, and leaving more starter behind will all make this go faster. Modifications to anything but residual starter also change other variables: flavor being the big one. I don\u0026rsquo;t really want to do that. Therefore we\u0026rsquo;re gonna increase the amount of starter we leave behind. This is an exponential growth thing (is this why everyone\u0026rsquo;s into sourdough lately?) so doubling the residual starter should halve the amount of time. We want to cut it by 50%, so lets add 50%. So 12% residual starter, or 20g plus the 160g new stuff we\u0026rsquo;re adding. Dump everything but 20g of yesterday\u0026rsquo;s starter, add 40g AP flour, 40g WW flour, 80g water (microwave \u0026rsquo;till it\u0026rsquo;s close to 77 degrees, 14s in my case). Stir that bad boy up, loose lid, let sit \u0026rsquo;till 6pm. freshly mixed starter I know that sounds like a lot, but you\u0026rsquo;ll get the hang of it after a couple tries and you won\u0026rsquo;t need to pull out the calculator. The math also doesn\u0026rsquo;t need to be exactly perfect, you\u0026rsquo;re gonna have a 1-3h window here to use the thing.\nHow do I know when my starter is ready to be used? #Generally you want your starter to be at its peak when you use it. It\u0026rsquo;s growing the fastest at this point and is almost done consuming all the available food, so your microorganism population is the highest. If you use it too early, it\u0026rsquo;ll be diluted too much and won\u0026rsquo;t be able to leaven your bread (or it\u0026rsquo;ll take a while). If you use it too late, it\u0026rsquo;ll have gone into dormancy and it\u0026rsquo;ll take too long to come back.\nSome people like to take a little bit of the starter and drop it in a cup of water and see if it floats. That\u0026rsquo;s fine, but using your eyes and nose usually works too. It should look really bubbly and shouldn\u0026rsquo;t have fallen much, if any, from its peak. Check out the featured image at the top for what a fully mature starter looks like. It also smells like fermentation: a little bit of alcohol, a little bit of vinegar. Yeasty, but definitely not foul.\nNow what? #Now you make some bread. I haven\u0026rsquo;t written that up in long form yet, but here\u0026rsquo;s a few places to look if you\u0026rsquo;re impatient:\nTPL\u0026rsquo;s Focaccia was my first sourdough, and it came out great on the first try. It is not sour at all, and if you don\u0026rsquo;t like sourdough this is a great place to start. It also doesn\u0026rsquo;t require a dutch oven because it bakes in a 13x9\u0026quot; casserole dish. ProTip™: if you use a glass one, line it with parchment so it doesn\u0026rsquo;t stick. If you want to practice with dough before your starter is ready, try Kenji\u0026rsquo;s No Knead Recipe. It\u0026rsquo;s a good read regardless. That dough is 70% hydration, which is fairly wet but not as wet as the 78% I usually bake. I\u0026rsquo;ve made a ton of TPL\u0026rsquo;s Beginners Sourdough. There\u0026rsquo;s a lot of good sourdough discussion in that article, so I highly recommend that you read it regardless. I also like to make it with a 90:10 white:wheat ratio for a milder loaf. At 90:10 it tastes like really good white bread, with just a touch of extra wheaty flavor from the whole wheat. It\u0026rsquo;s also only very, very mildly sour. Peruse my bread spreadsheet (Breadsheet?). This breadsheet has bakers formulas for most of the stuff I\u0026rsquo;ve made recently. For those of you who are fans of Zingerman\u0026rsquo;s Sesame Semolina, there\u0026rsquo;s a tab in there for you. ","date":"29 March 2020","permalink":"https://brandon.dimcheff.com/recipe/sourdough-starter/","section":"Recipes","summary":"\u003ch2 id=\"creating-a-starter\" class=\"relative group\"\u003eCreating a Starter \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#creating-a-starter\" aria-label=\"Anchor\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003cp\u003eSo how do you get one of these magical starter cultures? You can ask me, and I\u0026rsquo;ll give you part of mine, but there is some satisfaction in doing it yourself. My best suggestion is to head over to \u003ca href=\"https://www.theperfectloaf.com/\" target=\"_blank\" rel=\"noreferrer\"\u003eThe Perfect Loaf\u003c/a\u003e, one of my favorite places to learn about sourdough. Maurizio\u0026rsquo;s stuff is great, and he has a good procedure for \u003ca href=\"https://www.theperfectloaf.com/7-easy-steps-making-incredible-sourdough-starter-scratch/\" target=\"_blank\" rel=\"noreferrer\"\u003estarting a starter\u003c/a\u003e that\u0026rsquo;s pretty much as efficient as possible. Once you have one going, you have to name it. It is the law.\u003c/p\u003e","title":"Sourdough Starters"},{"content":"A little bit of history #I\u0026rsquo;ve been making bread off and on since high school, with varying degrees of success. We had a bread machine during the bread machine craze, which got pretty good use through college. I graduated to no-knead bread in a dutch oven maybe 10 years ago after it got popularized by the New York Times and Cooks Illustrated. All of that bread was fine (certainly better than grocery store bread) but it was never great. The no-knead recipe was a relatively low-effort way of getting fresh-baked bread, but it just became something I did when I needed bread and didn\u0026rsquo;t really think much about it.\nAbout a year ago, I ended up in a medical study (that\u0026rsquo;s a different post) that allowed me to eat somewhere around a half a slice of sandwich bread unless it was sourdough. Well in my opinion, Brandon deserves more than a little bread, as a treat. The trouble is, I don\u0026rsquo;t like sourdough. Or at least I didn\u0026rsquo;t think I liked sourdough. But I\u0026rsquo;d rather eat 2 slices of bread rather than a half of a slice so\u0026hellip; I bought some sourdough from the store. It was meh, as expected. Too sour. Then I wandered into Zingerman\u0026rsquo;s and discovered that the farm bread is actually 100% naturally leavened, aka sourdough. I genuinely like farm bread, so what was going on here? I set on a mission to make some good, not-too-sour sourdough that I was allowed to eat. I ended up getting so much more out of it than that.\nWhat is sourdough, anyways? #Sourdough is just bread that\u0026rsquo;s made with naturally occurring yeast and bacteria instead of commercially produced yeast. At its most basic, it contains only three ingredients: water, flour, and salt. Of course, you have to grow your own little culture of microorganisms in a flour/water slurry, but there\u0026rsquo;s no added yeast.\nAt this point, I\u0026rsquo;ve gotten everything streamlined well enough that it only really takes me 45min of wall time to actually make 2 loaves of bread, assuming I\u0026rsquo;m not trying out a new recipe and everything goes well. I could probably trim it to 30min if I really was ambitious, but I find the process relaxing and I\u0026rsquo;m not trying to be as efficient as possible.\n5min to weigh everything out and do the initial autolyze mix 5-10 min to do the final mix 30s ✖️ 3-4 to stretch and fold the dough 10min to shape 10min to score and bake #BreadThread #First, the fun part! I spent some time over the holidays writing a stream-of-consciousness thread while I was preparing and baking bread. It contains some puns and silliness, but well written it is not.\nBelow is my original #breadthread in all its glory, and here\u0026rsquo;s the unrolled thread, which is probably easier to read. I\u0026rsquo;m bready to answer all your questions, so feel free to ask.\n🎶 dough, a bread, an un-baked bread 🎶 #sourdough #theperfectloaf https://t.co/6RTvFWq4Pf pic.twitter.com/GIrvBGvlf3\n\u0026mdash; brandon aka @bdimcheff@hachyderm.io 🌻 (@bdimcheff) December 21, 2019 Other Sourdough Posts # All about Starters: starting them, maintaining them, talking to them. More to come! In the mean time:\nread The Perfect Loaf read Ken Forkish\u0026rsquo;s Flour, Water, Salt, Yeast. Note that I don\u0026rsquo;t follow the Forkish sourdough instructions, or do the upside-down proofing, but it has good general bread technique. Buy some supplies #Absolutely mandatory #The 3 ingredients that you can\u0026rsquo;t do without:\nFlour: unbleached always. I have King Arthur All Purpose flour, Bread Flour, and Hard Red Winter Whole Wheat around at all times. Some rye is nice from time to time. White rice flour is handy for dusting baskets. Water: don\u0026rsquo;t buy it, but you need water without chlorine, so get a filter or fill a pitcher and leave it overnight. Kosher or sea salt without additives: Diamond Crystal is good. Get fine sea salt, you gotta dissolve this in room temperature water. No iodine! Really quite necessary #You really gotta have these for bread baking, regardless of sourdough or not:\nA scale: You need at least 3kg of capacity to make a decent sized batch. It is extremely hard to bake consistently without a scale. Measuring flour by volume is folly. Get a crappy scale before you decide to go without. Mason jars: I just use wide-mouthed Ball pint jars. Some larger batches of starter might need larger jars (or using a liquid measuring cup). Plastic lids are also handy. Bench knife: for cutting and moving dough. Most doughs are pretty wet, so it\u0026rsquo;s hard to do with your hands. Bulk fermentation container: I use a Cambro 6L. Round and plastic is good. Dutch Oven: You really need a way to steam your bread for the first 20 minutes of cooking if you want it to come out with great crust. A Lodge Combo Cooker is the best solution because you can use it upside down. A regular dutch oven will work in a pinch. You can also steam your oven, but it\u0026rsquo;s a pain in the butt. Optional but great # Lame: You need a really sharp blade to score bread well. You can use a sharp knife in a pinch, but a lame makes it easier. I like this one because it\u0026rsquo;s heavy and easy to switch between straight and curved. Bannetons: These little baskets do a great job cradling your loaves as they proof, and they also impart some cool designs on them if you use them without the liner. The one I linked has real linen liners, which is a plus. Dough proofer: I love my Brod \u0026amp; Taylor proofer. An oven with the light on works in a pinch, but this thing will help with consistency, and won\u0026rsquo;t occupy your oven 24/7. Bowls that fit your bannetons: I have large glass pyrex bowls that my bannetons fit inside entirely. I put plastic wrap on them and stick them in the fridge overnight, which I find more convenient than messing with plastic bags. A plastic container with a lid would also probably work nicely. For more, check out Maurizio\u0026rsquo;s list.\n","date":"28 December 2019","permalink":"https://brandon.dimcheff.com/recipe/bread-thread/","section":"Recipes","summary":"I set on a mission to make some good, not-too-sour sourdough that I was allowed to eat. I ended up getting so much more out of it than that.","title":"#BreadThread"},{"content":"We recently started using go modules at work to handle dependencies. The experience has been mostly great, but unfortunately a lot of tooling hasn\u0026rsquo;t added support for modules. Most of the team uses vscode, which depends on module support in open-source tooling, some of which is incomplete. At the time of writing, refactoring/rename tools don\u0026rsquo;t work, and many of the other tools are very slow when modules are enabled. I wanted to find a way to use modules for dependency management, but use GOPATH for development. It turns out that it\u0026rsquo;s fairly easy to get the best of both worlds if you follow a few simple rules:\nPut your project in GOPATH in the correct location defined by the go.mod file. If your module line specifies foo.com/bar/baz, you need to put your project in $GOPATH/src/foo.com/bar/baz. It\u0026rsquo;s the module line that matters, not the URL to the actual project. Use GOMODULE111=on when you\u0026rsquo;re dealing with dependencies. By default, when you\u0026rsquo;re inside of GOPATH, modules will be disabled. You need to manually enable them in order to add and update dependencies with go mod ... subcommands, or go get. These dependencies are what our builds use, and will be deterministic. One catch: when you alter dependencies with modules, you must run go mod vendor, still with GOMODULE111=on. This will save your dependencies to ./vendor, which will allow non-module-aware tooling to function. A good test to see if things are working correctly: you should be able to open a module-enabled project in vscode and use gorename to change a symbol name.\nPS - We\u0026rsquo;re hiring go folks!\n","date":"6 April 2019","permalink":"https://brandon.dimcheff.com/2019/04/go-modules-the-best-of-both-worlds/","section":"Posts","summary":"\u003cp\u003eWe recently started using go \u003ca href=\"https://github.com/golang/go/wiki/Modules\" target=\"_blank\" rel=\"noreferrer\"\u003emodules\u003c/a\u003e at \u003ca href=\"https://openly.com\" target=\"_blank\" rel=\"noreferrer\"\u003ework\u003c/a\u003e to handle dependencies. The experience has been mostly great, but unfortunately a lot of tooling hasn\u0026rsquo;t added support for modules. Most of the team uses vscode, which depends on \u003ca href=\"https://github.com/Microsoft/vscode-go/wiki/Go-modules-support-in-Visual-Studio-Code\" target=\"_blank\" rel=\"noreferrer\"\u003emodule support\u003c/a\u003e in open-source tooling, some of which is \u003ca href=\"https://github.com/golang/go/issues/24661\" target=\"_blank\" rel=\"noreferrer\"\u003eincomplete\u003c/a\u003e. At the time of writing, refactoring/rename tools don\u0026rsquo;t work, and many of the other tools are very slow when modules are enabled. I wanted to find a way to use modules for dependency management, but use \u003ccode\u003eGOPATH\u003c/code\u003e for development. It turns out that it\u0026rsquo;s fairly easy to get the best of both worlds if you follow a few simple rules:\u003c/p\u003e","title":"Go Modules: The Best of Both Worlds"},{"content":"","date":null,"permalink":"https://brandon.dimcheff.com/tags/golang/","section":"Tags","summary":"","title":"Golang"},{"content":"","date":null,"permalink":"https://brandon.dimcheff.com/tags/modules/","section":"Tags","summary":"","title":"Modules"},{"content":"A little bit of exploration of Linkerd 2.0: quick intro, plus how to use Linkerd to monitor third-party services as if they were your own.\nOrchestructure · Ann Arbor, MI\nSlides Code ","date":"27 February 2019","permalink":"https://brandon.dimcheff.com/talk/orchestructure-linkerd-feb-2019/","section":"Talks","summary":"\u003cp\u003eA little bit of exploration of Linkerd 2.0: quick intro, plus how to use Linkerd to monitor third-party services as if they were your own.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e\u003ca href=\"https://www.meetup.com/orchestructure/events/259159699/\" target=\"_blank\" rel=\"noreferrer\"\u003eOrchestructure\u003c/a\u003e\u003c/strong\u003e · Ann Arbor, MI\u003c/p\u003e","title":"Orchestructure - Linkerd at Openly"},{"content":"","date":null,"permalink":"https://brandon.dimcheff.com/tags/deployment/","section":"Tags","summary":"","title":"Deployment"},{"content":"","date":null,"permalink":"https://brandon.dimcheff.com/tags/kubernetes/","section":"Tags","summary":"","title":"Kubernetes"},{"content":"or: how you can deploy services to Kubernetes that require long periods of draining. #🌈 🌈 🌈 #If you want to jump directly to the technical solution, check out the project repo. Below is a short story about how we got to this solution.\n🌈 🌈 🌈 #In an ideal cloud native world, your services will be stateless so deploys and restarts aren\u0026rsquo;t disruptive. Unfortunately in the real world, sometimes you have stateful services and can\u0026rsquo;t realistically turn them stateless.\nAt Olark, the service that powers chat.olark.com is stateful. Each user\u0026rsquo;s browser establishes a websockets connection to the backend, which in turn establishes an XMPP connection to our XMPP server. If a backend service instance goes away, all the users who have established XMPP connections via that server will be disconnected and will have to reconnect. While that\u0026rsquo;s not the end of the world, it\u0026rsquo;s not a great experience. Also, if it happens to everybody at once, it causes a huge load spike. If we deploy to Kubernetes the traditional way, the rolling deploy will restart all backends, which will cause all logged-in users to reconnect. We had to find a better way.\nThe old way #Before chat.olark.com was running in Kubernetes, we used up, which would fork new workers each time new code was deployed. This is a common idiom for no-downtime deploys in a variety of languages. We could deploy as often as we want, and the old workers could stick around for a couple days to serve the existing XMPP connections. Once the users had (mostly) switched to the new backend, up would clean up the old workers. We couldn\u0026rsquo;t do the same thing inside of a container without a ton of trickery and hacks. Containers are meant to be immutable once they\u0026rsquo;re deployed, and hot-loading code is simply not advised.\nFirst try #Our first attempt to solve this problem was effectively to port \u0026ldquo;the old way\u0026rdquo; to use Kubernetes primitives. We used service-loadbalancer to stick sessions to backends and we turned up the terminationGracePeriodSeconds to several hours. This appeared to work at first, but it turned out that we lost a lot of connections before the client closed the connection. We decided that we were probably relying on behavior that wasn\u0026rsquo;t guaranteed anyways, so we scrapped this plan.\nBlue/Green Deploys #Our second thought was to build a Blue/Green deployment in Kubernetes. It\u0026rsquo;s a fairly common strategy outside of Kube, and isn\u0026rsquo;t that hard to implement. We would have 2 Deployments, lets call them chat-olark-com-blue and chat-olark-com-green. When you want to deploy, you just roll out the least-recently-deployed and switch the Service to point at that Deployment once it\u0026rsquo;s healthy. Rolling back is easy: just switch the service back to the other color. There is a downside: with only two colors, we can only deploy about once per day. It takes 24-48h for connections to naturally burn down, and we don\u0026rsquo;t want to force too many reconnects. This means that every time we use one of the deployments, we need to wait at least a day before we deploy to the other one.\nBut wait! We\u0026rsquo;re in Kubernetes, so lets just make a ton of colors! We have all of ROY-G-BIV to work with here, so lets go crazy. This strategy is fine in principle, but managing a bunch of static deployment colors is cumbersome. Plus, each deployment currently requires 16 pods, so running enough to allow us to deploy 4x/day means we need 8 colors (4 per day, plus a day delay) and we\u0026rsquo;ll be running 128 (2G, 1CPU) pods all the time, even if we only deploy once all week. There\u0026rsquo;s gotta be a better way!\n🌈 Rainbow Deploys 🌈 #It turns out that we were almost there with the original Rainbow Deploy idea. The key was simple: instead of using fixed colors, we used git hashes. Instead of a Deployment called chat-olark-com-$COLOR we deploy chat-olark-com-$SHA. As a bonus, since the first six characters of a git sha are also a valid hex color, the name still makes sense. You might even find a new favorite color!\nUsing this technique, a deploy goes like this:\nCreate a new deployment with the pattern chat-olark-com-$NEW_SHA. When the pods are ready, switch the service to point at chat-olark-com-$NEW_SHA. If you need to roll back, point the service back at chat-olark-com-$OLD_SHA. Once connections have burned down, delete the old deployment. Any of the (few) remaining users will reconnect to a newer backend. I made a demo repo to showcase how this works.\nWe\u0026rsquo;ve been deploying chat.olark.com this way since June, 2017 via Gitlab pipelines. This deployment strategy has been far easier to use and far more reliable than our previous deployments. One day we will hopefully be able to avoid connection draining, but this has proved to be a step in the right direction.\nClean up #We still have one unsolved issue with this deployment strategy: how to clean up the old deployments when they\u0026rsquo;re no longer serving (much) traffic. So far we haven\u0026rsquo;t found a good way of detecting a lightly used deployment, so we\u0026rsquo;ve been cleaning them up manually every once in a while. The idea is to wait until the number of connections are low enough that it will be minimally disruptive. It would be nice to automate this, but it\u0026rsquo;s actually somewhat difficult to detect when the time is right. Hopefully this will be a future post.\nThe future #I would love to see something like this end up as a native Deployment Strategy. It ought to be possible to make an Immutable deployment method where pods only get created but the old ones aren\u0026rsquo;t destroyed immediately. It\u0026rsquo;d be even better if there were some way to define when old pods would be cleaned up. A lifecycle hook or signal may suffice here, to indicate to the pod when it\u0026rsquo;s no longer receiving production traffic and should shut down when ready.\n🌈 #","date":"13 February 2018","permalink":"https://brandon.dimcheff.com/2018/02/rainbow-deploys-with-kubernetes/","section":"Posts","summary":"\u003ch2 id=\"or-how-you-can-deploy-services-to-kubernetes-that-require-long-periods-of-draining\" class=\"relative group\"\u003eor: how you can deploy services to Kubernetes that require long periods of draining. \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#or-how-you-can-deploy-services-to-kubernetes-that-require-long-periods-of-draining\" aria-label=\"Anchor\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h2\u003e\u003ch1 id=\"127752-127752-127752\" class=\"relative group\"\u003e🌈 🌈 🌈 \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#127752-127752-127752\" aria-label=\"Anchor\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h1\u003e\u003cp\u003eIf you want to jump directly to the technical solution, check out the \u003ca href=\"https://github.com/bdimcheff/rainbow-deploys\" target=\"_blank\" rel=\"noreferrer\"\u003eproject repo\u003c/a\u003e.  Below is a short story about how we got to this solution.\u003c/p\u003e","title":"Rainbow Deploys with Kubernetes"},{"content":"","date":null,"permalink":"https://brandon.dimcheff.com/tags/cheap/","section":"Tags","summary":"","title":"Cheap"},{"content":"This is a modified version of a recipe from Hip Pressure Cooking that I make quite frequently. It\u0026rsquo;s pretty fast and very cheap. I recommend an Instant Pot IP-DUO80 if you don\u0026rsquo;t have a pressure cooker. You can probably only fit 8 legs in a 6-quart cooker, but an 8 quart should hold 12.\nIngredients # 1 T olive oil 1 onion, chopped 1 T tomato paste 1 clove garlic, minced 1 bay leaf 1.5 T kosher salt 1/2 t dried thyme or a couple sprigs fresh 1/2 cup water (or your pressure cooker\u0026rsquo;s minimum required liquid amount) 8-12 bone-in, skin-on dark meat chicken pieces (about 2-3lb) 2 cups (340g) basmati rice Method # Heat oil on high saute mode until shimmering. Add onion and cook for a few minutes until softened but not browned. Add garlic and cook, stirring constantly, for 30 seconds until fragrant. Add tomato paste and cook, stirring constantly, for 30 seconds until fragrant and beginning to caramelize a little. Turn off pressure cooker, add 1/2 cup water, and scrape up any browned bits. Add bay leaf, thyme, chicken, and salt, and mix everything around a bit and then nestle the chicken down into the pot. Try to get a fair amount of salt onto the chicken itself. Set the pressure cooker for 9 minutes on high and secure the lid. After the time is up, let the pressure cooker sit for 5 additional minutes and then release the remaining pressure. Remove the chicken pieces to a plate and tent with foil. Pour the liquid in the pot into a 1-quart measuring cup. Add water until the line between the water and fat is at the 3 cup line. Don\u0026rsquo;t skim the fat off :-o Return the liquids to the pot and add the rice. Set the cooker for high for 2 minutes. Once the timer is up, let the pressure release for at least 10 minutes, then release the remaining pressure and remove the lid. Stir a few times gently, then serve with the chicken. ","date":"13 November 2017","permalink":"https://brandon.dimcheff.com/recipe/pressure-cooker-chicken-and-rice/","section":"Recipes","summary":"\u003cp\u003eThis is a modified version of a \u003ca href=\"https://www.hippressurecooking.com/pressure-cooker-chicken-and-rice-one-pot-meal/\" target=\"_blank\" rel=\"noreferrer\"\u003erecipe\u003c/a\u003e from Hip Pressure Cooking that I make quite frequently.  It\u0026rsquo;s pretty fast and \u003cem\u003every\u003c/em\u003e cheap.  I recommend an \u003ca href=\"http://amzn.to/2yzkplO\" target=\"_blank\" rel=\"noreferrer\"\u003eInstant Pot IP-DUO80\u003c/a\u003e if you don\u0026rsquo;t have a pressure cooker.  You can probably only fit 8 legs in a 6-quart cooker, but an 8 quart should hold 12.\u003c/p\u003e","title":"Pressure Cooker Chicken and Rice"},{"content":"","date":null,"permalink":"https://brandon.dimcheff.com/tags/rice/","section":"Tags","summary":"","title":"Rice"},{"content":"","date":null,"permalink":"https://brandon.dimcheff.com/tags/bellpepper/","section":"Tags","summary":"","title":"Bellpepper"},{"content":"This recipe is a common quick dinner for us. It\u0026rsquo;s quite easy if you have an electric pressure cooker. It\u0026rsquo;s adapted from a recipe from Cooks Illustrated. You can use any sort of non-strand pasta for this, like shells, ziti, rigatoni, etc. Spaghetti and strand pasta will create a disaster.\nWhy Mr. Snausage II? Mr. Snausage I was the older recipe I used, but this one is easier. I\u0026rsquo;ll post the other one eventually.\nSpecial Equipment #I make this in my 8 quart Instant Pot IP-DUO80, but it should work in a 6 quart also.\nIngredients # 1 T olive oil 1 lb sweet (or hot if you want it spicy) Italian sausage, casings removed 1 onion, chopped fine 2 bell peppers, stemmed, seeded, and cut into 3/4-inch pieces 1 (25 oz) jar tomato sauce 1 jar plus 1/2 c water 1 lb large shell pasta (or another pasta you prefer) 2 T chopped fresh basil 4 oz mozzarella cheese, shredded Salt and pepper Method # Heat 1T olive oil in your pressure cooker until shimmering. Add sausage, onion, bell pepper, and 2t kosher salt. Cook, breaking up sausage into 1/4\u0026quot; pieces with a wooden spoon, until the sausage isn\u0026rsquo;t pink anymore. Add jar of pasta sauce, refill it with water and add the water as well, using the water to rinse the remainder of the sauce out of the jar, plus an extra 1/2 cup of water. Add the pasta and mix well. Set the pressure cooker for 5 minutes on high, and seal the pot. I frequently take the lid off and stir once before the mixture starts boiling too much, just to make sure it doesn\u0026rsquo;t stick. Once the timer finishes, quick release your pressure cooker. Remove the lid and stir for a couple minutes to unstick the pasta and thicken the sauce. Add chopped basil and shredded cheese, stirring gently to melt the cheese into a creamy sauce. Serve. Leftovers #This actually reheats relatively well. The pasta gets a little bit soft, but there\u0026rsquo;s not much you can do about that. Just add a couple teaspoons of water per serving and microwave it, stirring a couple times, until hot.\n","date":"12 November 2017","permalink":"https://brandon.dimcheff.com/recipe/mr-snausage-ii/","section":"Recipes","summary":"\u003cp\u003eThis recipe is a common quick dinner for us.  It\u0026rsquo;s quite easy if you have an electric pressure cooker.  It\u0026rsquo;s adapted from a \u003ca href=\"https://www.cooksillustrated.com/recipes/7536-pressure-cooker-easy-ziti-with-sausage-and-peppers\" target=\"_blank\" rel=\"noreferrer\"\u003erecipe\u003c/a\u003e from Cooks Illustrated.  You can use any sort of non-strand pasta for this, like shells, ziti, rigatoni, etc.  Spaghetti and strand pasta will create a disaster.\u003c/p\u003e","title":"Mr. Snausage II"},{"content":"","date":null,"permalink":"https://brandon.dimcheff.com/tags/pasta/","section":"Tags","summary":"","title":"Pasta"},{"content":"","date":null,"permalink":"https://brandon.dimcheff.com/tags/sausage/","section":"Tags","summary":"","title":"Sausage"},{"content":"","date":null,"permalink":"https://brandon.dimcheff.com/tags/breakfast/","section":"Tags","summary":"","title":"Breakfast"},{"content":"This is the family recipe we\u0026rsquo;ve been using since I was a child. This will make approximately 6 large pancackes, or 12 small ones. Nana used to let me eat the butter when my mom wasn\u0026rsquo;t watching, which I also highly recommend.\nNote: Do not flip the pancakes more than once. Do not whack them with your spatula. Do not shake the pan around. You just spent a lot of time beating some egg whites so the pancakes are light and fluffy. Don\u0026rsquo;t ruin it.\nIngredients # 2c (9oz) all purpose flour 1T sugar 0.5t salt 2t baking soda 2.5c buttermilk 2 eggs, separated 1T melted butter 0.5t vanilla extract Method # Mix dry ingredients together in a bowl Put buttermilk, egg yolks, vegetable oil, and vanilla into a separate bowl. Whisk until well mixed. Beat egg whites until stiff Add buttermilk mixture to dry ingredients. Mix with whisk until just incorporated. It is ok if a few lumps still exist. Overmixing will make the pancakes tough. Fold stiff egg whites into batter until just incorporated. It is ok if a few blobs of egg white still remain unincorporated. Preheat heavy bottomed (I use cast iron) skillet over medium heat. Spray skillet with cooking spray or grease with a little butter. Ladle approximately 1/2c of batter onto the skillet. Distribute the batter with the back of a ladle moving in a circular motion until the pancake is about 6 inches around. Reduce heat to medium-low and cook for 2-4 minutes, until the edges of the pancake is set and at least one bubble that has formed leaves a small hole in the pancake when it pops. Flip with a wide spatula. Cook for another 1-2 minutes, until the bottom is golden brown. Serve with your favorite pancake topping. I like a mixture of apple butter and maple syrup. ","date":"12 November 2017","permalink":"https://brandon.dimcheff.com/recipe/nanas-pancakes/","section":"Recipes","summary":"\u003cp\u003eThis is the family recipe we\u0026rsquo;ve been using since I was a child.  This will make approximately 6 large pancackes, or 12 small ones.  Nana used to let me eat the butter when my mom wasn\u0026rsquo;t watching, which I also highly recommend.\u003c/p\u003e","title":"Nana's Pancakes"},{"content":"Well, it\u0026rsquo;s been more than 7 years since I\u0026rsquo;ve blogged, but I\u0026rsquo;ve collected a pretty large list of topics. But first, some people and and projects deserve credit for my fancy new site. Stay tuned for actual content.\nHugo #I\u0026rsquo;ve been doing a fair amount of work with go lately, primarily due to increasing use of Kubernetes. Since Hugo is written in go and we\u0026rsquo;re using it for our website at Olark, I thought it would be a good excuse to check it out.\nAcademic Theme #Since I\u0026rsquo;m a bad designer, I needed to use an off-the-shelf theme. Hugo has a lot of themes available, and I settled on the Academic theme. It\u0026rsquo;s a nice combination of a single-page homepage with a bio and sections for portfolio items, but also includes separate pages for each subsection.\nGCS Deploy #I stole my GCS deploy from this blog post, and added gsutil rsync functionality.\n.PHONY: all clean watch help deploy HUGO := hugo GSUTIL := gsutil WEBSITE_URL := brandon.dimcheff.com # All input files FILES=$(shell find content layouts static themes -type f) # Below are PHONY targets all: public help: @echo \u0026#34;Usage: make \u0026lt;command\u0026gt;\u0026#34; @echo \u0026#34; all Builds the blog and minifies it\u0026#34; @echo \u0026#34; clean Cleans all build files\u0026#34; @echo \u0026#34; watch Runs hugo in watch mode, waiting for changes\u0026#34; @echo \u0026#34;\u0026#34; @echo \u0026#34;New article:\u0026#34; @echo \u0026#34; hugo [-k kind] new post/the_title\u0026#34; @echo \u0026#34; $$EDITOR content/post/the_title.md\u0026#34; @echo \u0026#34; make watch\u0026#34; @echo \u0026#34; open \u0026#34; clean: -rm -rf public watch: clean $(HUGO) server -w # Below are file based targets public: $(FILES) config.toml $(HUGO) # process files here if necessary # Ensure the public folder has it\u0026#39;s mtime updated. touch $@ deploy: public $(GSUTIL) -m rsync -R public gs://$(WEBSITE_URL) ","date":"16 October 2017","permalink":"https://brandon.dimcheff.com/2017/10/hello-again/","section":"Posts","summary":"\u003cp\u003eWell, it\u0026rsquo;s been more than 7 years since I\u0026rsquo;ve blogged, but I\u0026rsquo;ve collected a pretty large list of topics.  But first, some people and and projects deserve credit for my fancy new site.  Stay tuned for actual content.\u003c/p\u003e","title":"hello again"},{"content":"","date":null,"permalink":"https://brandon.dimcheff.com/tags/hugo/","section":"Tags","summary":"","title":"Hugo"},{"content":"","date":null,"permalink":"https://brandon.dimcheff.com/posts/","section":"Posts","summary":"","title":"Posts"},{"content":"","date":null,"permalink":"https://brandon.dimcheff.com/talk/","section":"Talks","summary":"","title":"Talks"},{"content":"When you start building new infrastructure from scratch, it’s relatively easy to take into account the constraints that Docker and Kubernetes impose. Unfortunately most of us aren’t starting brand new projects, but are maintaining and migrating legacy infrastructure that may not be well suited to run on Kubernetes. Over the past several months, Olark has migrated a number of services that were never designed with Kubernetes or Docker in mind from over 200 puppet-managed Ubuntu VMs to Google Container Engine. Brandon will share some of Olark’s successes and failures, so that hopefully you can have a good starting point and avoid making the same mistakes that they did. He’ll also answer some questions like: How can I set up DNS and VPN so that I can route between my legacy infrastructure and Kubernetes services? I have a stateful application, can (or should) I still use Kubernetes? What are some things I can do to reduce the risk involved in a large-scale migration?\nKubeCon · Seattle, WA\nSlides (PDF) ","date":"9 November 2016","permalink":"https://brandon.dimcheff.com/talk/migrating-to-kubernetes/","section":"Talks","summary":"\u003cp\u003eWhen you start building new infrastructure from scratch, it’s relatively easy to take into account the constraints that Docker and Kubernetes impose. Unfortunately most of us aren’t starting brand new projects, but are maintaining and migrating legacy infrastructure that may not be well suited to run on Kubernetes. Over the past several months, Olark has migrated a number of services that were never designed with Kubernetes or Docker in mind from over 200 puppet-managed Ubuntu VMs to Google Container Engine. Brandon will share some of Olark’s successes and failures, so that hopefully you can have a good starting point and avoid making the same mistakes that they did. He’ll also answer some questions like: How can I set up DNS and VPN so that I can route between my legacy infrastructure and Kubernetes services? I have a stateful application, can (or should) I still use Kubernetes? What are some things I can do to reduce the risk involved in a large-scale migration?\u003c/p\u003e","title":"Migrating Legacy Infrastructure to Kubernetes: Olark's Lessons From the Trenches"},{"content":"Motivations #I spent some time hacking around in Chrome the other day because I have been extremely frustrated with the behavior of the downloads bar in the Mac version of Chrome. When the user initiates a download, it appends the downloads bar to the bottom of your current window, causing your window to grow by the height of the download bar.\nThis behavior really bothers me, since I have my window set up with about 10px of padding around all sides so I can easily see my IM window and other things that I have docked to the top/side of my desktop. When Chrome grows the window, I have to manually shrink it and then scoot the window away from the title bar again. Then, when I close the downloads tab, I need to make the window bigger so there isn\u0026rsquo;t an enormous gap below the browser window.\nI submitted a bug report about this issue, but a member of the Chrome team explains that they consider this to be the correct behavior:\nThis is by design, as we do not want to change the size of the web content. We do attempt to restore the original window size when you close the download shelf, although that logic seems to break at times (see Issue 39266).\nIf that\u0026rsquo;s their position, then fine, though it does contradict other behavior of Chrome\u0026rsquo;s. Chrome will, for instance, not enlarge the window when they display the \u0026ldquo;do you want Chrome to remember your password\u0026rdquo; alert bar and other similar things. It simply pushes the content down a small amount and then pulls it back up when you close the alert. This is far preferable to me over messing with the size of my window.\nThe Fix #Well, Chrome is open source, so I decided that if they won\u0026rsquo;t fix it, I would. At least for my build, anyways. Turns out that it\u0026rsquo;s a one-line patch to a single controller file. Here they check to see if the view that\u0026rsquo;s initiating a redraw is the download shelf or the bookmark bar. If it is, they add the height to the view to the window. In this case, I just removed the condition for the download shelf and voila!\nHow I built Chrome #Hopefully I can save you some time if you\u0026rsquo;d like to perform similar surgery to your copy of Chrome. It took me a few tries to get everything right, due to some incorrect documentation and the enormous size of the Chrome checkout. Naturally I want to use git, since it\u0026rsquo;ll make my patch sets so much easier to maintain. These instructions show you how to build a specific release version with your patches using git. This assumes you\u0026rsquo;re building 5.0.375.17. Substitute a different version if you\u0026rsquo;d like.\nFollow the Chrome Git instructions steps 1-3. You\u0026rsquo;ll need to install depot tools as indicated in step 2. Instead of using the URL specified in step 4, use http://src.chromium.org/svn/releases/5.0.375.17, or another version of your choice. cd into ./src git config --add svn-remote.375.url http://src.chromium.org/svn/branches/375/src git config --add svn-remote.375.fetch :refs/remotes/375 git svn fetch 375 (this fetches branch 375 into your local git repo) Look in http://src.chromium.org/svn/releases/5.0.375.17/DEPS and find in the deps dict where there is src alone. In this case, the value is /branches/375/src@45275. This means that version 375.17 is svn commit 45275. Remember that number. git checkout refs/remotes/375 git log and search for 45275. Once you find the commit, note the git sha hash. In this case, it is 1bb2782587c269be10f842a468e2d26b38003daa. git checkout -b 375.17 1bb2782587c269be10f842a468e2d26b38003daa (make a checkout of the exact version of the release) Do steps 5-6 of the Chrome git instructions. Apply your patches You now have a specific version of Chrome and all its dependencies checked out and ready to build. You can now follow the Mac OS X build instructions, or just open src/chrome/chrome.xcodeproj and choose \u0026ldquo;chrome\u0026rdquo; from the build menu in the upper left. Choose \u0026ldquo;Release\u0026rdquo; if you want to build Chrome for actual use. Note that this took over an hour on my fancy new i7 MacBook Pro with 4GB of RAM. It also used enough resources that my computer was nearly unusable for part of the compile.\nChrome Build Process #A few notes about the Chrome build process: The git repo stores only the code for the browser itself. General libraries, both Google internal and external, are fetched by using the gclient sync command. This is somewhat similar to git submodules, in that it allows Google to pin specific revisions of dependencies to a release. The DEPS file stores all the revisions of the external repositories that are necessary to duplicate a build. The tricky part was to make sure that the git checkout and the dependencies both corresponded to the same release version.\nI haven\u0026rsquo;t yet had to switch my build to use a different release. As soon as that happens, I will update this page to give instructions on how to do so.\nDownload #If you\u0026rsquo;d like, you can download a copy of the current dev channel of Chromium with my fix applied. Or you can follow the instructions above and patch it yourself.\nThe Future #The Chrome guys are working on eliminating the http:// scheme from standard HTTP urls. It turns out that this caused a lot of bugs when they released it into the dev channel so they reverted the change, but they have said that they will eventually revive this \u0026ldquo;feature\u0026rdquo;. I found it really annoying and my custom chrome build will likely do away with http hiding once it becomes part of Chrome. I\u0026rsquo;m happy to work with someone who\u0026rsquo;s also annoyed by this to set up an automatic build to release a new dev channel build with custom patches to fix some of these \u0026ldquo;features\u0026rdquo;\u0026hellip; Let me know.\n","date":"24 April 2010","permalink":"https://brandon.dimcheff.com/2010/04/24/hacking-chrome/","section":"Posts","summary":"\u003ch3 id=\"motivations\" class=\"relative group\"\u003eMotivations \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#motivations\" aria-label=\"Anchor\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h3\u003e\u003cp\u003eI spent some time hacking around in Chrome the other day because I have been extremely frustrated with the behavior of the downloads bar in the Mac version of Chrome.  When the user initiates a download, it appends the downloads bar to the bottom of your current window, causing your window to grow by the height of the download bar.\u003c/p\u003e","title":"Hacking Chrome with Git"},{"content":" John Roos of Roos Roast designed an excellent blend of coffee for Great Lakes Ruby Bash. John started Roos Roast while selling cars at Dunning Subaru. I met him there when I bought my WRX, when he gave me a free pound of coffee with my car. Not long after that, he quit selling cars and started roasting coffee full-time.\nWe have enough coffee to make 300 cups during the conference, plus we have 6 half-pound bags of coffee to raffle off for the attendees.\nHuge thanks to John for doing this for us. If there\u0026rsquo;s enough demand, he might be convinced to roast more batches. Call him up or stop by his roasting operation and demand some Ruby Brew!\nIf you\u0026rsquo;re not in the Ann Arbor area, you can order his coffee by phone or online.\nWorking on this project with John was a lot of fun. I watched as he carved the Ruby Brew logo into a rubber stamp block. He also put me to work a bit. I stamped 300 of our cups, and weighed and ground our coffee for the conference.\nThanks, John!\n","date":"17 April 2010","permalink":"https://brandon.dimcheff.com/2010/04/17/ruby-brew-at-great-lakes-ruby-bash/","section":"Posts","summary":"\u003cp\u003e\u003cspan style=\"margin:0 10px; float:right\"\u003e\u003cimg src=\"/images/ruby_brew.jpg\" width=\"240\" height=\"160\" alt=\"ruby brew\" /\u003e\u003c/span\u003e\nJohn Roos of \u003ca href=\"http://roosroast.com\" target=\"_blank\" rel=\"noreferrer\"\u003eRoos Roast\u003c/a\u003e designed an excellent blend of coffee for Great Lakes Ruby Bash.  John started Roos Roast while selling cars at Dunning Subaru.  I met him there when I bought my WRX, when he gave me a free pound of coffee with my car.  Not long after that, he quit selling cars and started roasting coffee full-time.\u003c/p\u003e","title":"Ruby Brew at Great Lakes Ruby Bash"},{"content":"Ruby\u0026rsquo;s Array has 2 methods for sorting: sort and sort_by. Both methods sort your array (obviously) but they do it in slightly different ways.\nBackground #This article is based on a talk I gave at the Ann Arbor Ruby Brigade in August. The idea for this talk was conjured up at eRubyCon during a discussion between Gayle Craig and me. We decided we would each give a brief talk about the differences between sort and sort_by at our next user group meetings. Amazingly, we both followed through.\nsort #A Ruby array\u0026rsquo;s sort method is pretty straightforward. If called without a block, it uses each objects\u0026rsquo; comparison operator (\u0026lt;=\u0026gt;) to return a new array with all the elements sorted. If called with a block, you may specify your own comparator as shown below:\n[1, 4, 3, 7, 2, 9].sort # =\u0026gt; [1, 2, 3, 4, 7, 9] [1, 4, 3, 7, 2, 9].sort {|a, b| b \u0026lt;=\u0026gt; a} # =\u0026gt; [9, 7, 4, 3, 2, 1] Note that the block for sort accepts two parameters. The return value of the block must be -1, 0, or 1. -1 indicates that the first item is less than the second, 0 indicates they are equal, and 1 indicates that the first item is greater than the second one.\nsort_by #The sort_by method is slightly different. Its block only takes one parameter instead of two. Your array is then sorted by the results of each of the block calls. For example:\n[1, 4, 3, 7, 2, 9].sort_by {|i| -i} # =\u0026gt; [9, 7, 4, 3, 2, 1] %w{ abcd ab abc abcde }.sort_by {|i| i.length} # =\u0026gt; [\u0026#34;ab\u0026#34;, \u0026#34;abc\u0026#34;, \u0026#34;abcd\u0026#34;, \u0026#34;abcde\u0026#34;] This is accomplished using something called a Schwartzian Transform.\nThe Schwartzian Transform #All a schwartzian transform does is turn each record of your array into a tuple with the first element being the item on which you wish to sort. That array of tuples is then sorted. Since the first item in the tuple gets precedence, it is effectively the same as sorting the array by the results of the sort_by block. Once sorted, the first element of the tuple is removed, leaving your original array in sorted order. Below is an example implementation in pure ruby:\nmodule Enumerable # This is essentially the implementation of sort_by # It\u0026#39;s written in C in MRI, so it\u0026#39;s a little faster def my_sort_by self.map {|i| [yield(i), i]}.sort.map {|j| j[1]} end end Why choose one over the other? #If you\u0026rsquo;re sorting a small array, it really doesn\u0026rsquo;t matter which sort method you choose. Use whichever is easiest to code and understand. For larger arrays, however, the performance differences between sort and sort_by can be substantial.\nYou generally want to use sort_by over sort whenever comparisons are relatively expensive. Note that in Ruby, method dispatch is often enough to count as an expensive comparison. Unless you\u0026rsquo;re sorting things that end up as C primitives in MRI (like an Integer) you\u0026rsquo;ll likely want to use sort_by.\nThe performance varies so greatly because of the Schwartzian Transform. Using sort, each pairwise comparison that must be performed calls the \u0026lt;=\u0026gt; operator. In the case of sort_by, the comparison \u0026ldquo;calculation\u0026rdquo; is only done once at the beginning, and then the array is sorted on an Integer primitive much more quickly.\nI hope this was helpful to someone. It\u0026rsquo;s probably more than anyone has written on the difference between these two methods.\n","date":"18 November 2009","permalink":"https://brandon.dimcheff.com/2009/11/18/rubys-sort-vs-sort-by/","section":"Posts","summary":"\u003cp\u003eRuby\u0026rsquo;s Array has 2 methods for sorting: \u003ccode\u003esort\u003c/code\u003e and \u003ccode\u003esort_by\u003c/code\u003e.  Both\nmethods sort your array (obviously) but they do it in slightly different ways.\u003c/p\u003e\n\u003ch3 id=\"background\" class=\"relative group\"\u003eBackground \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#background\" aria-label=\"Anchor\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h3\u003e\u003cp\u003eThis article is based on a talk I gave at the \u003ca href=\"http://a2rb.org\" target=\"_blank\" rel=\"noreferrer\"\u003eAnn Arbor Ruby\nBrigade\u003c/a\u003e in August.  The idea for this talk was\nconjured up at \u003ca href=\"http://erubycon.com\" target=\"_blank\" rel=\"noreferrer\"\u003eeRubyCon\u003c/a\u003e during a discussion\nbetween \u003ca href=\"http://gayleforce.wordpress.com\" target=\"_blank\" rel=\"noreferrer\"\u003eGayle Craig\u003c/a\u003e and me.  We\ndecided we would each give a brief talk about the differences between\n\u003ccode\u003esort\u003c/code\u003e and \u003ccode\u003esort_by\u003c/code\u003e at our next user group meetings.  Amazingly, we\nboth followed through.\u003c/p\u003e","title":"Method of the Month 1:  Ruby's sort vs. sort_by"},{"content":"Introduction #In a duck-typed language like Ruby, it\u0026rsquo;s very important that you actually use duck typing. This is especially important when you\u0026rsquo;re designing a library or other code that could interact with objects that you don\u0026rsquo;t control. I have come across a few libraries lately that don\u0026rsquo;t follow duck typing conventions and have caused unexpected behavior when I\u0026rsquo;ve used them.\nIn this article, I\u0026rsquo;m going to pick on Shoulda. Thoughtbots, please do not take offense! I\u0026rsquo;m a fan, and I figured you guys could take it.\nDuck Typing # Before I get into the details, I\u0026rsquo;ll say a word or two about duck typing for those who may need a refresher. The principle of duck typing basically says that if something \u0026ldquo;walks like a duck and talks like a duck\u0026rdquo; it probably is a duck. What this really means is that when you\u0026rsquo;re interacting with other objects, you should not care what they are, but rather how they behave. If you have an object that responds to #each, who cares if it\u0026rsquo;s an Array or Set or a custom collection?\nImplementing Duck Typing #You should rarely ever use #is_a? on an object. You should be using #respond_to? instead. The whole point in duck typing is that you don\u0026rsquo;t care what kind of object you\u0026rsquo;ve received. The only thing you care about is that the object does what you want it to do. Let me show you an example from Shoulda.\nThe following code is from lib/shoulda/assertions.rb in Shoulda\u0026rsquo;s git repository. assert_contains is a custom assertion for Shoulda that allows you to easily test a collection for the presence of a particular element.\ndef assert_contains(collection, x, extra_msg = \u0026#34;\u0026#34;) collection = [collection] unless collection.is_a?(Array) msg = \u0026#34;#{x.inspect} not found in #{collection.to_a.inspect} #{extra_msg}\u0026#34; case x when Regexp assert(collection.detect { |e| e =~ x }, msg) else assert(collection.include?(x), msg) end end If you look at the first line of the method definition, you\u0026rsquo;ll notice that they are calling is_a?(Array) on the \u0026ldquo;collection\u0026rdquo; this is passed into the function. The code I was writing was using a Set instead of an Array. The trouble is, if you pass anything other than an array, that line will wrap whatever you passed in an array. So I ended up with an Array with a Set inside of it, which caused the rest of the assertion code to fail.\nThe solution to this problem is very easy. If you look at my fork, all I\u0026rsquo;ve done is change that one line (and add some tests, of course). Now we only wrap the collection in an array if it doesn\u0026rsquo;t respond to include?. It\u0026rsquo;ll work with an Array still. It\u0026rsquo;ll work with a Set. It\u0026rsquo;ll work with your custom data structure that can detect the presence of objects. That\u0026rsquo;s the power of duck typing.\ndef assert_contains(collection, x, extra_msg = \u0026#34;\u0026#34;) collection = [collection] unless collection.respond_to? :include? msg = \u0026#34;#{x.inspect} not found in #{collection.to_a.inspect} #{extra_msg}\u0026#34; case x when Regexp assert(collection.detect { |e| e =~ x }, msg) else assert(collection.include?(x), msg) end end Conclusion #Whenever you\u0026rsquo;re checking for an actual class of an object rather than examining how it behaves, take a second to think if you can duck type it instead. It will make your code more generic, and make it easier for others to use.\nAgain, thank you to Thoughtbot for Shoulda and I\u0026rsquo;m sorry I singled you out. Shoulda is great, and just happened to be in the wrong place at the wrong time for me to start a rant about duck typing.\n","date":"7 April 2009","permalink":"https://brandon.dimcheff.com/2009/04/07/walk-like-a-duck/","section":"Posts","summary":"\u003ch3 id=\"introduction\" class=\"relative group\"\u003eIntroduction \u003cspan class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100\"\u003e\u003ca class=\"group-hover:text-primary-300 dark:group-hover:text-neutral-700\" style=\"text-decoration-line: none !important;\" href=\"#introduction\" aria-label=\"Anchor\"\u003e#\u003c/a\u003e\u003c/span\u003e\u003c/h3\u003e\u003cp\u003eIn a \u003ca href=\"http://en.wikipedia.org/wiki/Duck_typing\" target=\"_blank\" rel=\"noreferrer\"\u003educk-typed\u003c/a\u003e language like Ruby, it\u0026rsquo;s very important that you actually use duck typing.  This is especially important when you\u0026rsquo;re designing a library or other code that could interact with objects that you don\u0026rsquo;t control.  I have come across a few libraries lately that don\u0026rsquo;t follow duck typing conventions and have caused unexpected behavior when I\u0026rsquo;ve used them.\u003c/p\u003e","title":"Walk Like a Duck"},{"content":"Recently I was adding new user registration to tasteb.in and I wanted my users to be automatically logged in as soon as they created their account. I\u0026rsquo;m using merb for tasteb.in, and consequently merb-auth for authentication. It turns out it\u0026rsquo;s really easy to implement, but it took me a while to get it right. All you need to do is add the following to your action that creates the new user:\nsession.user = @user That\u0026rsquo;s it. All you must do is set the user in the session to the newly created user. I hope this saves somebody else some time.\n","date":"17 March 2009","permalink":"https://brandon.dimcheff.com/2009/03/17/automatically-log-in-on-merb-auth-account-creation/","section":"Posts","summary":"\u003cp\u003eRecently I was adding new user registration to \u003ca href=\"http://tasteb.in\" target=\"_blank\" rel=\"noreferrer\"\u003etasteb.in\u003c/a\u003e and I wanted my users to be automatically logged in as soon as they created their account.  I\u0026rsquo;m using merb for tasteb.in, and consequently merb-auth for authentication.  It turns out it\u0026rsquo;s really easy to implement, but it took me a while to get it right.  All you need to do is add the following to your action that creates the new user:\u003c/p\u003e","title":"Automatically log in on merb-auth account creation"},{"content":"I had a bit of trouble with Disqus where it would only display a link saying \u0026ldquo;Discuss this topic on Disqus\u0026rdquo; instead of displaying an actual comment form. It turns out that this problem was caused by a mismatch between the URL configured in Disqus and the url where my blog was actually accessible. So if you\u0026rsquo;re missing a Disqus comment form, make sure that the URL listed under Settings -\u0026gt; Website URL in Disqus is the actual URL where your site resides.\n","date":"4 March 2009","permalink":"https://brandon.dimcheff.com/2009/03/04/fix-missing-disqus/","section":"Posts","summary":"\u003cp\u003eI had a bit of trouble with Disqus where it would only display a link saying \u0026ldquo;Discuss this topic on Disqus\u0026rdquo; instead of displaying an actual comment form.  It turns out that this problem was caused by a mismatch between the URL configured in Disqus and the url where my blog was actually accessible.  So if you\u0026rsquo;re missing a Disqus comment form, make sure that the URL listed under Settings -\u0026gt; Website URL in Disqus is the actual URL where your site resides.\u003c/p\u003e","title":"Fix Missing Disqus Comment Form"},{"content":"I\u0026rsquo;ve been working on a Merb-based recipe paste site for the past couple weeks called tasteb.in. It\u0026rsquo;s extremely simple for now. It lets you paste recipes in a very simple format and they show up on the site. You can access your recipes and all recipes on the site. And that\u0026rsquo;s about it.\nI\u0026rsquo;ll be going into more details about how tasteb.in is built and where I\u0026rsquo;d like to take the site, but for now, just play with it if you like. Drop me a line with any problems you have, or features you would like to see.\n","date":"1 March 2009","permalink":"https://brandon.dimcheff.com/2009/03/01/tasteb-in-is-up/","section":"Posts","summary":"\u003cp\u003eI\u0026rsquo;ve been working on a Merb-based recipe paste site for the past couple weeks called \u003ca href=\"http://tasteb.in\" target=\"_blank\" rel=\"noreferrer\"\u003etasteb.in\u003c/a\u003e.  It\u0026rsquo;s extremely simple for now.  It lets you paste recipes in a very simple format and they show up on the site.  You can access your recipes and all recipes on the site.  And that\u0026rsquo;s about it.\u003c/p\u003e","title":"tasteb.in is up!"},{"content":"I needed to test some code that reads and writes files on the filesystem. I got sick of manually setting up a scratch area for my test files and cleaning them up when I was done, so I created Sandbox to keep my tests DRY.\nSee the Sandbox readme for more information, but the basic idea is this:\n# inside a test somewhere Sandbox.play do |path| file = File.join(path, \u0026#39;foo\u0026#39;) FileUtils.touch(file) # build a sand castle assert File.exists?(file) # test whatever you want in here end assert !File.exists?(file) # path has been deleted The project is currently only on github, but it will be on RubyForge once approved. If you want to use it now, you have to use the github gems source or install it from source.\nFuture plans # Optionally Dir.chdir to the temporary directory for even easier usage Supply a template directory/archive to be used for the base state of the sandbox ","date":"14 February 2009","permalink":"https://brandon.dimcheff.com/2009/02/14/play-in-the-sandbox/","section":"Posts","summary":"\u003cp\u003eI needed to test some code that reads and writes files on the filesystem.  I got sick of manually setting up a scratch area for my test files and cleaning them up when I was done, so I created \u003ca href=\"http://github.com/bdimcheff/sandbox/tree/master\" target=\"_blank\" rel=\"noreferrer\"\u003eSandbox\u003c/a\u003e to keep my tests DRY.\u003c/p\u003e","title":"Play in the Sandbox"},{"content":"UPDATE 4/20/2010: Well Grounded Rubyist is not prerelease anymore. Corrected.\nUPDATE 6/30/2011: Fix links to _why\u0026rsquo;s poignant guide, since he vanished from the earth. Add a bit about finding live people to help you.\nUPDATE 9/27/2015: Add udemy ruby guides. More updates coming soon, as many books have been updated since I originally posted this.\nSeveral people have asked me for tutorials, books, and other resources to help them learn Ruby, so I\u0026rsquo;ve attempted to compile a list of resources I feel are particularly valuable for beginning Rubyists. None of these resources are Rails-specific, but being a good Ruby programmer will obviously help you use Rails more effectively. If there is interest, I will compile a similar (and likely longer) list of Rails resources.\nAlso, if I\u0026rsquo;ve missed anything that helped you learn or teach Ruby, please leave a comment and I will add it to the page. I am especially interested in resources that beginning Rubyists have found useful.\nFor these resources, I assume you already have programming experience and are attempting to pick up Ruby to widen your skillset. If you\u0026rsquo;re new to programming entirely, check out Chris Pine\u0026rsquo;s Learn to Program online tutorial.\nThe 100% Best Way to Learn Ruby #The best way (in my not so humble opinion) to learn Ruby is to find a Ruby expert who is willing to mentor you. Maybe this means tagging along with somebody at work, or pairing with somebody at a startup weekend. At our Ruby meetups in Ann Arbor, we occasionally do a Ruby tutorial where people take turns working on a simple problem that is projected up on a board. New rubyists have often found a permanent guide at these sorts of events. The value of having somebody close to you to be able to help is profound. Do this if you can. If you can\u0026rsquo;t, or for when you\u0026rsquo;re alone, this post has many other non-sentient resources that you can use.\nOnline Resources #The following is a list of freely available online resources that I\u0026rsquo;ve found particularly helpful for new Rubyists.\nRuby Koans: The newest kid on the block (no pun intended) that\u0026rsquo;s taking github by storm is EdgeCase\u0026rsquo;s Ruby Koans. The Koans are essentially a series of failing test cases that you need to figure out how to fix in order to move on to the next step. The best way to learn anything is by doing, and this tutorial will get you programming in no time flat. We use this one at our \u0026ldquo;ruby for noobies\u0026rdquo; meetings a lot.\nNote that the point in the exercise is not to fix all the tests as fast as possible. In order to get the benefit of this exercise, you must read and understand what the code is showing you. Complete each Koan one by one. Run your tests after each time you change your code.\nI think the best way to use these Koans is to get in a small (2-3 person) group and take turns solving the problems. Discuss what you are doing with each other. Don\u0026rsquo;t take anything for granted.\nWhy\u0026rsquo;s Poignant Guide: Why the Lucky Stiff put together an extremely silly tutorial on Ruby. While it may seem a bit campy, it really is a good tutorial. And it\u0026rsquo;s a lot of fun! It\u0026rsquo;s not nearly as exhaustive as the Koans, but it has more cartoon foxes and chunky bacon.\nRuby Quiz: Once you get your feet wet, you might want to check out the Ruby Quiz archives. There are over 150 small programming challenges that you can try to solve using Ruby. Don\u0026rsquo;t cheat and look at the answers before you try it for yourself!\n10 Things Every Java Programmer Should Know About Ruby: If you\u0026rsquo;re a Java programmer trying to learn ruby, you should check out Jim Weirich\u0026rsquo;s 10 things presentation. He goes over many important differences between Java and Ruby, and this can really help you avoid mistakes that many Java programmers make when transitioning to Ruby.\nThe Humble Little Ruby Book: Jeremy McAnally\u0026rsquo;s free introductory online Ruby book. Covers the basics about a lot of stuff that every Ruby programmer needs to know. Also available in print.\nUdemy\u0026rsquo;s Intro Ruby on Rails Guide: Udemy, one of the new platforms for online learning, has an intro to Rails in step-by-step tutorial form. If you\u0026rsquo;re interested in Rails specifically, it\u0026rsquo;s definitely worth checking out.\nBooks #The following books are, in my opinion, the best books for aspiring Rubists to check out. None of them are Rails specific.\nBeginning Ruby: From Novice to Professional: Peter Cooper\u0026rsquo;s Beginning Ruby book has received rave reviews, and is specifically targeted at beginning Rubyists. I\u0026rsquo;m a bit ashamed that I didn\u0026rsquo;t pick it up on the first pass at this article. Sorry Peter!\nProgramming Ruby: The Pragmatic Programmers\u0026rsquo; Guide, Second Edition (aka. The Pickaxe): This book has been the gold standard of Ruby books for years, and is a must have for ruby programmers. It has both a descriptive section and a reference section. The 2nd edition is from 2004, however, and does not cover Ruby 1.9 at all. The 3rd edition is available in beta, and the final version will be available in March.\nThe Ruby Way: Hal Fulton\u0026rsquo;s book is full of solutions to common problems, plus it really helps you learn many of the Ruby idioms that are used by experienced Ruby programmers. Ruby 1.8 only.\nThe Ruby Programming Language: Written by the creator of Ruby himself, this book covers ruby 1.8 and 1.9. It\u0026rsquo;s not a tutorial-style book, nor a complete reference, but more of description of the important parts of the Ruby programming language. It\u0026rsquo;s a great second book (after the Pickaxe) to help you understand more details about how Ruby works.\nThe Well Grounded Rubyist: David Black\u0026rsquo;s newest book The Well Grounded Rubyist is now available in its final edition. It\u0026rsquo;s in tutorial form, which is generally good for beginners. I have not had a chance to read it yet, but his last book was great and I hear this one\u0026rsquo;s even better.\nNote: This is a work in progress. I will be updating it as new books and tutorials come out. I also don\u0026rsquo;t necessarily want an exhaustive list of every ruby resource. I\u0026rsquo;m looking for resources that are helpful for beginners. Too many choices may be overwhelming. Also, I haven\u0026rsquo;t been a Ruby beginner in a long time, so I am particularly interested in things that recent beginners have found helpful.\n","date":"5 February 2009","permalink":"https://brandon.dimcheff.com/2009/02/05/how-to-learn-ruby/","section":"Posts","summary":"\u003cp\u003e\u003cstrong\u003eUPDATE 4/20/2010:\u003c/strong\u003e Well Grounded Rubyist is not prerelease anymore.  Corrected.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eUPDATE 6/30/2011:\u003c/strong\u003e Fix links to _why\u0026rsquo;s poignant guide, since he vanished from the earth. Add a bit about finding live people to help you.\u003c/p\u003e","title":"How to learn Ruby"},{"content":"The latest master Sinatra now supports optional block parameters. It captures any parameters in the URL and passes them into the block that defines the action:\nget \u0026#39;/hello/:name\u0026#39; do |n| \u0026#34;Hello #{n}!\u0026#34; end The params hash is still available as before, so this should not break any existing applications. It will also work with regular expressions. Any captures are yielded in order:\nget %r{/hello/([\\w]+)/([\\w]+)} do |a, b| \u0026#34;Hello, #{a} and #{b}!\u0026#34; end Big thanks to rtomayko for accepting my patch, and working with me to get this solid enough to put into Sinatra!\nOne final note: this feature behaves slightly differently in ruby 1.8 and 1.9. Ruby 1.9 is much stricter about block arity than 1.8 is. If the number of captures in the URL and the arity of the block do not match, 1.9 will raise an exception. 1.8 will likely just ignore the extra parameters and throw up a warning. If you write code that is compatible with 1.9, it will also work with 1.8, as ruby 1.9 is simply more strict.\n","date":"4 February 2009","permalink":"https://brandon.dimcheff.com/2009/02/04/sinatra-block-parameters/","section":"Posts","summary":"\u003cp\u003eThe latest master \u003ca href=\"http://www.sinatrarb.com/\" target=\"_blank\" rel=\"noreferrer\"\u003eSinatra\u003c/a\u003e now supports optional block parameters.  It captures any parameters in the URL and passes them into the block that defines the action:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-ruby\" data-lang=\"ruby\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eget\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;/hello/:name\u0026#39;\u003c/span\u003e \u003cspan class=\"k\"\u003edo\u003c/span\u003e \u003cspan class=\"o\"\u003e|\u003c/span\u003e\u003cspan class=\"n\"\u003en\u003c/span\u003e\u003cspan class=\"o\"\u003e|\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"s2\"\u003e\u0026#34;Hello \u003c/span\u003e\u003cspan class=\"si\"\u003e#{\u003c/span\u003e\u003cspan class=\"n\"\u003en\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s2\"\u003e!\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eend\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003eThe \u003ccode\u003eparams\u003c/code\u003e hash is still available as before, so this should not break any existing applications.  It will also work with regular expressions.  Any captures are yielded in order:\u003c/p\u003e","title":"Sinatra block parameters!"},{"content":"It seems that it\u0026rsquo;s not well publicized, but if you want to run your RSpec files with autotest try autospec instead. It looks inside the spec/ directory for files named \u0026ldquo;*_spec.rb\u0026rdquo; by default for specs. autospec is part of the RSpec gem, and basically just sets up the proper environment and then shells out to autotest.\nAlso, if your files in lib/ match up with specs in spec/, autospec will automatically re-run your specs for changed files in lib/ on save. So if you have lib/foo/bar.rb, autospec will re-run lib/foo/bar_spec.rb when you save bar.rb.\n","date":"26 January 2009","permalink":"https://brandon.dimcheff.com/2009/01/26/run-specs-with-autotest-er-autospec/","section":"Posts","summary":"\u003cp\u003eIt seems that it\u0026rsquo;s not well publicized, but if you want to run your RSpec files with \u003ccode\u003eautotest\u003c/code\u003e try \u003ccode\u003eautospec\u003c/code\u003e instead.  It looks inside the spec/ directory for files named \u0026ldquo;*_spec.rb\u0026rdquo; by default for specs.  \u003ccode\u003eautospec\u003c/code\u003e is part of the RSpec gem, and basically just sets up the proper environment and then shells out to autotest.\u003c/p\u003e","title":"Run specs with autotest, er, autospec!"},{"content":"I\u0026rsquo;m getting all packed for CodeMash! Hope too see a lot of you there. I\u0026rsquo;m a little bit disappointed by the dearth of Ruby sessions, but there are enough of us that the open sessions will be rockin\u0026rsquo;. And the ever popular scotch track always helps.\n","date":"6 January 2009","permalink":"https://brandon.dimcheff.com/2009/01/06/gearing-up-for-codemash/","section":"Posts","summary":"\u003cp\u003eI\u0026rsquo;m getting all packed for CodeMash!  Hope too see a lot of you there.  I\u0026rsquo;m a little bit disappointed by the dearth of Ruby sessions, but there are enough of us that the open sessions will be rockin\u0026rsquo;.  And the ever popular scotch track always helps.\u003c/p\u003e","title":"Gearing up for CodeMash"},{"content":"Update: Deskin points out that there is a commit to git that fixes this problem by adding a --root option to rebase --onto. So when you get a new build of git, you can probably ignore everything here.\nThe other day I needed to commit a plain old (git-svn free) git repository to subversion. Why, you ask? I had been working on a small project at work in my own little git repository and needed to get it into our official version control. I could, of course, just commit the latest version that I had, but that would not record any of my git commit history in subversion. I needed a better option. git-svn can save each individual commit of a linear commit history to subversion, so I figured I could just apply git-svn metadata to my repository and go from there.\nThis post is a bit long, as I explain the whole process for the solution. If you\u0026rsquo;re interested in just the solution, scroll to the bottom.\nI\u0026rsquo;m going to create a small git repository for illustrative purposes: $ git init Initialized empty Git repository in /Users/bdimchef/testgit/.git/\nFor this howto, I\u0026rsquo;m using a blank subversion repository, but you can use this method with any subversion repository that has an empty directory to put your new project.\n$ svnadmin create /Users/bdimchef/testsvn $ svn mkdir file:///Users/bdimchef/testsvn/trunk $ svn mkdir file:///Users/bdimchef/testsvn/branches $ svn mkdir file:///Users/bdimchef/testsvn/tags Then, I added my svn metadata to my git repository and fetched the contents of svn:\n$ git svn init -s file:///Users/bdimchef/testsvn $ git svn fetch Now I was ready to commit:\n$ git svn dcommit Can't call method \u0026quot;full_url\u0026quot; on an undefined value at /opt/local/libexec/git-core/git-svn line 425. What this error means (in our case) is that it can\u0026rsquo;t figure out where to dcommit. If we try to rebase, it\u0026rsquo;s clearer what the problem is:\n$ git svn rebase Unable to determine upstream SVN information from working tree history Our problem is that we have two disjoint histories in our git repository: The history that we made in git, and the history from our svn repository. Since they share no common ancestors, git svn can\u0026rsquo;t figure out where to commit its changes. Take a look at gitk to see what\u0026rsquo;s going on here.\nIt turns out that this problem is pretty easy to fix with svn rebase. But there is one little trick that will get you if you\u0026rsquo;re not careful. And before we get carried away doing too many rebases, lets just make a backup branch of master just in case.\n$ git branch master.bak master Lets try one approach. git rebase --onto A B C takes the commit range B..C and puts it onto A. In this case, we want to take all our commits and put them on to trunk:\n$ git rebase --onto trunk master~2 master Applying: added bar Applying: added baz Oops! That only applied bar and baz. It forgot about our first commit, foo. Lets go back one more.\n$ git rebase --onto trunk master~3 master fatal: Needed a single revision invalid upstream master~3 Well, that didn\u0026rsquo;t work either. The problem is that git rebase --onto rebases the range beginning after commit B. In this case, the commit after foo, which is bar. And there is no commit before foo, so there\u0026rsquo;s no way to rebase a range starting with foo included. The simple solution to this problem is to git cherry-pick foo first, then do the rebase. First we\u0026rsquo;ll create a named branch for our rebase.\nThe Solution #$ git co -b svnrebase trunk # create a temporary branch $ git cherry-pick master~2 # cherry pick the first commit $ git rebase --onto svnrebase master~2 master # rebase the 2nd through current commit $ git svn dcommit # finally commit the results to svn And that worked! So, generally, the secret to joining two separate histories together is to cherry-pick the first commit, and then rebase the rest on top of it.\nThanks to charon on #git for the cherry-pick idea.\n","date":"4 January 2009","permalink":"https://brandon.dimcheff.com/2009/01/04/commit-a-linear-git-history-to-subversion/","section":"Posts","summary":"\u003cp\u003e\u003cstrong\u003eUpdate:\u003c/strong\u003e Deskin points out that there is a \u003ca href=\"http://git.kernel.org/?p=git/git.git;a=commit;h=190f53232d1e92a57843df90e889bcfea39620d3\" target=\"_blank\" rel=\"noreferrer\"\u003ecommit\u003c/a\u003e to git that fixes this problem by adding a \u003ccode\u003e--root\u003c/code\u003e option to \u003ccode\u003erebase --onto\u003c/code\u003e.  So when you get a new build of git, you can probably ignore everything here.\u003c/p\u003e","title":"Commit a linear git history to subversion"},{"content":"This is a Capistrano recipe I use to configure my production database.yml. Before deploy:setup executes, this recipe will prompt for a database password and save a new database.yml file to the shared directory on your server. After each deploy, the database.yml file will be symlinked from the shared directory. You can reconfigure your database by executing cap db:configure.\nHere are the goods. I\u0026rsquo;m pretty sure I got this from Jeremy Voorhis a while back, and modified it to work with Capistrano 2.\n","date":"3 January 2009","permalink":"https://brandon.dimcheff.com/2009/01/03/use-capistrano-to-set-your-production-database-password/","section":"Posts","summary":"\u003cp\u003eThis is a Capistrano recipe I use to configure my production database.yml.  Before \u003ccode\u003edeploy:setup\u003c/code\u003e executes, this recipe will prompt for a database password and save a new database.yml file to the shared directory on your server.  After each deploy, the database.yml file will be symlinked from the shared directory.  You can reconfigure your database by executing \u003ccode\u003ecap db:configure\u003c/code\u003e.\u003c/p\u003e","title":"Use Capistrano to set your production database password"},{"content":"I generally think that new year resolutions are silly, but since it\u0026rsquo;s the new year and I have some goals I\u0026rsquo;d like to set, I guess I might as well call them resolutions.\nSince goals, like technical requirements, are meaningless if you can\u0026rsquo;t measure them, I\u0026rsquo;ll be as specific as possible even if it means that I\u0026rsquo;ll have to adjust them later. So here we go:\nResolved:\nI will blog at least once a week. Corollary: I will blog within one day of saying to myself \u0026ldquo;Hey, I should blog about this\u0026rdquo; I will contribute a patch to an open source project at least once a month I will start a useful open source project by April I will write my blog from scratch by July so I can do it just the way I want I will do Project 365. Seriously this time. and perhaps most importantly:\nI will have my next form of gainful employment arranged by January 23rd. This blog post does not count towards resolution #1, and I\u0026rsquo;ve got a decent backlog of items to write about, so you\u0026rsquo;ll be hearing from me soon.\nHappy new year!\n","date":"2 January 2009","permalink":"https://brandon.dimcheff.com/2009/01/02/resolutions/","section":"Posts","summary":"\u003cp\u003eI generally think that new year resolutions are silly, but since it\u0026rsquo;s the new year and I have some goals I\u0026rsquo;d like to set, I guess I might as well call them resolutions.\u003c/p\u003e","title":"Resolutions"},{"content":"Ruby Hoedown 2008 videos are now live. There are a lot of good talks. I highly recommend checking them out. I\u0026rsquo;ve set up a torrent of all the videos for your convenience.\n","date":"22 August 2008","permalink":"https://brandon.dimcheff.com/2008/08/22/ruby-hoedown-videos-online/","section":"Posts","summary":"\u003cp\u003eRuby Hoedown 2008 \u003ca href=\"http://rubyhoedown2008.confreaks.com/\" target=\"_blank\" rel=\"noreferrer\"\u003evideos\u003c/a\u003e are now live.  There are a lot of good talks.  I highly recommend checking them out.  I\u0026rsquo;ve set up a \u003ca href=\"http://thepiratebay.org/torrent/4355220\" target=\"_blank\" rel=\"noreferrer\"\u003etorrent\u003c/a\u003e of all the videos for your convenience.\u003c/p\u003e","title":"Ruby Hoedown Videos Online"},{"content":"To make TextMate\u0026rsquo;s RubyMate work with MacPorts (or any other non-default ruby install) just set TM_RUBY environment variable to be the path to your custom ruby interpreter in TextMate\u0026rsquo;s preferences. Custom environmental variable settings are located under \u0026lsquo;Advanced\u0026rsquo;-\u0026gt;\u0026lsquo;Shell Variables\u0026rsquo; in TM\u0026rsquo;s prefs.\n","date":"18 June 2008","permalink":"https://brandon.dimcheff.com/2008/06/18/make-rubymate-work-with-macports-ruby/","section":"Posts","summary":"\u003cp\u003eTo make TextMate\u0026rsquo;s RubyMate work with MacPorts (or any other non-default ruby install) just set TM_RUBY environment variable to be the path to your custom ruby interpreter in TextMate\u0026rsquo;s preferences.  Custom environmental variable settings are located under \u0026lsquo;Advanced\u0026rsquo;-\u0026gt;\u0026lsquo;Shell Variables\u0026rsquo; in TM\u0026rsquo;s prefs.\u003c/p\u003e","title":"Make RubyMate work with MacPorts Ruby"},{"content":"I\u0026rsquo;ve had a problem with my sake tasks being blank for the past couple days. Since there were a couple comments on err about similar things, I\u0026rsquo;ll share my fix: gem install -v 2.0.1 ParseTree. That\u0026rsquo;s it. Turns out my ParseTree install was messed up and to_ruby was not working on the task blocks.\n","date":"10 February 2008","permalink":"https://brandon.dimcheff.com/2008/02/10/fix-empty-sake-tasks/","section":"Posts","summary":"\u003cp\u003eI\u0026rsquo;ve had a problem with my \u003ca href=\"http://errtheblog.com/posts/60-sake-bomb\" target=\"_blank\" rel=\"noreferrer\"\u003esake\u003c/a\u003e tasks being blank for the past couple days.  Since there were a couple comments on err about similar things, I\u0026rsquo;ll share my fix: \u003ccode\u003egem install -v 2.0.1 ParseTree\u003c/code\u003e.  That\u0026rsquo;s it.  Turns out my ParseTree install was messed up and to_ruby was not working on the task blocks.\u003c/p\u003e","title":"Fix empty sake tasks"},{"content":"Rails 2.0 has been released. Check it.\n","date":"7 December 2007","permalink":"https://brandon.dimcheff.com/2007/12/07/rails-2-0-is-out/","section":"Posts","summary":"\u003cp\u003e\u003ca href=\"http://weblog.rubyonrails.org/2007/12/7/rails-2-0-it-s-done\" target=\"_blank\" rel=\"noreferrer\"\u003eRails 2.0\u003c/a\u003e has been released. Check it.\u003c/p\u003e","title":"Rails 2.0 is out"},{"content":"Try create_table(:suppliers, :options =\u0026gt; \u0026#39;ENGINE=InnoDB DEFAULT CHARSET=utf8\u0026#39;) if you need to make a table with a different storage engine than default on MySQL. Note that this will bind your migration to MySQL, as it simply appends whatever is in the :options string to the end of the CREATE_TABLE generated by the migration.\n","date":"3 December 2007","permalink":"https://brandon.dimcheff.com/2007/12/03/using-other-mysql-storage-engines/","section":"Posts","summary":"\u003cp\u003eTry \u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-ruby\" data-lang=\"ruby\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003ecreate_table\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"ss\"\u003e:suppliers\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"ss\"\u003e:options\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;ENGINE=InnoDB DEFAULT CHARSET=utf8\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e if you need to make a table with a different storage engine than default on MySQL.  Note that this will bind your migration to MySQL, as it simply appends whatever is in the \u003ccode\u003e:options\u003c/code\u003e string to the end of the \u003ccode\u003eCREATE_TABLE\u003c/code\u003e generated by the migration.\u003c/p\u003e","title":"Using other MySQL Storage Engines"},{"content":"RubyInject is a small library from the folks who brought you RubyCocoa. It allows you to inject a ruby interpreter into a Cocoa app and tinker with all its\u0026rsquo; internals.\n","date":"27 November 2007","permalink":"https://brandon.dimcheff.com/2007/11/27/rubyinject/","section":"Posts","summary":"\u003cp\u003e\u003ca href=\"http://rubycocoa.sourceforge.net/RubyInject\" target=\"_blank\" rel=\"noreferrer\"\u003eRubyInject\u003c/a\u003e is a small library from the folks who brought you RubyCocoa.  It allows you to inject a ruby interpreter into a Cocoa app and tinker with all its\u0026rsquo; internals.\u003c/p\u003e","title":"RubyInject"},{"content":"I\u0026rsquo;m trying out shoulda, a testing framework written by the guys over at Thoughtbot.\n","date":"29 September 2007","permalink":"https://brandon.dimcheff.com/2007/09/29/shoulda/","section":"Posts","summary":"\u003cp\u003eI\u0026rsquo;m trying out \u003ca href=\"http://thoughtbot.com/projects/shoulda\" target=\"_blank\" rel=\"noreferrer\"\u003eshoulda\u003c/a\u003e, a testing framework written by the guys over at Thoughtbot.\u003c/p\u003e","title":"shoulda"},{"content":"This is a based on a comment I made on a post on thoughtbot\u0026rsquo;s blog. I suggest you read the original post for some background on what I\u0026rsquo;m talking about.\nIf you\u0026rsquo;re too lazy to read, here\u0026rsquo;s the basic gist: You could potentially test your associations or plugins (such as acts_as_solr) by simply checking whether or not your object responds to the messages that the plugins generate when their class methods are called.\nThe problem is, we should be trying to test behavior, not simply whether or not acts_as_solr or has_many are being called. The problem with the approach described above is that it assumes too much about implementation details and doesn\u0026rsquo;t actually make sure your app is doing what it\u0026rsquo;s supposed to be doing.\nIn this case, I think that find_by_solr should be called find_by_content or something, since it doesn\u0026rsquo;t really matter that it\u0026rsquo;s solr that\u0026rsquo;s doing the lookup. All the developer using the API cares about is that when they pass a particular query into the method, the proper results are returned. And that is what our tests should test.\nI am not convinced that (as many test/rspec examples show) simply checking for association methods (has_many, belongs_to, etc.) or plugin methods (acts_as_solr) are sufficient, or even a good idea at all. Nor do I think that those sorts of tests qualify as BDD. For instance, I have something resembling the following in an application per someone\u0026rsquo;s suggestion:\nPerson.reflect_on_association(:addresses).should_not be_nil I really don\u0026rsquo;t like this, though. I don\u0026rsquo;t care one bit that there\u0026rsquo;s an association called \u0026ldquo;addresses\u0026rdquo; on my Person object. What I care about is that Person responds to addresses and that addresses returns an array of the proper addresses. This is the whole point in BDD. Care about the behavior of your objects, not their implementation.\nTo explore this further, I\u0026rsquo;ll use a slightly more complicated example. Say I have the following in my Person class:\n# app/models/person.rb has_many :addresses has_many :cool_addresses, :foreign_key =\u0026gt; \u0026#34;address_id\u0026#34;, :conditions =\u0026gt; [\u0026#34;foo = ? AND bar = ?\u0026#34;, foo, bar], :order =\u0026gt; :zipcode And the corresponding test case:\nPerson.reflect_on_association(:cool_addresses).should_not be_nil Well, guess what. This association exists. Our tests pass. But it\u0026rsquo;s wrong. That :foreign_key is supposed to be person_id and not address_id. Well, we can solve that! Just test to make sure the has_many receives the appropriate parameters. Something like this (made up) helper would work:\nPerson.reflect_on_association(:cool_addresses).should have_foreign_key(\u0026#34;person_id\u0026#34;)) And we could go about our business, basically duplicating all the parameters supplied to has_many in our tests. But in the end, this is just going to make our tests horribly brittle and is not actually testing anything useful. It\u0026rsquo;s not testing behavior at all.\nThe whole point in BDD is to make our tests poke and prod our application in a certain way and have them spit back the correct output. Yes, the plugins/associations are well tested and I shouldn\u0026rsquo;t be testing them again. I know that if my has_many call supplies the correct parameters, I will get the objects I expect to get. But I still need to make sure that I\u0026rsquo;m calling has_many properly. It\u0026rsquo;s simply not sufficient for me to know that has_many is called, I need to know that when it\u0026rsquo;s called, the proper \u0026ldquo;stuff\u0026rdquo; happens. I need to make sure the association does what I expect it to do. Here\u0026rsquo;s what I think my tests should do to ensure cool_addresses is working properly (no real code this time):\nAdd a few objects to the Addresses table, either using fixtures or in some kind of before callback. (Yes, fixtures suck, etc.) Make sure cool_addresses returns addresses that correspond to the \u0026lsquo;foo\u0026rsquo; and \u0026lsquo;bar\u0026rsquo; conditions above. Make sure that cool_addresses returns the addresses ordered by zipcode. And that\u0026rsquo;s it. Yes, it will take the tests slightly longer to run, since they\u0026rsquo;re using the database (and maybe fixtures). Yes, I\u0026rsquo;m partially testing ActiveRecord. But I\u0026rsquo;m testing that my object behaves like I want it to. That\u0026rsquo;s the point in BDD, right?\nAs an added benefit, the tests are much more flexible now. Check it out:\n# app/models/person.rb has_many :addresses #has_many :cool_addresses, :foreign_key =\u0026gt; \u0026#34;address_id\u0026#34;, :conditions =\u0026gt; [\u0026#34;foo = ? AND bar = ?\u0026#34;, foo, bar], :order =\u0026gt; :zipcode def cool_addresses addresses.find_all do {|a| a.foo == foo \u0026amp;\u0026amp; a.bar == bar}.sort(\u0026amp;:zipcode) end That passes my tests, too. And it should. But my previous example where I used association introspection would fail miserably.\nThis is a major complaint about a lot of the test code examples I see floating around. Everybody seems to be mocking and stubbing and introspecting to their heart\u0026rsquo;s content, but all they seem to be doing in the end is writing the same code twice: once in their implementation, and once in their tests. And so when they change the way their application is implemented (NOTE: I did not say their application\u0026rsquo;s behavior) their tests break.\nThere are two sides to this BDD thing. First, your tests need to ensure that if you change the behavior of your code, they will fail. Second, your tests need to still work when your application still behaves the right way, even if you change every single line of code in your application. Of course, this is nearly impossible to achieve, but at least we can try.\nThoughts?\n","date":"21 September 2007","permalink":"https://brandon.dimcheff.com/2007/09/21/test-behavior-not-implementation/","section":"Posts","summary":"\u003cp\u003eThis is a based on a comment I made on a \u003ca href=\"http://giantrobots.thoughtbot.com/2007/9/19/ruby-on-rails-testing-strategies\" target=\"_blank\" rel=\"noreferrer\"\u003epost\u003c/a\u003e on thoughtbot\u0026rsquo;s blog.  I suggest you read the original post for some background on what I\u0026rsquo;m talking about.\u003c/p\u003e\n\u003cp\u003eIf you\u0026rsquo;re too lazy to read, here\u0026rsquo;s the basic gist:  You could potentially test your associations or plugins (such as acts_as_solr) by simply checking whether or not your object responds to the messages that the plugins generate when their class methods are called.\u003c/p\u003e","title":"Test behavior, not implementation!"},{"content":"I was poking through svn for has_many_polymorphs to see if a bug that I found had been fixed. Lo and behold, it was:\nr688 | evanweaver | 2007-08-29 03:49:55 -0400 (Wed, 29 Aug 2007) | 2 lines\nfix singularize bug in autoloader (Brandon Dimcheff)\n","date":"18 September 2007","permalink":"https://brandon.dimcheff.com/2007/09/18/i-can-has-patch/","section":"Posts","summary":"\u003cp\u003eI was poking through svn for \u003ca href=\"http://blog.evanweaver.com/files/doc/fauna/has_many_polymorphs/files/README.html\" target=\"_blank\" rel=\"noreferrer\"\u003ehas_many_polymorphs\u003c/a\u003e to see if a bug that I found had been fixed.  Lo and behold, it was:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003er688 | evanweaver | 2007-08-29 03:49:55 -0400 (Wed, 29 Aug 2007) | 2 lines\u003c/p\u003e","title":"I can has patch?"},{"content":"The Caboose sample app comes with user authentication and many other useful features baked in. It\u0026rsquo;s a great starting place for your new Rails app!\n","date":"10 September 2007","permalink":"https://brandon.dimcheff.com/2007/09/10/caboose-sample-app/","section":"Posts","summary":"\u003cp\u003eThe \u003ca href=\"http://sample.caboo.se/\" target=\"_blank\" rel=\"noreferrer\"\u003eCaboose sample app\u003c/a\u003e comes with user authentication and many other useful features baked in.  It\u0026rsquo;s a great starting place for your new Rails app!\u003c/p\u003e","title":"Caboose Sample App"},{"content":"The Peepcode people have published a long list of Rails development tips: Tips!\n","date":"7 September 2007","permalink":"https://brandon.dimcheff.com/2007/09/07/massive-list-of-rails-development-tips-from-peepcode/","section":"Posts","summary":"\u003cp\u003eThe \u003ca href=\"http://peepcode\" target=\"_blank\" rel=\"noreferrer\"\u003ePeepcode\u003c/a\u003e people have published a long list of Rails development tips: \u003ca href=\"http://nubyonrails.com/articles/massive-list-of-rails-development-tips\" target=\"_blank\" rel=\"noreferrer\"\u003eTips!\u003c/a\u003e\u003c/p\u003e","title":"Massive list of Rails development tips from Peepcode"},{"content":"A new Rails plugin repository has been launched: Railsify. Check it out.\n","date":"7 September 2007","permalink":"https://brandon.dimcheff.com/2007/09/07/railsify/","section":"Posts","summary":"\u003cp\u003eA new Rails plugin repository has been launched: \u003ca href=\"http://railsify.com/\" target=\"_blank\" rel=\"noreferrer\"\u003eRailsify\u003c/a\u003e.  Check it out.\u003c/p\u003e","title":"Railsify"},{"content":"Earlier today I was trying to figure out how to make a list of potential models to be created. For example: I have some Users and some Groups. I have a many-to-many Membership join model with some has_many :throughs. The fundamental goal is to provide the user an interface to add Membership models that link a User to a Group. I could use a bunch of checkboxes, but I\u0026rsquo;d rather pull up a list of possible Groups with little \u0026ldquo;add\u0026rdquo; links next to them.\nSince I\u0026rsquo;m using RESTful controllers, we have a MembershipsController that implements all the standard methods. We\u0026rsquo;re also nesting our routes such that MembershipsController nested beneath the UsersController. In order to create the Membership, we need to POST to /users/1/memberships. But how do we get a list of Memberships that we can quickly add?\nHow about modifying MembershipsController.new? We don\u0026rsquo;t need the normal definition of new, since we\u0026rsquo;re never going to be manually creating a new Membership.\n# controllers/memberships_controller.rb def new @memberships = Groups.find(:all).collect do |group| Membership.new(:user_id =\u0026gt; params[:user_id], :group_id =\u0026gt; group.id) end end Now we have a list of potential Membership objects available to our view. Remember, the Memberships haven\u0026rsquo;t been saved yet. They\u0026rsquo;re just there for convenience for holding attributes. We are doing object-oriented programming after all.\n# views/memberships/new.html.erb \u0026lt;% @memberships.each do |membership| %\u0026gt; \u0026lt;% form_for :membership, membership, :url =\u0026gt; memberships_path do |f| %\u0026gt; \u0026lt;%= f.hidden_field :user_id %\u0026gt; \u0026lt;%= f.hidden_field :group_id %\u0026gt; \u0026lt;%= f.submit membership.group.name %\u0026gt; \u0026lt;% end %\u0026gt; \u0026lt;% end %\u0026gt; Basically what we have here is a big list of predefined join models wrapped up in form tags. When you click on one of them, you\u0026rsquo;ll end up submitting the form that actually creates the model. Eventually, we could make this into an AJAX widget that uses form_remote_for with very little effort.\nNothing I have described here is particularly revolutionary. Rather than just returning a single new Membership in the new method, we return a list of objects. Rather than rendering one form with editable fields, we render multiple forms with predefined, hidden fields. Whichever you submit creates the corresponding object. These two very simple changes to the standard REST actions allow us to easily and elegantly create our join models.\n","date":"31 August 2007","permalink":"https://brandon.dimcheff.com/2007/08/31/predefined-models-no-different-than-any-others/","section":"Posts","summary":"\u003cp\u003eEarlier today I was trying to figure out how to make a list of potential models to be created.  For example:  I have some \u003ccode\u003eUser\u003c/code\u003es and some \u003ccode\u003eGroup\u003c/code\u003es.  I have a many-to-many \u003ccode\u003eMembership\u003c/code\u003e join model with some \u003ccode\u003ehas_many :through\u003c/code\u003es.  The fundamental goal is to provide the user an interface to add Membership models that link a \u003ccode\u003eUser\u003c/code\u003e to a \u003ccode\u003eGroup\u003c/code\u003e.  I \u003cem\u003ecould\u003c/em\u003e use a bunch of checkboxes, but I\u0026rsquo;d rather pull up a list of possible \u003ccode\u003eGroup\u003c/code\u003es with little \u0026ldquo;add\u0026rdquo; links next to them.\u003c/p\u003e","title":"Predefined models?  No different than any others."},{"content":"I have a clean install of OS X on which I need to install Rails. I\u0026rsquo;ve done this maybe 3 or 4 times in the past year with minor variations each time which inevitably come back to bite me later. This post is an effort to document and standardize all the details to get a Rails stack going with MacPorts.\nInstalling Xcode Tools #You need the latest version of Xcode tools to be able to compile all the packages necessary for Ruby and Rails. They\u0026rsquo;re a free download from Apple.\nInstalling MacPorts #First thing\u0026rsquo;s first: Install MacPorts! Be sure to follow the directions closely. Especially the bit about setting your PATH appropriately. The /opt paths must be before your standard path so when you type ruby, you use the ruby interpreter from MacPorts rather than the old one that came with OS X.\nInstalling Rails Prerequisites with MacPorts #$ sudo port install mysql5 +server $ sudo port install ruby $ sudo port install rb-rubygems $ sudo port install rb-mysql $ sudo port install rb-termios $ sudo port install subversion +tools Configure MySQL #First, add /opt/local/lib/mysql5/bin/ to your PATH as you did in the instructions to install MacPorts.\n$ sudo mysql_install_db5 --user=mysql Install Gems #$ sudo gem install -y rake $ sudo gem install -y rails $ sudo gem install -y capistrano $ sudo gem install -y mongrel $ sudo gem install -y mongrel_cluster $ sudo gem install -y piston Install Optional Packages #The above ports and gems are the minimum you\u0026rsquo;ll need to get rails running successfully. The ones below, while not required, are often useful when developing rails apps.\nOther Databases #Try postgres or sqlite3 for some database variety (port install postgresql82-server \u0026amp;\u0026amp; port install rb-postgres or port install rb-sqlite3, respectively).\nTesting # RSpec - a powerful BDD framework Flexmock and/or Mocha - for mocking/stubbing Misc # tzinfo - Time Zone handling ","date":"28 August 2007","permalink":"https://brandon.dimcheff.com/2007/08/28/installing-a-rails-stack-on-mac-os-x-with-macports/","section":"Posts","summary":"\u003cp\u003eI have a clean install of OS X on which I need to install Rails.  I\u0026rsquo;ve done this maybe 3 or 4 times in the past year with minor variations each time which inevitably come back to bite me later.  This post is an effort to document and standardize all the details to get a Rails stack going with MacPorts.\u003c/p\u003e","title":"Installing a Rails stack on Mac OS X with MacPorts"},{"content":"After 9 months of trying to get a Ruby blog launched, I finally have succeeded. And now it\u0026rsquo;s late, so I\u0026rsquo;m going to bed. But check back soon for juicy Ruby and Rails tidbits.\nNo, tags don\u0026rsquo;t quite work yet. It\u0026rsquo;s Heminway\u0026rsquo;s fault. I\u0026rsquo;m fixing it and I\u0026rsquo;ll release my changes.\n","date":"27 August 2007","permalink":"https://brandon.dimcheff.com/2007/08/27/first-post/","section":"Posts","summary":"\u003cp\u003eAfter 9 months of trying to get a Ruby blog launched, I finally have succeeded.  And now it\u0026rsquo;s late, so I\u0026rsquo;m going to bed.  But check back soon for juicy Ruby and Rails tidbits.\u003c/p\u003e","title":"First Post"},{"content":"Brandon Dimcheff is a software engineer born and raised in Ann Arbor, Michigan, and educated at the University of Michigan. He uses go for his day job, wrangles pods with Kubernetes, is an aspiring functional programming language nerd, and is an advocate of open source. He\u0026rsquo;s an urbanist who loves density, bike lanes, and transit. In his free time, he\u0026rsquo;s a pretty good cook and tries to spend a lot of time on his bike or knee deep in powder.\nHe\u0026rsquo;s currently a Principal Engineer at Openly, an insuretech startup. He lives in Jackson, Wyoming. Go Blue.\n","date":null,"permalink":"https://brandon.dimcheff.com/","section":"Brandon Dimcheff","summary":"\u003cp\u003eBrandon Dimcheff is a software engineer born and raised in Ann Arbor, Michigan, and educated at the University of Michigan. He uses go for his day job, wrangles pods with Kubernetes, is an aspiring functional programming language nerd, and is an advocate of open source. He\u0026rsquo;s an urbanist who loves density, bike lanes, and transit. In his free time, he\u0026rsquo;s a \n      \n    \u003ca href=\"https://brandon.dimcheff.com/recipe/\"\u003epretty good cook\u003c/a\u003e and tries to spend a lot of time on his bike or knee deep in powder.\u003c/p\u003e","title":"Brandon Dimcheff"},{"content":"","date":null,"permalink":"https://brandon.dimcheff.com/recipe/","section":"Recipes","summary":"","title":"Recipes"}]