And now it’s all this

Web Name: And now it’s all this

WebSite: http://www.leancrew.com

ID:146755

Keywords:

now,And,it,

Description:

LaunchBar and LaTeXDecember 12, 2020 at 6:50 PM by Dr. DrangWhen I send a proposal for new work to a client, I do it in the form of a letter addressed to the client and emailed to them as a PDF attachment.1 I write the letter in LaTeX, using TextExpander for the boilerplate and then filling in the job-specific parts. One of the job-specific parts is the name and address of the client, which, in a LaTeX letter, is the second argument to the \begin block:\begin{letter}{John Appleseed\\Apple Inc.\\1 Infinite Loop\\Cupertino, CA 95014}In LaTeX, linebreaks in multiline blocks of text have to be preceded by a pair of backslashes. Also, because the ampersand is a special character in LaTeX, it has to be escaped with a backslash. Thus, the firm of Dewey, Cheatham Howe has to be written in the LaTeX source as Dewey, Cheatham \ Howe.Over the years, I’ve written several little scripts to format addresses for LaTeX. They’ve all done the job, but they’ve all forced me to eithermove out of my text editor to run the script and then return to paste the result; orenter a shell command within the text editor and then select and run it.Neither is the way I want to work.When writing on the Mac, I use LaunchBar to look up contacts. I tap ⌘-Space, start typing the contact’s name, and up it pops.What I want is to be able to run a command at this point that gets the address, puts it in LaTeX form, and pastes it into the letter where the cursor is sitting. This past week, I finally got around to writing a script that does just that.It uses LaunchBar’s “sending” feature to pass the contact to a script that assembles, formats, and pastes the address—all without leaving LaunchBar. The idea is that after getting the contact as above, I can tap the Tab key to bring up a list of things I can do with it:Choosing the LaTeXAddress script sends the contact to that script, which then inserts the formatted name and address. No switching out of and back into my text editor, and no messing around with the clipboard.While I was at it, I decided the script should also handle an address sent to it. That would happen if I select the contact’s address instead of the contact itself:Will I ever use it this way? It adds an extra step, so probably not. But it was fairly easy to add this extra capability, and it’s usually better to finish off a project when it’s fresh in your mind.Here’s the LateXAddress script:applescript: 1: use AppleScript version "2.4" -- Yosemite (10.10) or later 2: use scripting additions 4: (* This script is to be used within LaunchBar. It is sent either a 5: contact or the address of a contact. When sent a contact, the argument 6: of handle_string is the full name of the contact as a single line of 7: text. When sent an address,the argument of handle_string is the street 8: address as a multi-line block of text with an attn: line that contains 9: the name.*) 10: 11: -- The US may show up as any of these names in the country field. 12: property usNames : {"USA", "US", "United States", "United States of America"} 13: 14: -- Handle string passed in from LaunchBar 15: on handle_string(s) 16: set sList to paragraphs of s 17: 18: -- Get the plain name and address as a list of text lines. 19: -- The method called depends on whether a single-line name 20: -- or multi-line address (with attn:) is passed in. 21: if (count of sList) is 1 then 22: set plainList to addressFromName(s) 23: else 24: set plainList to addressFromAddress(sList) 25: end if 26: 27: -- Convert from plain name and address to LaTeX 28: set blockText to latexify(plainList) 29: 30: -- Insert it at the cursor 31: tell application "LaunchBar" to paste in frontmost application blockText 32: end handle_string 33: 34: 35: -- Strip the US line part of the address if it's there 36: on stripUS(aList) 37: if last item of aList is in usNames then 38: return items 1 thru -2 of aList 39: end if 40: end stripUS 41: 42: 43: -- Convert from list of lines of plain address to text block 44: -- formatted according to LaTeX rules 45: on latexify(aList) 46: set oldDelims to AppleScript's text item delimiters 47: set AppleScript's text item delimiters to linefeed 48: 49: -- Escape the ampersands and end each line except the last with two backslashes 50: set cmd to "echo " quoted form of (aList as text) ¬ 51: "| sed 's/ /\\\\ /g' " ¬ 52: "| sed '$!s/$/\\\\\\\\/' " 53: set newBlock to do shell script cmd 54: return newBlock 55: 56: set AppleScript's text item delimiters to oldDelims 57: end latexify 58: 59: 60: -- Handle single-line name 61: on addressFromName(fullname) 62: tell application "Contacts" 63: --Find the contact with that name 64: set match to first item of (people whose name is fullname) 65: 66: -- Get the address and strip the country if US 67: set addr to formatted address of first item of (addresses of match) 68: set addrList to paragraphs of addr 69: set addrList to my stripUS(addrList) 70: 71: -- Add the company to the top of the list of lines 72: set org to organization of match 73: if org is not missing value then 74: set beginning of addrList to org 75: end if 76: 77: -- Add the name to top of the list of lines 78: set beginning of addrList to fullname 79: 80: end tell 81: 82: return addrList 83: end addressFromName 84: 85: 86: -- Handle multi-line address 87: on addressFromAddress(aList) 88: -- Strip the country if US 89: set aList to stripUS(aList) 90: 91: -- Loop through and find the addressee via the attn: line 92: -- Keep track of the attn: line number and save in aLine 93: set lCount to 1 94: repeat with theLine in aList 95: if (word 1 of theLine) is "attn" then 96: set aLength to length of theLine 97: set addressee to text 7 thru aLength of theLine 98: set aLine to lCount 99: end if100: set lCount to lCount + 1101: end repeat102: 103: -- Build a list with everything except the attn: line104: set addrList to items 1 thru (aLine - 1) of aList items (aLine + 1) thru -1 of aList105: set beginning of addrList to addressee106: 107: return addrList108: end addressFromAddressThe handle_string handler, Lines 15–32, is required and is the entry point for the script. Depending on how LaTeXAddress is called, it will get passed either the name of the selected contact—e.g., John Appleseed—or the selected address, which will be a block of text in this form:Apple, Inc.attn: John Appleseed1 Infinite LoopCupertino CA 95014The handle_string function splits its argument into a list of lines (in AppleScript parlance, paragraphs are separated by linefeeds). If there’s only one line, we know that the argument is the full name of the contact, and the addressFromName handler is called. If there’s more than one line, we know the argument is an address block, and the addressFromAddress handler is called. Both of these functions return a list of address lines in the variable plainList, which is then reformatted on Line 28 by the latexify function and then pasted at the cursor position of the current document by the tell application "LaunchBar"… command on Line 31.The addressFromName function finds the contact from their name (Line 64) and gets the first address listed for that contact (Line 67). It then splits this block of text into lines, stripping off the last line if it’s “USA” or any of the other names in the usNames property defined in Line 12.The idea here is that the country name is unnecessary for an address in the US. It’s only my Canadian clients that need the country included in the address. The stripping is done by the function stripUS, defined on Lines 36–40.Lines 72–75 add the company name (if there is one) to the top of the list of lines. Line 78 adds the contact’s name to the top of the list. This list of lines is what addressFromName returns.The addressFromAddress handler is just a text manipulation function. Line 89 calls stripUS to get rid of the superfluous country name, if present. The rest of the function looks for an attn: line, removes it, and adds the addressee from that line to the top of the list.The latexify function takes a list of address lines and returns a block of text properly formatted for a LaTeX document. The bulk of the work is done by the pipeline of three sed commands on Lines 51–52. The first one,sed 's/ /\\\\ /g'escapes all the ampersands. There are four backslashes in the replacement because this command is processed first by AppleScript, which eats half of the backslashes, and then by the shell, which also eats half of the backslashes. So AppleScript turns four backslashes into two, and then the shell turns two into one. And that’s what we want, one backslash in front of every ampersand. Because there’s no prefix before the s (substitute) command, the command is applied to each line. The g (global) flag at the end of the command tells sed to apply the substitution for every ampersand it finds on a given line.The second sed command,sed '$!s/$/\\\\\\\\/'adds the backslashes required at the ends of the lines. Once again, both AppleScript and the shell consume half of the backslashes, so we need to start with eight to end up with two. The lines to which this substitution is applied are defined by the $! prefix that comes before the s. This is a two-part definition. The $ says to select only the last line, and the ! says to negate (or invert) that selection. The inverse of the last line is every line except the last line, which, if you look at the example up at the top of the post, is exactly what we want.This system for inserting LaTeX-formatted addresses is more efficient than anything I’ve previously made. It’s possible I can squeeze out another keystroke by building a LaunchBar Action based on this script, but I’m not sure that’s worth the effort. I’ll live with what I have for a while.This may seem old-fashioned to you, but it’s what my clients prefer. ↩Good-bye to SetappDecember 8, 2020 at 11:38 AM by Dr. DrangI held off on Setapp for quite a while, despite all the recommendations it got from people I trust. I already owned several of the apps in its inventory, and the great majority of those I didn’t own weren’t all that appealing to me. But last year, when Setapp was doing a Black Friday sale on a year’s subscription, I succumbed.Over the course of the year, I installed maybe 15–20 of its apps. They fell into five categories:Those that had interesting descriptions but were just wrong for me. These were usually uninstalled after a quick trial. The exception was Better Touch Tool, which I really wanted to like and kept installed for at least a month. But it never clicked1 for me.Those that worked well, often an improvement over some command-line utility, but not used often. Downie is probably the best example. It’s basically youtube-dl with a GUI. I kept it installed for the entire year, but didn’t use it more than 2–3 times. Returning to youtube-dl won’t be a hardship.Those that replaced an app I use reasonably often, but which weren’t that much better than what I’d been using before. Renamer is the exemplar in this category. I usually rename files at the command line, but sometimes I want a nice GUI preview before going ahead with the renaming. Renamer was good for that, but I already own a copy of Better File Rename, and I’m perfectly comfortable returning to it.Those that were updated versions of apps I already owned, like BusyCal and PDFpen. I installed BusyCal because I prefer its look to that of Apple’s Calendar app, particularly the weather and moon phase data. Ultimately, though, it’s not really a replacement for Calendar because it doesn’t have an AppleScript dictionary,2 which is why I hadn’t updated the version I bought several years ago. Moving back to Calendar has been just fine, possibly because I see the weather and moon phase regularly on my phone.Similarly, I hadn’t updated PDFpen for a while, so I installed the Setapp version (v. 12). I’m not sure what’s changed between over the past few years, but I found myself using the Setapp PDFpen quite a lot, so I’ll be updating my purchased version. That’ll cost me $30.Finally, there was one app that I didn’t own before and that I used regularly over the year: Base, the SQLite frontend from Menial. I’ve written several scripts that interact with SQLite databases, but those are for standard operations that do the same thing over and over. One-off changes—like when a client’s email address changes—are easier to do through a GUI. Setapp includes a handful of database frontends, and I tried them all before settling on Base. Its layout is simple, and it’s easy to search without building an SQL query from scratch. When my Setapp subscription ran out last week, I bought it from the Mac App Store for $20.If I didn’t already own apps like PDFpen, Bartender, Marked, and Default Folder X, Setapp would make a lot of sense for me. But I do, so it doesn’t. Still, I wouldn’t have known that if I hadn’t given it a try. I’m walking away perfectly happy with the year I spent with it.You may be surprised to hear this—I certainly was. BusyMac positions its apps as pro-level versions of the standard Mac apps, but to my way of thinking, scriptability is the pro feature. ↩A simple shortcut for directionsOctober 30, 2020 at 12:17 PM by Dr. DrangLast week, I got angry at Siri:Me, in car: Hey, Siri, get directions to my next appointment.Siri: OK, where do you want to go?M, through gritted teeth: My next appointment.S: Your next appointment is blah blah blah…M: opens Calendar, taps Location — Dr. Drang (@drdrang) October 21, 2020What’s frustrating about this, of course, is that Siri has access to all the information necessary to give me what I want:It knows how to interpret “next appointment.”It knows the location of that entry in my calendar. If I ask “Where is my next appointment?” it answers with the address.It knows how to get directions to a location.As is too often the case, Siri’s inability to tie things together is its greatest failure.Fortunately, Shortcuts allows us to apply real intelligence where artificial intelligence fails. Here’s a simple shortcut called Next Location.StepActionCommentI chose the “Find Calendar Events” action instead of “Get Upcoming Events” because I wanted to make sure the event returned has a Location associated with it, and the filtering included with this action gives me that. I must say the terminology used for the Order is confusing; the choices should be Earliest/Latest not Oldest/Latest. “Oldest” is not the opposite of “latest.”Now I can say “Hey, Siri, next location” to get the directions. I still have to tap a button to choose one of the three sets of directions the phone gives me, but that’s better than screaming “What the fuck is wrong with you?!” when sitting in a car by myself.Interrupted loopsOctober 9, 2020 at 8:51 PM by Dr. DrangA few days ago, I ran across last week’s edition of Matt Parker’s Maths Puzzles. It’s a simple challenge: rearrange the numbers 1–9, inclusive, so that each sequential pair sum to a prime number.It’s not hard to come up with a solution. After all, the original sequence,1, 2, 3, 4, 5, 6, 7, 8, 9has lots of pairs that add to primes, and it takes only a switch of the 5 and 7 to get a sequence that works:1, 2, 3, 4, 7, 6, 5, 8, 9What’s more interesting is to come up with all the solutions, and it’s natural to assume that that’s best done by writing a program.My first thought was to use brute force. Generate all the permutations of the list and go through them, keeping only the ones that meet the prime pairs criterion. Brute force is often the best solution when you need an answer quickly and want a solution that’s easy to explain.“Quickly” is in the eye of the beholder. A clever algorithm will undoubtedly run much faster, but it may take much longer to work out and debug than the dumb algorithm takes to run. Clever algorithms are essential when a program has to run again and again, but brute force is often the way to go when your program is a one-off.Looking at every permutation seemed feasible in this case, as there are only 9! = 362,880 ways to arrange the nine numbers. And I wouldn’t have to come up with a way to get all the permutations, because the itertools library already has a function for that. So I started writing:python: 1: from itertools import permutations 3: # Initialization 4: numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9] 5: primes = [3, 5, 7, 11, 13, 17] 6: winners = [] 8: # Loop though the permutations, collecting only prime pairs 9: for p in permutations(numbers):10: for i in range(1, 9):11: if p[i-1] + p[i] not in primes:12: breakAt this point, I had to stop and think. The problem is that the break statement will only break me out of the inner loop, the one that starts on Line 10. But when I run into a pair that don’t add to a prime, I want to move on to the next item in the outer loop, like a continue statement. Neither break nor continue have a way to specify how far out to break or where to continue from. Old Fortran habits started to bubble up in my brain, and I began to wish for a goto statement, but Python doesn’t have one.1A clumsy solution is to add a flag variable for keeping track of whether you broke out of the inner loop or exited it normally.python: 1: from itertools import permutations 3: # Initialization 4: numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9] 5: primes = [3, 5, 7, 11, 13, 17] 6: winners = [] 8: # Loop though the permutations, collecting only prime pairs 9: for p in permutations(numbers):10: allPrimes = True11: for i in range(1, 9):12: if p[i-1] + p[i] not in primes:13: allPrimes = False14: break15: if allPrimes:16: winners.append(p)18: # Print the results19: print(len(winners))20: for p in winners:21: print(p)I know I’m doing a brute force solution, but I have some pride and didn’t like the way this looked.A few years ago Ned Batchelder wrote a post about breaking out of two loops, and here’s what he had to say about this method:Use boolean variables to note that the loop is done, and check the variable in the outer loop to execute a second break. This is a low-tech solution, and may be right for some cases, but is mostly just extra noise and bookkeeping.In this case, we’re not really breaking out of two loops, but the idea is the same: extra noise and bookkeeping.Batchelder’s suggestion is to use a function to handle the inner loop and simplify the outer loop. Like this:python: 1: from itertools import permutations 3: # Initialization 4: numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9] 5: primes = [3, 5, 7, 11, 13, 17] 6: winners = [] 8: def primePairs(s): 9: '''Do all the pairs in s sum to a prime?'''10: for i in range(1, 9):11: if s[i-1] + s[i] not in primes:12: return False13: return True15: # Loop though the permutations, collecting only prime pairs16: for p in permutations(numbers):17: if primePairs(p):18: winners.append(p)20: # Print the results21: print(len(winners))22: for p in winners:23: print(p)This is slightly longer but is definitely easier to understand. We’ve applied some good old-fashioned structured programming ideas to put the sequence checker into its own function. It’s clear what it does, and by isolating it, we’ve also made the main loop, Lines 16–18, clearer.But Python has another trick up its sleeve. In the clumsy solution, we used a flag variable, allPrimes, to keep track of whether we exited the loop normally or by breaking out. But Python already has a way to do that: the else clause of a for loop. Here’s what the docs say:Loop statements may have an else clause; it is executed when the loop terminates through exhaustion of the iterable (with for) or when the condition becomes false (with while), but not when the loop is terminated by a break statement.I confess I’ve never used this before, but it’s really simple:python: 1: from itertools import permutations 3: # Initialization 4: numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9] 5: primes = [3, 5, 7, 11, 13, 17] 6: winners = [] 8: # Loop though the permutations, collecting only prime pairs 9: for p in permutations(numbers):10: for i in range(1, 9):11: if p[i-1] + p[i] not in primes:12: break13: else:14: winners.append(p)16: # Print the results17: print(len(winners))18: for p in winners:19: print(p)If we get to the end of the inner for loop without breaking, the winners.append(p) statement in the else clause is executed. If we run into a non-prime sum in Line 11, the break in Line 12 breaks us out of the entire for/else construct and we move on to the next permutation in the outer loop.I’m not sure whether I prefer the function solution or this one. My natural tendency is to go with the shorter code, but else doesn’t strike me as the right word to describe what this code is doing. In fact, my first instinct is to think that the else clause is invoked when the loop doesn’t complete normally, which is the exact opposite of how it behaves.Whether I ever write code with a for/else again, it’s good to know it exists and how to use it.And if you were wondering, there are 140 ways to reorder the list to get all the sequential pairs to sum to a prime number. You could argue that there are really only 70, with the other 70 being the same sequences in reverse. I won’t take sides; I was just here to hone my Python skills.There are at least a couple of third-party libraries that provide goto, but I didn’t want to resort to them. ↩

