GF2QFPRRD67Y6EORPB2YU5VVX6VGMOJQDGGZGO6BKBWBIKRRQ6UAC
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>ANSIBlackColor</key>
<data>
YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMS
AAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGjCwwTVSRudWxs0w0ODxARElVO
U1JHQlxOU0NvbG9yU3BhY2VWJGNsYXNzTxAnMC4xMTc2NDcwNTg4IDAuMTI5NDExNzY0
NyAwLjE1Mjk0MTE3NjUAEAGAAtIUFRYXWiRjbGFzc25hbWVYJGNsYXNzZXNXTlNDb2xv
cqIWGFhOU09iamVjdAgRGiQpMjdJTFFTV11kand+qKqssbzFzdAAAAAAAAABAQAAAAAA
AAAZAAAAAAAAAAAAAAAAAAAA2Q==
</data>
<key>ANSIBlueColor</key>
<data>
YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMS
AAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGjCwwTVSRudWxs0w0ODxARElVO
U1JHQlxOU0NvbG9yU3BhY2VWJGNsYXNzTxAmMC4zODAzOTIxNTY5IDAuNjg2Mjc0NTA5
OCAwLjkzNzI1NDkwMgAQAYAC0hQVFhdaJGNsYXNzbmFtZVgkY2xhc3Nlc1dOU0NvbG9y
ohYYWE5TT2JqZWN0CBEaJCkyN0lMUVNXXWRqd36nqauwu8TMzwAAAAAAAAEBAAAAAAAA
ABkAAAAAAAAAAAAAAAAAAADY
</data>
<key>ANSIBrightBlackColor</key>
<data>
YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMS
AAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGjCwwTVSRudWxs0w0ODxARElVO
U1JHQlxOU0NvbG9yU3BhY2VWJGNsYXNzTxAnMC4zNjA3ODQzMTM3IDAuMzg4MjM1Mjk0
MSAwLjQzOTIxNTY4NjMAEAGAAtIUFRYXWiRjbGFzc25hbWVYJGNsYXNzZXNXTlNDb2xv
cqIWGFhOU09iamVjdAgRGiQpMjdJTFFTV11kand+qKqssbzFzdAAAAAAAAABAQAAAAAA
AAAZAAAAAAAAAAAAAAAAAAAA2Q==
</data>
<key>ANSIBrightBlueColor</key>
<data>
YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMS
AAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGjCwwTVSRudWxs0w0ODxARElVO
U1JHQlxOU0NvbG9yU3BhY2VWJGNsYXNzTxAmMC4zODAzOTIxNTY5IDAuNjg2Mjc0NTA5
OCAwLjkzNzI1NDkwMgAQAYAC0hQVFhdaJGNsYXNzbmFtZVgkY2xhc3Nlc1dOU0NvbG9y
ohYYWE5TT2JqZWN0CBEaJCkyN0lMUVNXXWRqd36nqauwu8TMzwAAAAAAAAEBAAAAAAAA
ABkAAAAAAAAAAAAAAAAAAADY
</data>
<key>ANSIBrightCyanColor</key>
<data>
YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMS
AAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGjCwwTVSRudWxs0w0ODxARElVO
U1JHQlxOU0NvbG9yU3BhY2VWJGNsYXNzTxAmMC4zMzcyNTQ5MDIgMC43MTM3MjU0OTAy
IDAuNzYwNzg0MzEzNwAQAYAC0hQVFhdaJGNsYXNzbmFtZVgkY2xhc3Nlc1dOU0NvbG9y
ohYYWE5TT2JqZWN0CBEaJCkyN0lMUVNXXWRqd36nqauwu8TMzwAAAAAAAAEBAAAAAAAA
ABkAAAAAAAAAAAAAAAAAAADY
</data>
<key>ANSIBrightGreenColor</key>
<data>
YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMS
AAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGjCwwTVSRudWxs0w0ODxARElVO
U1JHQlxOU0NvbG9yU3BhY2VWJGNsYXNzTxAnMC41OTYwNzg0MzE0IDAuNzY0NzA1ODgy
NCAwLjQ3NDUwOTgwMzkAEAGAAtIUFRYXWiRjbGFzc25hbWVYJGNsYXNzZXNXTlNDb2xv
cqIWGFhOU09iamVjdAgRGiQpMjdJTFFTV11kand+qKqssbzFzdAAAAAAAAABAQAAAAAA
AAAZAAAAAAAAAAAAAAAAAAAA2Q==
</data>
<key>ANSIBrightMagentaColor</key>
<data>
YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMS
AAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGjCwwTVSRudWxs0w0ODxARElVO
U1JHQlxOU0NvbG9yU3BhY2VWJGNsYXNzTxAnMC43NzY0NzA1ODgyIDAuNDcwNTg4MjM1
MyAwLjg2NjY2NjY2NjcAEAGAAtIUFRYXWiRjbGFzc25hbWVYJGNsYXNzZXNXTlNDb2xv
cqIWGFhOU09iamVjdAgRGiQpMjdJTFFTV11kand+qKqssbzFzdAAAAAAAAABAQAAAAAA
AAAZAAAAAAAAAAAAAAAAAAAA2Q==
</data>
<key>ANSIBrightRedColor</key>
<data>
YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMS
AAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGjCwwTVSRudWxs0w0ODxARElVO
U1JHQlxOU0NvbG9yU3BhY2VWJGNsYXNzTxAnMC44Nzg0MzEzNzI1IDAuNDIzNTI5NDEx
OCAwLjQ1ODgyMzUyOTQAEAGAAtIUFRYXWiRjbGFzc25hbWVYJGNsYXNzZXNXTlNDb2xv
cqIWGFhOU09iamVjdAgRGiQpMjdJTFFTV11kand+qKqssbzFzdAAAAAAAAABAQAAAAAA
AAAZAAAAAAAAAAAAAAAAAAAA2Q==
</data>
<key>ANSIBrightWhiteColor</key>
<data>
YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMS
AAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGjCwwTVSRudWxs0w0ODxARElVO
U1JHQlxOU0NvbG9yU3BhY2VWJGNsYXNzTxAaMSAwLjk5OTk3NDM3IDAuOTk5OTkxMjk3
NwAQAYAC0hQVFhdaJGNsYXNzbmFtZVgkY2xhc3Nlc1dOU0NvbG9yohYYWE5TT2JqZWN0
CBEaJCkyN0lMUVNXXWRqd36bnZ+kr7jAwwAAAAAAAAEBAAAAAAAAABkAAAAAAAAAAAAA
AAAAAADM
</data>
<key>ANSIBrightYellowColor</key>
<data>
YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMS
AAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGjCwwTVSRudWxs0w0ODxARElVO
U1JHQlxOU0NvbG9yU3BhY2VWJGNsYXNzTxAeMC44MTk2MDc4NDMxIDAuNjAzOTIxNTY4
NiAwLjQAEAGAAtIUFRYXWiRjbGFzc25hbWVYJGNsYXNzZXNXTlNDb2xvcqIWGFhOU09i
amVjdAgRGiQpMjdJTFFTV11kand+n6GjqLO8xMcAAAAAAAABAQAAAAAAAAAZAAAAAAAA
AAAAAAAAAAAA0A==
</data>
<key>ANSICyanColor</key>
<data>
YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMS
AAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGjCwwTVSRudWxs0w0ODxARElVO
U1JHQlxOU0NvbG9yU3BhY2VWJGNsYXNzTxAmMC4zMzcyNTQ5MDIgMC43MTM3MjU0OTAy
IDAuNzYwNzg0MzEzNwAQAYAC0hQVFhdaJGNsYXNzbmFtZVgkY2xhc3Nlc1dOU0NvbG9y
ohYYWE5TT2JqZWN0CBEaJCkyN0lMUVNXXWRqd36nqauwu8TMzwAAAAAAAAEBAAAAAAAA
ABkAAAAAAAAAAAAAAAAAAADY
</data>
<key>ANSIGreenColor</key>
<data>
YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMS
AAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGjCwwTVSRudWxs0w0ODxARElVO
U1JHQlxOU0NvbG9yU3BhY2VWJGNsYXNzTxAnMC41OTYwNzg0MzE0IDAuNzY0NzA1ODgy
NCAwLjQ3NDUwOTgwMzkAEAGAAtIUFRYXWiRjbGFzc25hbWVYJGNsYXNzZXNXTlNDb2xv
cqIWGFhOU09iamVjdAgRGiQpMjdJTFFTV11kand+qKqssbzFzdAAAAAAAAABAQAAAAAA
AAAZAAAAAAAAAAAAAAAAAAAA2Q==
</data>
<key>ANSIMagentaColor</key>
<data>
YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMS
AAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGjCwwTVSRudWxs0w0ODxARElVO
U1JHQlxOU0NvbG9yU3BhY2VWJGNsYXNzTxAnMC43NzY0NzA1ODgyIDAuNDcwNTg4MjM1
MyAwLjg2NjY2NjY2NjcAEAGAAtIUFRYXWiRjbGFzc25hbWVYJGNsYXNzZXNXTlNDb2xv
cqIWGFhOU09iamVjdAgRGiQpMjdJTFFTV11kand+qKqssbzFzdAAAAAAAAABAQAAAAAA
AAAZAAAAAAAAAAAAAAAAAAAA2Q==
</data>
<key>ANSIRedColor</key>
<data>
YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMS
AAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGjCwwTVSRudWxs0w0ODxARElVO
U1JHQlxOU0NvbG9yU3BhY2VWJGNsYXNzTxAnMC44Nzg0MzEzNzI1IDAuNDIzNTI5NDEx
OCAwLjQ1ODgyMzUyOTQAEAGAAtIUFRYXWiRjbGFzc25hbWVYJGNsYXNzZXNXTlNDb2xv
cqIWGFhOU09iamVjdAgRGiQpMjdJTFFTV11kand+qKqssbzFzdAAAAAAAAABAQAAAAAA
AAAZAAAAAAAAAAAAAAAAAAAA2Q==
</data>
<key>ANSIWhiteColor</key>
<data>
YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMS
AAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGjCwwTVSRudWxs0w0ODxARElVO
U1JHQlxOU0NvbG9yU3BhY2VWJGNsYXNzTxAnMC42NzA1ODgyMzUzIDAuNjk4MDM5MjE1
NyAwLjc0OTAxOTYwNzgAEAGAAtIUFRYXWiRjbGFzc25hbWVYJGNsYXNzZXNXTlNDb2xv
cqIWGFhOU09iamVjdAgRGiQpMjdJTFFTV11kand+qKqssbzFzdAAAAAAAAABAQAAAAAA
AAAZAAAAAAAAAAAAAAAAAAAA2Q==
</data>
<key>ANSIYellowColor</key>
<data>
YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMS
AAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGjCwwTVSRudWxs0w0ODxARElVO
U1JHQlxOU0NvbG9yU3BhY2VWJGNsYXNzTxAeMC44MTk2MDc4NDMxIDAuNjAzOTIxNTY4
NiAwLjQAEAGAAtIUFRYXWiRjbGFzc25hbWVYJGNsYXNzZXNXTlNDb2xvcqIWGFhOU09i
amVjdAgRGiQpMjdJTFFTV11kand+n6GjqLO8xMcAAAAAAAABAQAAAAAAAAAZAAAAAAAA
AAAAAAAAAAAA0A==
</data>
<key>BackgroundAlphaInactive</key>
<real>0.80306177745664742</real>
<key>BackgroundBlur</key>
<real>0.0</real>
<key>BackgroundBlurInactive</key>
<real>0.0</real>
<key>BackgroundColor</key>
<data>
YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMS
AAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGjCwwTVSRudWxs0w0ODxARElVO
U1JHQlxOU0NvbG9yU3BhY2VWJGNsYXNzTxAnMC4xMTc2NDcwNTg4IDAuMTI5NDExNzY0
NyAwLjE1Mjk0MTE3NjUAEAGAAtIUFRYXWiRjbGFzc25hbWVYJGNsYXNzZXNXTlNDb2xv
cqIWGFhOU09iamVjdAgRGiQpMjdJTFFTV11kand+qKqssbzFzdAAAAAAAAABAQAAAAAA
AAAZAAAAAAAAAAAAAAAAAAAA2Q==
</data>
<key>BackgroundSettingsForInactiveWindows</key>
<true/>
<key>BlinkText</key>
<false/>
<key>CursorColor</key>
<data>
YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMS
AAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGjCwwTVSRudWxs0w0ODxARElVO
U1JHQlxOU0NvbG9yU3BhY2VWJGNsYXNzTxAnMC4zNjA3ODQzMTM3IDAuMzg4MjM1Mjk0
MSAwLjQzOTIxNTY4NjMAEAGAAtIUFRYXWiRjbGFzc25hbWVYJGNsYXNzZXNXTlNDb2xv
cqIWGFhOU09iamVjdAgRGiQpMjdJTFFTV11kand+qKqssbzFzdAAAAAAAAABAQAAAAAA
AAAZAAAAAAAAAAAAAAAAAAAA2Q==
</data>
<key>CursorType</key>
<integer>0</integer>
<key>DisableANSIColor</key>
<false/>
<key>Font</key>
<data>
YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMS
AAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGkCwwVFlUkbnVsbNQNDg8QERIT
FFZOU1NpemVYTlNmRmxhZ3NWTlNOYW1lViRjbGFzcyNALAAAAAAAABAQgAKAA18QEEZp
cmFDb2RlLVJlZ3VsYXLSFxgZGlokY2xhc3NuYW1lWCRjbGFzc2VzVk5TRm9udKIZG1hO
U09iamVjdAgRGiQpMjdJTFFTWF5nbnd+hY6QkpSnrLfAx8oAAAAAAAABAQAAAAAAAAAc
AAAAAAAAAAAAAAAAAAAA0w==
</data>
<key>FontAntialias</key>
<true/>
<key>FontHeightSpacing</key>
<integer>1</integer>
<key>FontWidthSpacing</key>
<integer>1</integer>
<key>ProfileCurrentVersion</key>
<real>2.0699999999999998</real>
<key>RestoreLines</key>
<integer>3600</integer>
<key>ScrollAlternateScreen</key>
<false/>
<key>ScrollbackLines</key>
<integer>3600</integer>
<key>SelectionColor</key>
<data>
YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMS
AAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGjCwwTVSRudWxs0w0ODxARElVO
U1JHQlxOU0NvbG9yU3BhY2VWJGNsYXNzTxAnMC4yMjc0NTA5ODA0IDAuMjQ3MDU4ODIz
NSAwLjI5NDExNzY0NzEAEAGAAtIUFRYXWiRjbGFzc25hbWVYJGNsYXNzZXNXTlNDb2xv
cqIWGFhOU09iamVjdAgRGiQpMjdJTFFTV11kand+qKqssbzFzdAAAAAAAAABAQAAAAAA
AAAZAAAAAAAAAAAAAAAAAAAA2Q==
</data>
<key>ShouldLimitScrollback</key>
<integer>1</integer>
<key>ShowActiveProcessArgumentsInTabTitle</key>
<false/>
<key>ShowActiveProcessArgumentsInTitle</key>
<false/>
<key>ShowActiveProcessInTitle</key>
<false/>
<key>ShowDimensionsInTitle</key>
<true/>
<key>ShowRepresentedURLInTitle</key>
<true/>
<key>ShowRepresentedURLPathInTitle</key>
<false/>
<key>ShowShellCommandInTitle</key>
<false/>
<key>ShowTTYNameInTitle</key>
<false/>
<key>ShowWindowSettingsNameInTitle</key>
<false/>
<key>TerminalType</key>
<string>ansi</string>
<key>TextBoldColor</key>
<data>
YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMS
AAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGjCwwTVSRudWxs0w0ODxARElVO
U1JHQlxOU0NvbG9yU3BhY2VWJGNsYXNzTxAnMC42NzA1ODgyMzUzIDAuNjk4MDM5MjE1
NyAwLjc0OTAxOTYwNzgAEAGAAtIUFRYXWiRjbGFzc25hbWVYJGNsYXNzZXNXTlNDb2xv
cqIWGFhOU09iamVjdAgRGiQpMjdJTFFTV11kand+qKqssbzFzdAAAAAAAAABAQAAAAAA
AAAZAAAAAAAAAAAAAAAAAAAA2Q==
</data>
<key>TextColor</key>
<data>
YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMS
AAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGjCwwTVSRudWxs0w0ODxARElVO
U1JHQlxOU0NvbG9yU3BhY2VWJGNsYXNzTxAnMC42NzA1ODgyMzUzIDAuNjk4MDM5MjE1
NyAwLjc0OTAxOTYwNzgAEAGAAtIUFRYXWiRjbGFzc25hbWVYJGNsYXNzZXNXTlNDb2xv
cqIWGFhOU09iamVjdAgRGiQpMjdJTFFTV11kand+qKqssbzFzdAAAAAAAAABAQAAAAAA
AAAZAAAAAAAAAAAAAAAAAAAA2Q==
</data>
<key>UseBoldFonts</key>
<false/>
<key>UseBrightBold</key>
<false/>
<key>VisualBell</key>
<true/>
<key>WindowTitle</key>
<string></string>
<key>blackColour</key>
<data>
BAtzdHJlYW10eXBlZIHoA4QBQISEhAdOU0NvbG9yAISECE5TT2JqZWN0AIWEAWMBhARm
ZmZmg7JNIT2DkvUjPoO+F0s+AYY=
</data>
<key>blueColour</key>
<data>
BAtzdHJlYW10eXBlZIHoA4QBQISEhAdOU0NvbG9yAISECE5TT2JqZWN0AIWEAWMBhARm
ZmZmgyqcAj6DtOHsPoO+RUg/AYY=
</data>
<key>brightBlackColour</key>
<data>
BAtzdHJlYW10eXBlZIHoA4QBQISEhAdOU0NvbG9yAISECE5TT2JqZWN0AIWEAWMBhARm
ZmZmg+ZzgjyDs44BPoNahyM+AYY=
</data>
<key>brightBlueColour</key>
<data>
BAtzdHJlYW10eXBlZIHoA4QBQISEhAdOU0NvbG9yAISECE5TT2JqZWN0AIWEAWMBhARm
ZmZmg7yT4T6DEXcCP4POUAQ/AYY=
</data>
<key>brightCyanColour</key>
<data>
BAtzdHJlYW10eXBlZIHoA4QBQISEhAdOU0NvbG9yAISECE5TT2JqZWN0AIWEAWMBhARm
ZmZmg7CIAT+Dj5oQP4N8ShA/AYY=
</data>
<key>brightGreenColour</key>
<data>
BAtzdHJlYW10eXBlZIHoA4QBQISEhAdOU0NvbG9yAISECE5TT2JqZWN0AIWEAWMBhARm
ZmZmgzyujT6DFZy2PoOYFsQ+AYY=
</data>
<key>brightMagentaColour</key>
<data>
BAtzdHJlYW10eXBlZIHoA4QBQISEhAdOU0NvbG9yAISECE5TT2JqZWN0AIWEAWMBhARm
ZmZmgxMjsj6D+uazPoNkyTc/AYY=
</data>
<key>brightRedColour</key>
<data>
BAtzdHJlYW10eXBlZIHoA4QBQISEhAdOU0NvbG9yAISECE5TT2JqZWN0AIWEAWMBhARm
ZmZmgyfkPT+D/15aPoMgl5Y9AYY=
</data>
<key>brightWhiteColour</key>
<data>
BAtzdHJlYW10eXBlZIHoA4QBQISEhAdOU0NvbG9yAISECE5TT2JqZWN0AIWEAWMBhARm
ZmZmg49LfT+D0Dt1P4MGM10/AYY=
</data>
<key>brightYellowColour</key>
<data>
BAtzdHJlYW10eXBlZIHoA4QBQISEhAdOU0NvbG9yAISECE5TT2JqZWN0AIWEAWMBhARm
ZmZmg1MTpj6DeHnQPoPQg+A+AYY=
</data>
<key>columnCount</key>
<integer>120</integer>
<key>cyanColour</key>
<data>
BAtzdHJlYW10eXBlZIHoA4QBQISEhAdOU0NvbG9yAISECE5TT2JqZWN0AIWEAWMBhARm
ZmZmg4VRFj6DfyESP4PkZwY/AYY=
</data>
<key>greenColour</key>
<data>
BAtzdHJlYW10eXBlZIHoA4QBQISEhAdOU0NvbG9yAISECE5TT2JqZWN0AIWEAWMBhARm
ZmZmg9lI5j6DIYkKP4PVjKU8AYY=
</data>
<key>keyMapBoundKeys</key>
<dict>
<key>#F739</key>
<string>toggleNumLock:</string>
<key>$F702</key>
<string>[1;2D</string>
<key>$F703</key>
<string>[1;2C</string>
<key>$F708</key>
<string>[25~</string>
<key>$F709</key>
<string>[26~</string>
<key>$F70A</key>
<string>[28~</string>
<key>$F70B</key>
<string>[29~</string>
<key>$F70C</key>
<string>[31~</string>
<key>$F70D</key>
<string>[32~</string>
<key>$F70E</key>
<string>[33~</string>
<key>$F70F</key>
<string>[34~</string>
<key>$F728</key>
<string>[3;2~</string>
<key>F704</key>
<string>OP</string>
<key>F705</key>
<string>OQ</string>
<key>F706</key>
<string>OR</string>
<key>F707</key>
<string>OS</string>
<key>F708</key>
<string>[15~</string>
<key>F709</key>
<string>[17~</string>
<key>F70A</key>
<string>[18~</string>
<key>F70B</key>
<string>[19~</string>
<key>F70C</key>
<string>[20~</string>
<key>F70D</key>
<string>[21~</string>
<key>F70E</key>
<string>[23~</string>
<key>F70F</key>
<string>[24~</string>
<key>F710</key>
<string>[25~</string>
<key>F711</key>
<string>[26~</string>
<key>F712</key>
<string>[28~</string>
<key>F713</key>
<string>[29~</string>
<key>F714</key>
<string>[31~</string>
<key>F715</key>
<string>[32~</string>
<key>F716</key>
<string>[33~</string>
<key>F717</key>
<string>[34~</string>
<key>F728</key>
<string>[3~</string>
<key>F729</key>
<string></string>
<key>F72B</key>
<string></string>
<key>F72C</key>
<string></string>
<key>F72D</key>
<string></string>
<key>^F702</key>
<string>[1;5D</string>
<key>^F703</key>
<string>[1;5C</string>
<key>^F728</key>
<string>[3;5~</string>
<key>~F702</key>
<string>b</string>
<key>~F703</key>
<string>f</string>
<key>~F704</key>
<string>[17~</string>
<key>~F705</key>
<string>[18~</string>
<key>~F706</key>
<string>[19~</string>
<key>~F707</key>
<string>[20~</string>
<key>~F708</key>
<string>[21~</string>
<key>~F709</key>
<string>[23~</string>
<key>~F70A</key>
<string>[24~</string>
<key>~F70B</key>
<string>[25~</string>
<key>~F70C</key>
<string>[26~</string>
<key>~F70D</key>
<string>[28~</string>
<key>~F70E</key>
<string>[29~</string>
<key>~F70F</key>
<string>[31~</string>
<key>~F710</key>
<string>[32~</string>
<key>~F711</key>
<string>[33~</string>
<key>~F712</key>
<string>[34~</string>
<key>~^F728</key>
<string>[3;5~</string>
</dict>
<key>magentaColour</key>
<data>
BAtzdHJlYW10eXBlZIHoA4QBQISEhAdOU0NvbG9yAISECE5TT2JqZWN0AIWEAWMBhARm
ZmZmg/4CRz+DBTzdPYMgzt4+AYY=
</data>
<key>name</key>
<string>One Dark</string>
<key>redColour</key>
<data>
BAtzdHJlYW10eXBlZIHoA4QBQISEhAdOU0NvbG9yAISECE5TT2JqZWN0AIWEAWMBhARm
ZmZmg6i7UT+DUATePYMl2hA+AYY=
</data>
<key>rowCount</key>
<integer>36</integer>
<key>type</key>
<string>Window Settings</string>
<key>useOptionAsMetaKey</key>
<true/>
<key>whiteColour</key>
<data>
BAtzdHJlYW10eXBlZIHoA4QBQISEhAdOU0NvbG9yAISECE5TT2JqZWN0AIWEAWMBhARm
ZmZmgzqGaj+D2tdjP4NYPUw/AYY=
</data>
<key>yellowColour</key>
<data>
BAtzdHJlYW10eXBlZIHoA4QBQISEhAdOU0NvbG9yAISECE5TT2JqZWN0AIWEAWMBhARm
ZmZmg0DAJT+DB17vPoM4Y8A8AYY=
</data>
</dict>
</plist>
#! /usr/bin/env fish
# Wrapper that invokes the AWS CLI with cached credentials provided by imaws.
# Helps Lens, et al function better with imaws & role assumption.
# TODO: deal with assuming special roles (other than the profile default)
# - how? where does AWS_PROFILE even come from when this script gets invoked?
if test -n "$AWS_ACCESS_KEY_ID"; and test -n "$AWS_SECRET_ACCESS_KEY"
# Nothing to do; we already (appear to) have valid creds
aws $argv
exit 0
end
set -l min_ttl 60
set -l profile_name $AWS_PROFILE
set mfa_serial (grep -A5 "\[profile $profile_name\]" ~/.aws/config | grep mfa_serial | awk 'BEGIN { FS = " ?= ?" } ; { print $2 }')
set role_arn (grep -A5 "\[profile $profile_name\]" ~/.aws/config | grep role_arn | awk 'BEGIN { FS = " ?= ?" } ; { print $2 }')
set source_profile (grep -A5 "\[profile $profile_name\]" ~/.aws/config | grep source_profile | awk 'BEGIN { FS = " ?= ?" } ; { print $2 }')
if test -z "$role_arn"
echo "imaws-wrapper: No profile '$profile_name' in ~/.aws/config"
exit 1
end
set -l role_account_id (echo $role_arn | cut -d: -f5)
set -l cache_key (echo $role_arn | cut -d: -f5)-(echo $role_arn | cut -d/ -f2)
set -l json_file $HOME/.aws/cli/cache/imaws-$cache_key.json
if test -f "$json_file"
set -gx AWS_SESSION_EXPIRY (jq -r '.Credentials.Expiration | strptime("%Y-%m-%dT%H:%M:%S+00:00") | mktime' $json_file)
if test (math $AWS_SESSION_EXPIRY - (jq -n 'now|floor')) -gt $min_ttl
set -gx AWS_ACCOUNT_ID $role_account_id
set -gx AWS_PROFILE $profile_name
set -gx AWS_ACCESS_KEY_ID (jq -r .Credentials.AccessKeyId $json_file)
set -gx AWS_SECRET_ACCESS_KEY (jq -r .Credentials.SecretAccessKey $json_file)
set -gx AWS_SESSION_TOKEN (jq -r .Credentials.SessionToken $json_file)
aws $argv
exit 0
end
end
echo "imaws-wrapper: Credentials expired; please run imaws to refresh them"
exit 1
# Run a project-local Ruby/JavaScript executable in the PWD.
function x
if test -f Gemfile; or test (count *.gemspec) -gt 0
bundle exec $argv
else if test -f package.json
set -l pmgr (cat package.json | jq -r .packageManager)
switch $pmgr
case 'npm*'
npx $argv
case 'yarn*'
yarn exec $argv
case '*'
if test -f package-lock.json
npx $argv
else if test -f yarn.lock
yarn $argv
else
echo "i: Dunno how to run; please add packageManager to package.json"
return 1
end
end
end
end
# CURRENTLY: watch dir for changes and then invoke a command (in a loop)
function watch
while true
eval $argv[2..-1]
set -l output (fswatch -L -r -t -1 $argv[1])
if test -z "$output"
break # user hit Ctrl+C
else
clear # filesystem changed
end
end
end
# FORMERLY: watch a container's logs across restarts
# function watch
# set -l subject $argv[1]
# if test -f docker-compose.yml
# while true
# docker-compose logs -f $subject
# if test $status -ne 0
# break
# end
# echo "Recommence watching in 10 seconds..."
# sleep 10
# end
# else if test -d $subject
# echo "TODO: watching dirs is not implemented"
# else
# echo "watch: $subject is neither a directory nor a docker-compose service"
# end
# end
# unset all environment variables matching a pattern
function unset
set -l all (env | grep -E $argv[1] | cut -d= -f1)
echo "unset: $all"
for e in $all
set -e $e
end
end
function track
set -l branch (git symbolic-ref HEAD 2>/dev/null | sed -e 's:refs/heads/::')
git branch --set-upstream-to $argv[1]/$branch
end
# Run a script/task of a Ruby or Javascript project located in PWD.
function r
if test -f Makefile; and grep -q "$argv[1]:" Makefile
make $argv
else if test -f Rakefile
bundle exec rake $argv
else if test -f package.json
set -l pmgr (cat package.json | jq -r .packageManager)
switch $pmgr
case 'yarn*'
yarn $argv
case '*'
npm run $argv
end
else
echo "r: Nothing seems to be runnable in this folder"
end
end
# Push the working branch to its remote tracking branch at origin. If
# there is no remote tracking branch, then push to an upstream branch of the
# same name and set upstream for future pushes.
function push
set -l branch (git symbolic-ref HEAD 2>/dev/null | sed -e 's:refs/heads/::')
set -l tracking_branch (git rev-parse --abbrev-ref --symbolic-full-name '@{upstream}' 2>/dev/null)
or set -e tracking_branch
if test -n "$tracking_branch"
git push
else
git push --set-upstream origin $branch
end
end
# Pull from remote. Performs a `git fetch` and fast-forwards the local branch
# named in $argv[1] (or the working branch, if no argument is passed).
#
# Usage:
# `pull` to fast-forward working branch
# `pull branchname` to fast-forward chosen branch
function pull
set -l working_branch (git symbolic-ref HEAD 2>/dev/null | sed -e 's:refs/heads/::')
test -n "$argv[1]"; and set -l branch $argv[1]; or set -l branch $working_branch
git pull -p --ff-only origin $branch
end
# Pull All the Things! Performs a `git fetch`, fast-forwards the working branch
# if applicable, and pulls the Docker image of the corresponding tag name,
# if any.
#
# Does not give any output from `git pull`; this would be nice to have...
#
# Usage:
# `pull!` to fast-forward working branch and pull corresponding image
# `pull! branchname` to fast-forward chosen branch and pull corresponding image
function pull!
# Git repository parameters
set -l working_branch (git symbolic-ref HEAD 2>/dev/null | sed -e 's:refs/heads/::')
test -n "$argv[1]"; and set -l branch $argv[1]; or set -l branch $working_branch
# Docker image parameters (derived from Git parameters)
set -l org (basename (dirname $PWD))
set -l repository (basename $PWD)
set -l tag $branch
# special case for master -> latest naming convention
if test $tag = master
set tag latest
end
set -l image "$org/$repository:$tag"
echo "Pulling branch: origin/$branch"
git pull --ff-only origin $branch &
if test -f Dockerfile
echo "Pulling image: $image"
docker pull $image
else
echo "No Dockerfile; skip image pull"
end
jobs | grep -q 'git pull'; and fg %git
end
# Delete all local branches that are fully merged into master.
function prune
argparse --name=prune 'r/remote' -- $argv
or return
if test -n "$_flag_r"
echo "Prune remote branches (WARNING: only understands true merge):"
git remote prune origin
git branch -r --merged=origin/master | grep -vE 'master|\*' | xargs -L 1 echo
read -P "Remove ALL of the above branches (please respond 'yes')? " confirmation
if test "$confirmation" = "yes"
git branch -r --merged=origin/master | grep -vE 'master|\*' | sed -e 's/^ *origin\//:/' | xargs git push origin
end
else
git remote prune origin
echo "Pruning local repository"
for branchname in (git branch -l --format='%(refname:short)')
if ! string match -r '^\\*' $branchname
if test -z (git branch -lr origin/$branchname)
echo -n ' * '
git branch -D $branchname
end
end
end
end
end
# Open a browser to GitHub in order to compare this branch and/or open a
# pull request to another branch.
function pr
set -l remote (git remote -v | grep push | head -1 | sed 's|^.*github.com[:/]\(.*\)\.git.*$|\1|')
set -l source (git symbolic-ref HEAD 2>/dev/null | sed -e 's:refs/heads/::')
set -l dest $argv[1]
if test -n "$dest"
if [ $dest = master ]; and git show-ref -q --heads main
echo "Using main (not $dest) as default branch -- you insensitive prick!"
set dest main
end
open "https://github.com/$remote/pull/new/$dest...$source"
else
open "https://github.com/$remote/compare/$source"
end
end
# Process a PDF with OCR to add a searchable text layer
function ocr
docker run -it --rm -v (pwd):/~ petpaulsen/ocr $argv
end
# AWS assume-role with fish sauce and an IM garnish.
function impush
argparse --name=impush 'h/help' -- $argv 2> /dev/null
or set _flag_h 1
if test -n "$_flag_h"
echo "Usage: impush"
echo "TODO.."
return 1
end
pushd ~/Code/appfolio/im
cd backend/api/deploy
set release_name (git symbolic-ref --short HEAD | sed 's/\([A-Z]\)/-\1/g;s/^-//' | tr '[:upper:]' '[:lower:]')
bin/coreapi release delete $release_name
bin/coreapi release create $release_name --sha=(HEAD)
cd ../../../deploy
set account_name $release_name
bin/im account create $account_name --rel=$release_name
popd
end
function imchamber__pwd --on-variable=PWD
if test -f .chamberrc
imchamber
end
end
function imchamber
argparse --name=imchamber 'f/force' 'h/help' -- $argv 2> /dev/null
or set _flag_h 1
set -l argcount (count $argv)
set -l fingerprint ""
set -l services ""
if test $argcount -eq 0
set -l gci_account_id ''
set -l gci_arn (aws sts get-caller-identity --output=text --query=Arn 2> /dev/null)
if string match -q '*:assumed-role/*' $gci_arn
set gci_account_id (echo $gci_arn | cut -d: -f5)
else
echo "imchamber: skipping (no AWS credentials available); use --force to override"
return 0
end
set -l rcfile .chamberrc
if test -f .chamberrc.$gci_account_id
set rcfile ".chamberrc.$gci_account_id"
end
if test -f $rcfile
set fingerprint "$gci_account_id"-(md5 -q $rcfile)
set services (cat $rcfile)
end
else if test $argcount -gt 0
for service in $argv
set -a services "env $service"
end
end
echo "5"
if test -n "$_flag_h"; or test -z "$services"
echo "Usage: imchamber <service> [service2 ...]"
echo " - or, write .chamberrc to PWD containing `chamber` commands, one per line"
echo ""
echo "Exports secrets from the designated chamber service(s) to your shell environment."
echo ""
echo "Example .chamberrc file:"
echo " env service1"
echo " env service2"
echo ""
echo "Flags:"
echo " force - re-run chamberrc even if already run"
return 1
end
if test -n "$fingerprint"; and test "$fingerprint" = "$__imchamber_last_fingerprint"; and test -z "$_flag_f"
echo "imchamber: skipping (already ran successfully); use --force to override"
return 0
end
set -l num (count $services)
echo "imchamber: automating $num commands"
for cmd in $services
if not string match -qr '^\s*#|^$' $cmd # ignore comments and empty lines
echo "+ $cmd"
if string match -qr '^env' $cmd
set -l cmd_suffix (string sub -s5 $cmd)
set -l secrets_json (chamber export --format=json $cmd_suffix)
if test $status -ne 0
echo "imchamber: error exporting secrets from $cmd_suffix"
return 1
end
set -l secrets_names (echo $secrets_json | jq -r 'keys | .[]')
for name in $secrets_names
set -gx (echo $name | tr a-z A-Z) (echo $secrets_json | jq -r .$name)
end
else
set -l entire_cmd "chamber $cmd"
eval $entire_cmd
end
end
end
if test -n "$fingerprint"
set -g __imchamber_last_fingerprint $fingerprint
end
end
# AWS assume-role with fish sauce and an IM garnish.
function imaws
argparse --name=imaws 'h/help' 'c/cached' 't/ttl' 'u/unset' -- $argv 2> /dev/null
or set _flag_h 1
set -l profile_name $argv[1]
set -l role_name $argv[2]
if test -n "$_flag_h"
echo "Usage: imaws [--cached] [--ttl=<ttl>] <arn|profile>"
echo " Uses the AWS CLI to assume-role (w/ MFA if required) into an AWS profile"
echo " as named in your from ~/.aws/config file, or as specified by an IAM role ARN."
echo "Flags:"
echo " -c / --cached - do not obtain fresh credentials; exit silently if none cached"
echo " -t / --ttl - min acceptable TTL for cached credentials (default 3600 sec)"
echo ""
echo "To unset all environment variables and restore AWS CLI to its default behavior,"
echo "run imaws without an ARN or profile name."
return 1
end
set -ge AWS_ACCOUNT_ID
set -ge AWS_PROFILE
set -ge AWS_ACCESS_KEY_ID
set -ge AWS_SECRET_ACCESS_KEY
set -ge AWS_SESSION_EXPIRY
set -ge AWS_SESSION_TOKEN
set -ge IM_AWS_ACCESS_KEY
set -ge IM_AWS_SESSION_TOKEN
set -ge IM_AWS_SECRET_ACCESS_KEY
if test -z "$argv[1]"; or test -n "$_flag_u"
echo "imaws: unsetting all environment variables"
echo "(For usage information, run imaws --help)"
return 0
end
if test -n "$_flag_t"
set min_ttl $_flag_t
else
set min_ttl 3600
end
set -l role_arn ''
set -l mfa_serial ''
set -l profile_name ''
if string match -qr '^arn:' $argv[1]
set role_arn $argv[1]
if test -n "$AWS_MFA_SERIAL"
set mfa_serial $AWS_MFA_SERIAL
end
else
set profile_name $argv[1]
set mfa_serial (grep -A5 "\[profile $profile_name\]" ~/.aws/config | grep mfa_serial | awk 'BEGIN { FS = " ?= ?" } ; { print $2 }')
set role_arn (grep -A5 "\[profile $profile_name\]" ~/.aws/config | grep role_arn | awk 'BEGIN { FS = " ?= ?" } ; { print $2 }')
set source_profile (grep -A5 "\[profile $profile_name\]" ~/.aws/config | grep source_profile | awk 'BEGIN { FS = " ?= ?" } ; { print $2 }')
if test -z "$role_arn"
echo "imaws: No profile '$profile_name' in ~/.aws/config"
return 1
end
if test -n "$role_name"
set role_arn (echo $role_arn | sed "s/:role\/.*/:role\/$role_name/")
echo "imaws: Specifically assuming the $role_name role ($role_arn)"
end
end
set -l role_account_id (echo $role_arn | cut -d: -f5)
set -l cache_key (echo $role_arn | cut -d: -f5)-(echo $role_arn | cut -d/ -f2)
set -l json_file $HOME/.aws/cli/cache/imaws-$cache_key.json
set -l login_account_alias "unknown"
if test -f "$json_file"
set -gx AWS_SESSION_EXPIRY (jq -r '.Credentials.Expiration | strptime("%Y-%m-%dT%H:%M:%S+00:00") | mktime' $json_file)
if test (math $AWS_SESSION_EXPIRY - (jq -n 'now|floor')) -gt $min_ttl
# NB: Sets creds globally (and weirdly, not locally) for future shell commands
set -gx AWS_ACCOUNT_ID $role_account_id
set -gx AWS_PROFILE $profile_name
set -gx AWS_ACCESS_KEY_ID (jq -r .Credentials.AccessKeyId $json_file)
set -gx AWS_SECRET_ACCESS_KEY (jq -r .Credentials.SecretAccessKey $json_file)
set -gx AWS_SESSION_TOKEN (jq -r .Credentials.SessionToken $json_file)
# Deal with shitty old E2E suites that need CircleCI-style env vars (yech!)
set -gx IM_AWS_ACCESS_KEY $AWS_ACCESS_KEY_ID
set -gx IM_AWS_SECRET_ACCESS_KEY $AWS_SECRET_ACCESS_KEY
set -gx IM_AWS_SESSION_TOKEN $AWS_SESSION_TOKEN
echo "imaws: Resumed CLI session for $role_arn"
if test -f .chamberrc
# Set creds locally so instaneous imchamber invocation can use them.
# The `-gx` above can't be seen within the subroutine, weirdly enough. Maybe a fish bug?
set -lx AWS_ACCOUNT_ID $role_account_id
set -lx AWS_PROFILE $profile_name
set -lx AWS_ACCESS_KEY_ID (jq -r .Credentials.AccessKeyId $json_file)
set -lx AWS_SECRET_ACCESS_KEY (jq -r .Credentials.SecretAccessKey $json_file)
set -lx AWS_SESSION_TOKEN (jq -r .Credentials.SessionToken $json_file)
imchamber
end
return 0
end
end
if test -n "$_flag_c"
return 0
end
echo "imaws: Initializing CLI session for $role_arn"
set source_profile (grep -A5 "\[profile $profile_name\]" ~/.aws/config | grep source_profile | awk 'BEGIN { FS = " ?= ?" } ; { print $2 }')
if test -n "$source_profile"
set profile_stuff --profile=$source_profile
set -x AWS_ACCESS_KEY_ID (grep -A3 "\[$source_profile\]" ~/.aws/credentials | grep aws_access_key_id | awk 'BEGIN { FS = " ?= ?" } ; { print $2 }')
set -x AWS_PROFILE $source_profile
set -x AWS_SECRET_ACCESS_KEY (grep -A3 "\[$source_profile\]" ~/.aws/credentials | grep aws_secret_access_key | awk 'BEGIN { FS = " ?= ?" } ; { print $2 }')
set login_account_alias (aws iam list-account-aliases | jq -r '.AccountAliases[0]')
end
if test -z "$AWS_ACCESS_KEY_ID" -o -z "$AWS_SECRET_ACCESS_KEY" -o -z "$login_account_alias"
echo "imaws: Failed to obtain credentials for source profile $source_profile; cannot perform STS operations"
return 1
end
set duration_seconds (grep -A5 "\[profile $profile_name\]" ~/.aws/config | grep duration_seconds | awk 'BEGIN { FS = " ?= ?" } ; { print $2 }')
if test -z "$duration_seconds"
set duration_seconds 43200
end
set -l mfa_stuff ""
if test -n "$mfa_serial"
set -l aws_email (echo $mfa_serial | cut -d/ -f2)
set -l mfa_code 'unknown'
if which -s op; and op item list | grep -q "AWS ($aws_email)"
echo "+ op item get \"AWS ($aws_email)\""
set mfa_code (op item get "AWS ($aws_email)" | grep 'one-time password:' | cut -b25-)
else if which -s ykman
echo "+ ykman oath accounts code --single AWS:$login_account_alias"
set mfa_code (ykman oath accounts code --single AWS:$login_account_alias)
end
if [ "$mfa_code" = "unknown" ]
echo "imaws: Failed to obtain MFA code; sorry"
return 2
end
set mfa_stuff --role-session-name=$aws_email --serial-number=$mfa_serial --token-code=$mfa_code
else
set mfa_stuff --role-session-name=(whoami)@(hostname)
end
# TODO: look into this alternate version
# aws sts get-session-token $mfa_stuff
echo "+ aws sts assume-role $profile_stuff --role-arn=$role_arn $mfa_stuff --output=json --duration-seconds=$duration_seconds"
set -l session_json (aws sts assume-role --role-arn=$role_arn $mfa_stuff --output=json --duration-seconds=$duration_seconds)
set -l sts_status $status
if test "$sts_status" -ne 0
echo "imaws: Failed to obtain credentials ($sts_status); please try again"
return 3
else
mkdir -p (dirname $json_file)
echo $session_json > $json_file
imaws $argv # recurse to pick up the cached creds
return 0
end
end
# Install Ruby/Javascript project dependencies in PWD.
function i
if test -f Gemfile
bundle check || bundle install
end
if test -f package.json
set -l pmgr (cat package.json | jq -r .packageManager)
switch $pmgr
case 'npm*'
npm install
case 'yarn*'
yarn install
case '*'
if test -f package-lock.json
npm install
else if test -f yarn.lock
yarn install
else
echo "i: Dunno how to install; please add packageManager to package.json"
return 1
end
end
end
end
# Supported syntax (& search priority):
# g foobar --> chdir to foobar relative to pwd, if exists
# g xyz --> chdir to some project names x*_y*_z* or x*-z*-y*
function g
# Search well-known GitHub owners
set -l bases $HOME/Code/AppFolio-IM $HOME/Code/xeger $HOME/Code/onthespotqa $HOME/Code/appfolio
# If we're inside a Git (mono)repo, search top-level subdirs first
set -l toplevel (git rev-parse --show-toplevel 2> /dev/null)
if test -n "$toplevel"
set subdirs $toplevel/*
set subdirs $subdirs[-1..1]
for entry in $subdirs
if test -d $entry && not git check-ignore -q $entry
set -p bases $entry
end
end
end
set -l initials (echo "^$argv[1]" | sed -e 's/[A-Za-z]/&[^_-]*[_-]/g' | sed -e 's/\[_-\]$//')
# Check whether this is a shortcut for some source-code project.
for base in $bases
set -l dirents $base/*
for dir in $dirents
if test -d $dir
set -l bn (basename $dir)
if test $bn = $argv[1] # exact match
cd $dir
return 0
else if echo $bn | grep -qE $initials # initials match
cd $dir
return 0
end
end
end
end
# Check whether this is the literal name of some directory
if test -d $argv[1]
cd $argv[1]
return 0
end
# No matches! Display error message.
echo "Could not find a directory matching '$argv[1]' under any of:"
for base in $bases
echo " $base"
end
return 1
end
function exportify
rm -f index.ts
for f in *.ts *.tsx
if string match -q '*.config.ts' $f
continue
end
set -l base (path change-extension '' $f)
if grep -q 'export default' $f
echo "export { default as $base } from './$base';" >> index.ts
end
echo "export * from './$base';" >> index.ts
end
end
function eks
argparse --name=eks 'n/namespace' 'r/region' -- $argv
or return
set cluster "$argv[1]"
if test -n "$_flag_n"
set namespace $_flag_n
end
set -q region $_flag_r
or set region "us-east-2"
if test -z $cluster
echo "usage: eks <cluster>"
echo " available clusters (aws eks list-clusters --region=$region):"
aws eks list-clusters --region=$region | jq -r '.clusters | map(" - " + .) | .[]'
return 1
end
echo "+ aws eks --region $region update-kubeconfig --name $cluster"
aws eks --region $region update-kubeconfig --name $cluster
sed "s!command: aws!command: $HOME/.config/fish/scripts/imaws-wrapper!g" ~/.kube/config > ~/.kube/config.tmp
mv ~/.kube/config.tmp ~/.kube/config
chmod go-rwx ~/.kube/config
echo "Updated ~/.kube/config to use imaws-wrapper"
if test -n "$namespace"
echo "+ kubectl config set-context (kubectl config current-context) --namespace=$namespace"
kubectl config set-context (kubectl config current-context) --namespace=$namespace
end
end
function dsh
set -l search $argv[1]
set -l candidates (docker ps --format '{{.Names}}' | grep $search)
if test (count $candidates) -eq 1
docker exec -t -i $candidates[1] /bin/sh -c '[ -f /bin/bash ] && exec /bin/bash -l || exec /bin/sh -l'
else if test (count $candidates) -eq 0
docker exec -t -i $search /bin/sh -c '[ -f /bin/bash ] && exec /bin/bash -l || exec /bin/sh -l'
else
echo "Too many containers match '$search'; please be more specific to disambiguate between:"
for cand in $candidates
echo " $cand"
end
end
end
function dock
switch $argv[1]
case localhost
set -ex DOCKER_HOST
case development
set -gx DOCKER_HOST "tcp://10.105.8.128:3376"
case '*'
set -gx DOCKER_HOST "tcp://$argv[1]:2376"
end
echo "DOCKER_HOST is $DOCKER_HOST"
docker version | grep -A10 Server
end
function dl
set -l cnt (count $argv)
set -l search $argv[$cnt]
set --erase argv[$cnt]
set -l candidates (docker ps --format '{{.Names}}' | grep $search)
if test (count $candidates) -eq 1
docker logs $argv $candidates[1]
else if test (count $candidates) -eq 0
docker logs $argv $search
else
echo "Too many containers match '$search'; please be more specific to disambiguate between:"
for cand in $candidates
echo " $cand"
end
end
end
function dgc
set -l ids (docker ps --filter="status=exited" --format="{{.ID}}")
echo "Remove exited containers:"
for id in $ids
docker rm -v $id
end
echo "Prune unused volumes:"
docker volume prune -f
end
function cover
ginkgo -r -randomizeAllSpecs -randomizeSuites -cover
rm -f merged.coverprofile
gocovmerge (find . -iname '*.coverprofile') > merged.coverprofile
go tool cover -html=merged.coverprofile
end
# Run rubocop only on specified paths or staged changes; fallback to run on everything.
function cop
set -l paths
if test -n "$argv"
set paths $argv
else
set -l prefix (git rev-parse --show-prefix)
set paths (git diff --cached --name-status --relative=$prefix | grep '^[AM].*[.]rb$' | cut -f 2)
end
echo "+ bundle exec rubocop -A $paths"
bundle exec rubocop -A $paths
end
# Open a browser displaying the continuous integration status of the active branch.
function ci
set -l root (git rev-parse --show-toplevel)
set -l remote (git remote -v | grep -E '^origin.*push' | sed 's|^.*github.com[:/]\(.*\)\.git.*$|\1|')
set -l org (echo $remote | cut -d/ -f1)
set -l repo (echo $remote | cut -d/ -f2)
set -l branch (git symbolic-ref HEAD 2>/dev/null | sed -e 's:refs/heads/::')
if test -d $root/.circleci
open "https://circleci.com/gh/$org/workflows/$repo/tree/$branch"
else
open "https://github.com/$org/$repo/tree/$branch"
end
end
# Force-push the working branch to its remote tracking branch at origin.
function bump
set pushmode (git config push.default)
if test $pushmode = simple
git push --force-with-lease
return 0
else
echo "bump: Cannot force-push; please `git config --global push.default simple`"
return 1
end
end
#AWSume alias to source the AWSume script
alias awsume="source (which awsume.fish)"
function HEAD
git log -1 --format=%H $argv
end
######## basic Unix stuff: editor, terminal, etc
set -x EDITOR vi
# clean start (avoid Visual Studio Code bugs w/ path duplication)
if test -f /etc/paths
set -x PATH (cat /etc/paths | tr '\n' ':' | sed -Ee '$ s/:+$//')
end
alias psx 'pstree -U -g 2 %self'
alias lsx 'tree -A -C -L 2'
######## ssh
if test -n "$SSH_AUTH_SOCK"
set -l private_keys (grep -El 'BEGIN [A-Z]* ?PRIVATE KEY' ~/.ssh/*)
if test $status = 0; and test -n "$private_keys"
ssh-add $private_keys 2> /dev/null
if test $status != 0
echo "Could not add private SSH keys to agent"
echo "Please run this command by hand:"
echo "ssh-add $private_keys"
end
end
end
if test -d ~/java/apache-maven-3.9.2/bin
set -x PATH $PATH $HOME/java/apache-maven-3.9.2/bin
end
######## google go
if test -d ~/go/bin
set -x GOPATH ~/go
set -x PATH $PATH ~/go/bin
launchctl setenv PATH (string join ':' $PATH) GOPATH $GOPATH
end
######## python (on Mac OS X, i.e. `/usr/bin/pip3 install xyz`)
set -l pybin $HOME/Library/Python/3.*/bin
if test -n "$pybin"
set -x PATH $PATH $pybin
end
set -e pybin
######## ruby
# only works with Ruby 2.7 (not OS X builtin Ruby, blech)
set -x RUBYOPT "-W:no-deprecated"
#set -x RUBYOPT "-W0"
# seems to be actively harmful under Mojave w/ ruby 2.3.x
# does not harm Ruby 2.5
#if test -d /usr/local/opt/openssl
# set -x RUBY_CFLAGS -I/usr/local/opt/openssl/include -L/usr/local/opt/openssl/lib
#end
######## rust
# shrink rust installs with `asdf install rust` (and similar commands)
set -x RUST_WITHOUT "rust-docs"
if test -d ~/.cargo/bin
set -x PATH $PATH ~/.cargo/bin
end
######## docker
alias darch 'docker inspect -f "{{.Architecture}}"'
alias dc 'docker-compose'
alias dcb 'docker-compose build'
alias dcr 'docker-compose run'
alias di 'docker inspect'
alias dim 'docker images'
alias dn 'docker network'
alias dps 'docker ps'
alias drm 'docker rm -f'
alias drmi 'docker rmi'
alias dv 'docker volume'
alias dst 'docker stack'
alias ds 'docker service'
alias dsi 'docker service inspect --pretty'
alias dtty 'nc -U ~/Library/Containers/com.docker.docker/Data/debug-shell.sock'
######## Kubernetes
alias kc 'kubectl'
######## google cloud SDK
if [ -f '/Users/tony/google-cloud-sdk/path.fish.inc' ]
if type source > /dev/null
source '/Users/tony/google-cloud-sdk/path.fish.inc'
else
. '/Users/tony/google-cloud-sdk/path.fish.inc'
end
end
######## git
if [ ! -f '$HOME/.gitignore' ]
touch $HOME/.gitignore
echo ".DS_Store" >> $HOME/.gitignore
end
alias fetch='git fetch'
alias gb='git branch'
alias gco='git checkout'
alias gcp='git cherry-pick'
alias gd='git diff'
alias gdc='git diff --cached'
alias gl='git log --topo-order --pretty=format:"%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset" --abbrev-commit'
alias glp='git log --topo-order --pretty=format:"%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%G?:%an>%Creset" --abbrev-commit'
alias gss='git status'
alias gsw='git show'
alias sclear='git stash clear'
alias slist='git stash list'
alias spush='git stash save'
alias spop='git stash pop'
# git prompt lifted from http://goo.gl/Wq5lb7
set normal (set_color normal)
set magenta (set_color magenta)
set yellow (set_color yellow)
set green (set_color green)
set red (set_color red)
set gray (set_color -o black)
# Fish git prompt
set __fish_git_prompt_showdirtystate 'yes'
set __fish_git_prompt_showstashstate 'yes'
set __fish_git_prompt_showuntrackedfiles 'yes'
set __fish_git_prompt_showupstream 'yes'
set __fish_git_prompt_color_branch yellow
set __fish_git_prompt_color_upstream_ahead green
set __fish_git_prompt_color_upstream_behind red
# Status Chars
set __fish_git_prompt_char_dirtystate '⚡ '
set __fish_git_prompt_char_stagedstate '📌 '
set __fish_git_prompt_char_untrackedfiles '💩 '
set __fish_git_prompt_char_stashstate '↩'
set __fish_git_prompt_char_upstream_ahead '⋙'
set __fish_git_prompt_char_upstream_behind '⋘'
function fish_prompt
set last_status $status
set_color $fish_color_cwd
printf '%s' (prompt_pwd)
set_color normal
set danger ''
set here (basename $PWD)
if git add -n ../$here 2>&1 | grep -q 'are ignored'
set danger ' ⚠️ ️'
end
printf '%s%s ' $danger (__fish_git_prompt)
set_color normal
end
######## terraform
alias tf='terraform'
######## local config that should not be committed to git
if [ -f ~/.config/fish/local.fish ]
source ~/.config/fish/local.fish
end
######## tool version managers (even for non-interactive shells!)
if test -d ~/.asdf
set -x PATH ~/.asdf/shims $PATH
if status --is-interactive
if test -f /usr/local/share/fish/vendor_completions.d/asdf.fish
source /usr/local/share/fish/vendor_completions.d/asdf.fish
end
end
end
######## VS Code
string match -q "$TERM_PROGRAM" "vscode"
and . (code --locate-shell-integration-path fish)
#Auto-Complete function for AWSume
complete --command awsume --arguments '(awsume-autocomplete)'
This is my preferred fish configuration.
Please refer to [dotfiles](https://github.com/xeger/dotfiles) for installation instructions.
.git
.DS_Store
fish_history
fish_read_history
fish_variables
fishd*
local.fish
.pijul
.DS_Store
fish_history
fish_read_history
fish_variables
fishd*
local.fish