TAGS:now And it 

<<< Thank you for your visit >>>

Websites to related :
静岡県立大学薬学研究院薬科学専攻

  全合成道場をアメリカ化学会 Division of Organic Chemistry の Organic Chemistry Data にリンクしていただきました。 6月8日からレベル1になったので、ソーシャル

Home | seleniteswordmaker.com

  Selenite Swords of Light are some of the highest vibration energy tools available to practitioners today, and hand crafted from pure selenite crystal.

All County Jobs

  As of July 1, 2018, AllCountyJobs.com and its 27 affiliate sites have suspended operations. We want to thank our Clients and Job Seekers for your supp

Intelligent Insurer - Home

  Year in review 2020: the long shadow of the FCA BI test caseFrom the impact of the UK Financial Conduct Authority business interruption test case, and

Healthcare Marketing and Medical

  AHealthcare MarketingAgency that Wins Patients, Grows Revenues and Enhances Your ReputationDone properly, ethicalmedical marketingcan grow your profit

Футбол-Хоккей Южн

  Уважаемые читатели! Используйте Telegram для переписки. Присоединяйтесь!Подробнее...

Portal - X-Plane.Org Forum

  We are happy to announce that the SMS Beaver 1.3 update has been released for Christmas.You may also be interested in the development roadmap for the

Direct Selling News

  In toughtimes,the strong grow stronger. The organizations that will perform the best through this period and beyond will be those that maintain a stro

Yacht Controller - Wireless Remo

  Innovative Technology for the Marine Industry "The Most Trusted Product in the Marine Industry" Take total control of your boat with innovative techno

Spitfire Graveyard

  We are a specialist car parts stockist based in North Sheffield. We specialise in Triumph cars but have parts for many different cars. We accept card

ads

Hot Websites