Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
My BitBar enabled plugins - heroku, homebrew, github, and googlecal
#!/bin/bash
# <bitbar.title>Homebrew Updates</bitbar.title>
# <bitbar.author>killercup</bitbar.author>
# <bitbar.author.github>killercup</bitbar.author.github>
# <bitbar.desc>List available updates from Homebrew (OS X)</bitbar.desc>
exit_with_error() {
echo "err | color=red";
exit 1;
}
/usr/local/bin/brew update > /dev/null || exit_with_error;
PINNED=$(/usr/local/bin/brew list --pinned);
OUTDATED=$(/usr/local/bin/brew outdated --quiet);
UPDATES=$(comm -13 <(for X in "${PINNED[@]}"; do echo "${X}"; done) <(for X in "${OUTDATED[@]}"; do echo "${X}"; done))
UPDATE_COUNT=$(echo "$UPDATES" | grep -c '[^[:space:]]');
echo "🍺$UPDATE_COUNT | dropdown=false"
echo "---";
if [ -n "$UPDATES" ]; then
echo "Upgrade all | bash=/usr/local/bin/brew param1=upgrade terminal=false refresh=true"
echo "$UPDATES" | awk '{print $0 " | terminal=false refresh=true bash=/usr/local/bin/brew param1=upgrade param2=" $1}'
fi
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# <bitbar.title>GitHub Notifications</bitbar.title>
# <bitbar.version>v3.0.2</bitbar.version>
# <bitbar.author>Matt Sephton, Keith Cirkel, John Flesch</bitbar.author>
# <bitbar.author.github>flesch</bitbar.author.github>
# <bitbar.desc>GitHub (and GitHub:Enterprise) notifications in your menu bar!</bitbar.desc>
# <bitbar.image>https://i.imgur.com/hW7dw9E.png</bitbar.image>
# <bitbar.dependencies>python</bitbar.dependencies>
import json
import urllib2
import os
import sys
import re
from itertools import groupby
# GitHub.com
github_api_key = os.getenv( 'GITHUB_TOKEN', 'Enter your GitHub Personal Access Token here...' )
# GitHub:Enterprise (optional)
enterprise_api_key = os.getenv( 'GITHUB_ENTERPRISE_TOKEN', 'Enter your GitHub:Enterprise Personal Access Token here...' )
enterprise_api_url = os.getenv( 'GITHUB_ENTERPRISE_API', 'https://github.example.com/api/v3' )
active = '#4078C0'
inactive = '#7d7d7d'
# Utility Functions
def plural( word, n ):
return str(n) + ' ' + (word + 's' if n > 1 else word)
def get_dict_subset( thedict, *keys ):
return dict([ (key, thedict[key]) for key in keys if key in thedict ])
def print_bitbar_line( title, **kwargs ):
print title + ' | ' + ( ' '.join( [ '{}={}'.format( k, v ) for k, v in kwargs.items() ] ) )
def make_github_request( url, method='GET', data=None, enterprise = False ):
try:
api_key = enterprise_api_key if enterprise else github_api_key
headers = {
'Authorization': 'token ' + api_key,
'Accept': 'application/json',
}
if data is not None:
data = json.dumps(data)
headers['Content-Type'] = 'application/json'
headers['Contnet-Length'] = len(data)
request = urllib2.Request( url, headers=headers )
request.get_method = lambda: method
response = urllib2.urlopen( request, data )
return json.load( response ) if response.headers.get('content-length', 0) > 0 else {}
except Exception:
return None
def get_notifications( enterprise ):
url = '%s/notifications' % (enterprise_api_url if enterprise else 'https://api.github.com')
return make_github_request( url, enterprise=enterprise ) or []
def print_notifications( notifications, enterprise=False ):
notifications = sorted( notifications, key=lambda notification: notification['repository']['full_name'] )
for repo, repo_notifications in groupby( notifications, key=lambda notification: notification['repository']['full_name'] ):
if repo:
repo_notifications = list( repo_notifications )
print_bitbar_line( title=repo )
print_bitbar_line(
title='{title} - Mark {count} As Read'.format( title=repo, count=len( repo_notifications ) ),
alternate='true',
refresh='true',
bash=__file__,
terminal='false',
param1='readrepo',
param2=repo,
param3='--enterprise' if enterprise else None
)
for notification in repo_notifications:
formatted_notification = format_notification( notification )
print_bitbar_line( refresh='true', **get_dict_subset( formatted_notification, 'title', 'href', 'image', 'templateImage' ) )
print_bitbar_line(
refresh='true',
title='%s - Mark As Read' % formatted_notification['title'],
alternate='true',
bash=__file__,
terminal='false',
param1='readthread',
param2=formatted_notification['thread'],
param3='--enterprise' if enterprise else None,
**get_dict_subset( formatted_notification, 'image', 'templateImage' )
)
def format_notification( notification ):
type = notification['subject']['type']
formatted = {
'thread': notification['url'],
'title': notification['subject']['title'].encode('utf-8'),
'href': notification['subject']['url'],
'image': 'iVBORw0KGgoAAAANSUhEUgAAAA4AAAAQCAYAAAAmlE46AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEwAACxMBAJqcGAAAA',
}
if len(formatted['title']) > 90:
formatted['title'] = formatted['title'][:79] + '…'
formatted['title'] = formatted['title'].replace('|','-')
latest_comment_url = notification.get( 'subject', {} ).get( 'latest_comment_url', None )
typejson = make_github_request( formatted['href'] )
if latest_comment_url:
formatted['href'] = ( make_github_request( latest_comment_url ) or {} ).get( 'html_url', formatted['href'] )
# Try to hack a web-viewable URL if the last check failed
if formatted['href']:
formatted['href'] = re.sub( 'api\.|api/v3/|repos/', '', re.sub( '(pull|commit)s', ur'\1', formatted['href'] ) )
if (type == 'PullRequest'):
if typejson and typejson['merged']:
formatted['image'] += 'SpJREFUKJG9kkFOwmAQhb+ZQiVx5xm4hIlncEF7jLZuWSjSeAJsvQUY4xkMHsCtcU9MXBmwJsy4EWgFEt34VpP55mX+eflhj9KoGO5jAK00LmOwoZiaYIPRbXaXRsVQRC6BvWZJ4uLJRI6DcKlUMsVl/G0CwIw3UR8V4+QKxFd9BbfDqiP6buo1sB5QjgTJ07i8aPTFgvNFa/7i7fYzaL+YpEN3zwGux4mY2QmAm6db783i0rO4bGyrh7OL66a0Bigm6d5gGkYz3brvV8a/SjeF/dPGJLrpmTMDXs/i4vTnQNYrInNm5szqvIVYbiJdCV1Z6ANwXze6em4i3SBcqi+CNVeAIFxq9dkR0+07HfHVz6rzlsLAK5keUCEu/R0hDD7C+SME6A7+Z30BqF2G+GPLjSUAAAAASUVORK5CYII='
elif typejson and typejson['state'] == 'closed':
formatted['image'] += 'Q9JREFUKJG9kjFOw0AQRd9sbAiiQOIMqWJfAInOPULANehTQIjFCbgHFS1eKhR6cDpEbyHRmljyDpWVTWJbSsOvRvvm72i+BjpkI2ZdDIBszNVzTG7HvGcx543JxmifT7KIj4FyUlaYcMjcKI8Id17Pj8JDknMvrD4zoriwRg4OMaKtU44FUhtz6z8aFW7KkC9X82mESbJghpICJDkiyimAwvV2EDG6uZMfThs3TeFYB8miP1XjFb0pdhp31cro/muijbjAUTjDtx1zttnwEnGJo8BR+DxQSAcwWv5i9vd4BZ58Yy2kgTIqq3VuAMoKEx4htCQrijaX5fMAYRoOmbMEJ0y2lhGmZcgbNdDGd9Uf3M1iNlKZZGMAAAAASUVORK5CYII='
else:
formatted['image'] += 'TJJREFUKJG9krFOAlEQRe/MLpqHnd/ATyBWsLWF+hcLPYXibvwCE/gLC2MNVrD7AbbGnpjYboBlro2QXWATabzVy5x338ydPKBC4awTVTEA8Huz9i1FI5gZBINh6+0lnHUiEXkAUGmWMGm/c7Fues4pLU9IPv+aAABm9i2qT6Pm+BECbuoqpnZWW4lmmRLG3ZdV9VyAOEyD+1JdVO4yqX+ua7UPofRHrUlEMgaA4cVYALkEACF6e/N2k4DdJCh1Ky7nENftyVACo9akcjElox3I9yfjsdoaVfFPHbtpcG2GOUy/wjS42r0QTjs3ZpibYV7kPmkxVuuGOKfIl1MAr0WjqMRcrBqec8oCVwDwnNOFnwugezkJ4+ZnFbkPeANanpwsAQr7+2m8Qab1FKcAeYgfqR/3P4pMOYR15QAAAABJRU5ErkJggg=='
if typejson and typejson.get( 'user', {} ).get( 'login', None ):
formatted['title'] += ' (by @{})'.format(typejson['user']['login'])
elif (type == 'RepositoryInvitation'):
formatted['image'] = 'iVBORw0KGgoAAAANSUhEUgAAAA4AAAAKCAYAAACE2W/HAAAAAXNSR0IArs4c6QAAAM1JREFUKBWVkD0OQUEUhcdv/ASJn55SyxLoVBJq8tZjBRQsgkZiAQoqOiQ2oFc935nMvLxEXsRJPufOufe+kTHGmBeEf3Jg3i4t8IwOP6QZzeoi+3PFt1BRkKAq+Q4uEKbdUA+/wxm6LoubshPcoO8b9lp3GOMPGPomPoInqOcV/VUfyKfwhsChegJxfS3O6R5hALpFqFY2A69osUyygT3UQOpAWwVSpt4aShAt6lWXkIUk5WiswL5qiqIODdBz6+ZirM67cwFvulwfaH0AC7M1lHL62U4AAAAASUVORK5CYII=';
formatted['templateImage'] = formatted.pop('image');
formatted['href'] = 'https://github.com/{}/invitations'.format(notification['repository']['full_name'])
elif (type == 'Issue'):
if typejson and typejson['state'] == 'closed':
formatted['image'] += 'YpJREFUKJGdkj9I23EQxT93SZrJQYNQ6Bo65BtQcHRpSeyUuQqNWx2ti7qJRpqhUxGX0lGhlXQ0uJhfU7cOLm3+QKCzoIjoJpp8z0HT/BpJBd90HO/dvTsePBLS36iM8Uw6vANyQNJ7RJU/wG7nmo1XLY7uCStp8uL5BJwgbJtRU8E8jImR98qoGHPZBjsSFhlsCRQjCQovD2iHhx5OEDu/ZF2E5Y4wLn/tXdMy5WO2zkqXHKQxgEy95+y7Y1KMXwogbeaBk0iCwqBn7DteAJym+NmBnSiAF3IK2/32wiIVqoGjYE1GRMlGARSSZtQGbZtq8CNwFBBWDUxgJjqI3I9Mg7XAgRoXmSYlACqOWuAG39ePimNB7+oyxuzhBLEwIUhj3c92sZckLsaSAvg2m14ZPb98eGs8ThFlqBcAx4wJX8T4cGasvm5yFRaUUjwZUd4bLKow/W/kbsWfgTMxvorxmwhtjHEPbxSGEd5many7F/JqiqdemceT88rzu3ZLoWywma1z/NA5/8UNNkSJCdaYQF4AAAAASUVORK5CYII='
else:
formatted['image'] += 'ZxJREFUKJGdkjFoU2EUhb97k9jNRzEFoWvJVHXoZCqIaQaH7JaUbtpi2zc4ORWJYKGTYJLBroFaiGPo0hBwyAOhU51Cd8EOOid53uugL4SnkOK3/dx7OPccfvhPZPqxHZUWc0gIUjFs6c/CJdDBtN580P36lzCM1jZ+mr9HuFKkJfgXABO9i/mmqOTd7VlztXcyEYbR2oabtFx5kx+Oa7VHn+LpS7bOV3K5UfBaTF+6WLW52juR7ai0mDEGovq2WezuJ8t7UdkBGsXu5KqdfvlQhOeeGRc0h4QIV/nhuDarkIVgft+xHxJnQwWpKNJKn/cvasvtkcCxuFTUsKWkiOsgrhcoBb2uIE1W4NKRO8DH6cF0KSnLewYDBTqGb26dr+Sm53tR2ZNmE8LTx3O4V9XpKKZ1FV24MZyf2aoH8YE5garXBWC3X1oX12NXO8zfvPWqttwepZ08iA9wXqDypFE8a09y7PZL64geCXx37IO4XiSZcK/+dso8bRTP2pD65DufH96WOBuKSwWlAGD4QJ2Oqtff3e99mxVnJr8AXSGi02ni0+YAAAAASUVORK5CYII='
elif (type == 'Commit'):
formatted['image'] += 'HhJREFUKJHl0LEKwkAQBNCH3yIaf05S+VUqmh8ykFoUYn8WbnEc8a7XgYVlmNkdhv/EDgNmvHDFtmXq8ETCiFvsD2xqxksI9xnXB3cqxamYceHgVOpWC6JUi/QNQxj7jDsEd6wZ83KmLOId69bXzqekOeas0eiv4g3q4SY7NY1R2gAAAABJRU5ErkJggg=='
formatted['templateImage'] = formatted.pop('image')
elif (type == 'Release'):
formatted['image'] += 'JdJREFUKJGl0DsKwkAUBdDTRgvFHbgmNyLY+QWzKxM/kK2kSKc70MIIQ0ziqBceA/dxinn8mSkKVMGUmH+CBWaNboQjdn2wqt97Pa8kNd5+C0O86YNdSZC34RLjCJxhHZYLXDCIxKuwTHGOwBNcm2WKUw9OcMCybZl6XjHpQOs30cB5gKNQiDPPP0WjV/a4aVwxNsNfUGce7P8k4XgVPSYAAAAASUVORK5CYII='
formatted['templateImage'] = formatted.pop('image')
return formatted
if len(sys.argv) > 1:
command = sys.argv[1]
args = sys.argv[2:]
enterprise=False
if ('--enterprise' in args):
enterprise=True
args.remove( '--enterprise' )
if command == 'readrepo':
url = '%s/repos/%s/notifications' % (enterprise_api_url if enterprise else 'https://api.github.com', args[0])
print 'Marking %s as read' % url
make_github_request( url=url, method='PUT', data={}, enterprise=enterprise )
elif command == 'readthread':
url = args[0]
print 'Marking %s as read' % url
make_github_request( url=url, method='PATCH', data={}, enterprise=enterprise )
else:
is_github_defined = len( github_api_key ) == 40
is_github_enterprise_defined = len( enterprise_api_key ) == 40
github_notifications = get_notifications( enterprise=False ) if is_github_defined else []
enterprise_notifications = get_notifications( enterprise=True ) if is_github_enterprise_defined else []
has_notifications = len( github_notifications ) + len( enterprise_notifications )
color = active if has_notifications else inactive
if (has_notifications):
print_bitbar_line(
title=u'\u25CF'.encode( 'utf-8' ),
color=color
)
print '---'
else:
print ''
exit(0)
print_bitbar_line( title='Refresh', refresh='true' )
if is_github_defined:
if len( github_notifications ):
print_bitbar_line(
title=( u'GitHub \u2014 %s' % plural( 'notification', len( github_notifications ) ) ).encode( 'utf-8' ),
color=active,
href='https://github.com/notifications',
)
print_notifications( github_notifications )
else:
print_bitbar_line(
title=u'GitHub \u2014 No new notifications'.encode( 'utf-8' ),
color=inactive,
href='https://github.com',
)
if is_github_enterprise_defined:
if len( enterprise_notifications ):
if is_github_defined:
print '---'
print_bitbar_line(
title=( u'GitHub:Enterprise \u2014 %s' % plural( 'notification', len( enterprise_notifications ) ) ).encode( 'utf-8' ),
color=active,
href='%s/notifications' % re.sub( '/api/v3', '', enterprise_api_url ),
)
print_notifications( enterprise_notifications, enterprise=True )
else:
print '---'
print_bitbar_line(
title=u'GitHub:Enterprise \u2014 No new notifications',
color=inactive,
)
#!/usr/bin/env /usr/local/bin/node
/* jshint esversion: 6, loopfunc: true */
/*
<bitbar.title>Google Calendar</bitbar.title>
<bitbar.version>v1.2.0</bitbar.version>
<bitbar.author>Kodie Grantham</bitbar.author>
<bitbar.author.github>kodie</bitbar.author.github>
<bitbar.desc>Shows upcoming events from your Google Calendar - Be sure to read the installation instructions here: https://github.com/kodie/bitbar-googlecal</bitbar.desc>
<bitbar.image>https://raw.githubusercontent.com/kodie/bitbar-googlecal/master/screenshot.png</bitbar.image>
<bitbar.dependencies>node, npm</bitbar.dependencies>
<bitbar.dependencies.npm>npm/home-config, npm/googleapis, npm/google-auth-library, npm/hapi, npm/moment, npm/open</bitbar.dependencies.npm>
<bitbar.abouturl>https://github.com/kodie/bitbar-googlecal</bitbar.abouturl>
*/
var ver = '1.2.0';
var defaults = {
clientId: 'clientid',
clientSecret: 'clientsecret',
clientRedirect: 'http://localhost:3000',
calendarId: 'primary',
dateColor: false,
dateFont: false,
dateFormat: 'dddd M/D',
dateSize: 12,
days: 1,
eventColor: false,
eventFont: false,
eventLength: 80,
eventSize: false,
expandEvents: false,
limit: 25,
showAllOfFirstDay: true,
showEmptyDays: false,
serverHost: 'localhost',
serverPort: 3000,
startDate: Date.now(),
textToday: ' (Today)',
textTomorrow: ' (Tomorrow)',
timeFormat: 'h:mma',
tokenFile: '.googlecal.json'
};
if (process.env.BitBar) {
var icon = 'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAACXBIWXMAABYlAAAWJQFJUiTwAABD/WlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4KPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS42LWMxMTEgNzkuMTU4MzI1LCAyMDE1LzA5LzEwLTAxOjEw' +
'OjIwICAgICAgICAiPgogICA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogICAgICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgICAgICAgICB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iCiAgICAgICAgICAgIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIKICAgICAgICAgICAgeG1s' +
'bnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iCiAgICAgICAgICAgIHhtbG5zOnN0RXZ0PSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VFdmVudCMiCiAgICAgICAgICAgIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIgogICAgICAgICAgICB4bWxuczpwaG90b3Nob3A9Imh0dHA6Ly9ucy5hZG9iZS5jb20vcGhv' +
'dG9zaG9wLzEuMC8iCiAgICAgICAgICAgIHhtbG5zOnRpZmY9Imh0dHA6Ly9ucy5hZG9iZS5jb20vdGlmZi8xLjAvIgogICAgICAgICAgICB4bWxuczpleGlmPSJodHRwOi8vbnMuYWRvYmUuY29tL2V4aWYvMS4wLyI+CiAgICAgICAgIDx4bXA6Q3JlYXRlRGF0ZT4yMDE2LTAyLTI3VDA4OjQ1OjQwWjwveG1wOkNyZWF0ZURhdGU+CiAgICAgICAgIDx4bXA6TW9kaWZ5RGF0ZT4yMDE3LTAyLTIxVDE0OjQ4OjQ4LTA2OjAwPC94bXA6' +
'TW9kaWZ5RGF0ZT4KICAgICAgICAgPHhtcDpNZXRhZGF0YURhdGU+MjAxNy0wMi0yMVQxNDo0ODo0OC0wNjowMDwveG1wOk1ldGFkYXRhRGF0ZT4KICAgICAgICAgPHhtcDpDcmVhdG9yVG9vbD5BZG9iZSBQaG90b3Nob3AgQ0MgMjAxNSAoTWFjaW50b3NoKTwveG1wOkNyZWF0b3JUb29sPgogICAgICAgICA8ZGM6Zm9ybWF0PmltYWdlL3BuZzwvZGM6Zm9ybWF0PgogICAgICAgICA8eG1wTU06SGlzdG9yeT4KICAgICAgICAgICAg' +
'PHJkZjpTZXE+CiAgICAgICAgICAgICAgIDxyZGY6bGkgcmRmOnBhcnNlVHlwZT0iUmVzb3VyY2UiPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6YWN0aW9uPmNvbnZlcnRlZDwvc3RFdnQ6YWN0aW9uPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6cGFyYW1ldGVycz5mcm9tIGltYWdlL3BuZyB0byBhcHBsaWNhdGlvbi92bmQuYWRvYmUucGhvdG9zaG9wPC9zdEV2dDpwYXJhbWV0ZXJzPgogICAgICAgICAgICAgICA8L3JkZjps' +
'aT4KICAgICAgICAgICAgICAgPHJkZjpsaSByZGY6cGFyc2VUeXBlPSJSZXNvdXJjZSI+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDphY3Rpb24+c2F2ZWQ8L3N0RXZ0OmFjdGlvbj4KICAgICAgICAgICAgICAgICAgPHN0RXZ0Omluc3RhbmNlSUQ+eG1wLmlpZDozRTNFRTE5RTBCMjA2ODExODIyQUM1MTg3MTkxRkQ2Qzwvc3RFdnQ6aW5zdGFuY2VJRD4KICAgICAgICAgICAgICAgICAgPHN0RXZ0OndoZW4+MjAxNi0wMi0yN1Qx' +
'MzoxNTo1NiswNDowMDwvc3RFdnQ6d2hlbj4KICAgICAgICAgICAgICAgICAgPHN0RXZ0OmNoYW5nZWQ+Lzwvc3RFdnQ6Y2hhbmdlZD4KICAgICAgICAgICAgICAgPC9yZGY6bGk+CiAgICAgICAgICAgICAgIDxyZGY6bGkgcmRmOnBhcnNlVHlwZT0iUmVzb3VyY2UiPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6YWN0aW9uPmNvbnZlcnRlZDwvc3RFdnQ6YWN0aW9uPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6cGFyYW1ldGVy' +
'cz5mcm9tIGltYWdlL3BuZyB0byBhcHBsaWNhdGlvbi92bmQuYWRvYmUucGhvdG9zaG9wPC9zdEV2dDpwYXJhbWV0ZXJzPgogICAgICAgICAgICAgICA8L3JkZjpsaT4KICAgICAgICAgICAgICAgPHJkZjpsaSByZGY6cGFyc2VUeXBlPSJSZXNvdXJjZSI+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDphY3Rpb24+c2F2ZWQ8L3N0RXZ0OmFjdGlvbj4KICAgICAgICAgICAgICAgICAgPHN0RXZ0Omluc3RhbmNlSUQ+eG1wLmlpZDoz' +
'RjNFRTE5RTBCMjA2ODExODIyQUM1MTg3MTkxRkQ2Qzwvc3RFdnQ6aW5zdGFuY2VJRD4KICAgICAgICAgICAgICAgICAgPHN0RXZ0OndoZW4+MjAxNi0wMi0yN1QxMzoxNTo1NiswNDowMDwvc3RFdnQ6d2hlbj4KICAgICAgICAgICAgICAgICAgPHN0RXZ0OmNoYW5nZWQ+Lzwvc3RFdnQ6Y2hhbmdlZD4KICAgICAgICAgICAgICAgPC9yZGY6bGk+CiAgICAgICAgICAgICAgIDxyZGY6bGkgcmRmOnBhcnNlVHlwZT0iUmVzb3VyY2Ui' +
'PgogICAgICAgICAgICAgICAgICA8c3RFdnQ6YWN0aW9uPnNhdmVkPC9zdEV2dDphY3Rpb24+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDppbnN0YW5jZUlEPnhtcC5paWQ6ZDVlNDdmMzItMTk5YS00Mzc5LWEwMDEtMjYzODFlMTEzOWI3PC9zdEV2dDppbnN0YW5jZUlEPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6d2hlbj4yMDE2LTAyLTI3VDEzOjMxOjIxKzA0OjAwPC9zdEV2dDp3aGVuPgogICAgICAgICAgICAgICAgICA8' +
'c3RFdnQ6c29mdHdhcmVBZ2VudD5BZG9iZSBQaG90b3Nob3AgQ0MgMjAxNCAoTWFjaW50b3NoKTwvc3RFdnQ6c29mdHdhcmVBZ2VudD4KICAgICAgICAgICAgICAgICAgPHN0RXZ0OmNoYW5nZWQ+Lzwvc3RFdnQ6Y2hhbmdlZD4KICAgICAgICAgICAgICAgPC9yZGY6bGk+CiAgICAgICAgICAgICAgIDxyZGY6bGkgcmRmOnBhcnNlVHlwZT0iUmVzb3VyY2UiPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6YWN0aW9uPmNvbnZlcnRl' +
'ZDwvc3RFdnQ6YWN0aW9uPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6cGFyYW1ldGVycz5mcm9tIGFwcGxpY2F0aW9uL3ZuZC5hZG9iZS5waG90b3Nob3AgdG8gaW1hZ2UvcG5nPC9zdEV2dDpwYXJhbWV0ZXJzPgogICAgICAgICAgICAgICA8L3JkZjpsaT4KICAgICAgICAgICAgICAgPHJkZjpsaSByZGY6cGFyc2VUeXBlPSJSZXNvdXJjZSI+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDphY3Rpb24+ZGVyaXZlZDwvc3RFdnQ6' +
'YWN0aW9uPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6cGFyYW1ldGVycz5jb252ZXJ0ZWQgZnJvbSBhcHBsaWNhdGlvbi92bmQuYWRvYmUucGhvdG9zaG9wIHRvIGltYWdlL3BuZzwvc3RFdnQ6cGFyYW1ldGVycz4KICAgICAgICAgICAgICAgPC9yZGY6bGk+CiAgICAgICAgICAgICAgIDxyZGY6bGkgcmRmOnBhcnNlVHlwZT0iUmVzb3VyY2UiPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6YWN0aW9uPnNhdmVkPC9zdEV2dDph' +
'Y3Rpb24+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDppbnN0YW5jZUlEPnhtcC5paWQ6ZDAyY2E5NTUtM2IyYy00MTIyLTkzZTAtOTJmZDI2YzY4ZTdlPC9zdEV2dDppbnN0YW5jZUlEPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6d2hlbj4yMDE2LTAyLTI3VDEzOjMxOjIxKzA0OjAwPC9zdEV2dDp3aGVuPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6c29mdHdhcmVBZ2VudD5BZG9iZSBQaG90b3Nob3AgQ0MgMjAxNCAoTWFj' +
'aW50b3NoKTwvc3RFdnQ6c29mdHdhcmVBZ2VudD4KICAgICAgICAgICAgICAgICAgPHN0RXZ0OmNoYW5nZWQ+Lzwvc3RFdnQ6Y2hhbmdlZD4KICAgICAgICAgICAgICAgPC9yZGY6bGk+CiAgICAgICAgICAgICAgIDxyZGY6bGkgcmRmOnBhcnNlVHlwZT0iUmVzb3VyY2UiPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6YWN0aW9uPnNhdmVkPC9zdEV2dDphY3Rpb24+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDppbnN0YW5jZUlE' +
'PnhtcC5paWQ6MDU2OTA0MWQtNzJmNy00MjFkLTgyZGMtMTAzNGIxZWE4NjE4PC9zdEV2dDppbnN0YW5jZUlEPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6d2hlbj4yMDE3LTAyLTIxVDE0OjQ4OjQ4LTA2OjAwPC9zdEV2dDp3aGVuPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6c29mdHdhcmVBZ2VudD5BZG9iZSBQaG90b3Nob3AgQ0MgMjAxNSAoTWFjaW50b3NoKTwvc3RFdnQ6c29mdHdhcmVBZ2VudD4KICAgICAgICAgICAg' +
'ICAgICAgPHN0RXZ0OmNoYW5nZWQ+Lzwvc3RFdnQ6Y2hhbmdlZD4KICAgICAgICAgICAgICAgPC9yZGY6bGk+CiAgICAgICAgICAgIDwvcmRmOlNlcT4KICAgICAgICAgPC94bXBNTTpIaXN0b3J5PgogICAgICAgICA8eG1wTU06RGVyaXZlZEZyb20gcmRmOnBhcnNlVHlwZT0iUmVzb3VyY2UiPgogICAgICAgICAgICA8c3RSZWY6aW5zdGFuY2VJRD54bXAuaWlkOmQ1ZTQ3ZjMyLTE5OWEtNDM3OS1hMDAxLTI2MzgxZTExMzliNzwv' +
'c3RSZWY6aW5zdGFuY2VJRD4KICAgICAgICAgICAgPHN0UmVmOmRvY3VtZW50SUQ+eG1wLmRpZDozRTNFRTE5RTBCMjA2ODExODIyQUM1MTg3MTkxRkQ2Qzwvc3RSZWY6ZG9jdW1lbnRJRD4KICAgICAgICAgICAgPHN0UmVmOm9yaWdpbmFsRG9jdW1lbnRJRD54bXAuZGlkOjNFM0VFMTlFMEIyMDY4MTE4MjJBQzUxODcxOTFGRDZDPC9zdFJlZjpvcmlnaW5hbERvY3VtZW50SUQ+CiAgICAgICAgIDwveG1wTU06RGVyaXZlZEZyb20+' +
'CiAgICAgICAgIDx4bXBNTTpEb2N1bWVudElEPmFkb2JlOmRvY2lkOnBob3Rvc2hvcDo4NzMxODkyMC0zOTA1LTExN2EtOTlkNS1kZjA0MGM5YWI5NTg8L3htcE1NOkRvY3VtZW50SUQ+CiAgICAgICAgIDx4bXBNTTpJbnN0YW5jZUlEPnhtcC5paWQ6MDU2OTA0MWQtNzJmNy00MjFkLTgyZGMtMTAzNGIxZWE4NjE4PC94bXBNTTpJbnN0YW5jZUlEPgogICAgICAgICA8eG1wTU06T3JpZ2luYWxEb2N1bWVudElEPnhtcC5kaWQ6M0Uz' +
'RUUxOUUwQjIwNjgxMTgyMkFDNTE4NzE5MUZENkM8L3htcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD4KICAgICAgICAgPHBob3Rvc2hvcDpDb2xvck1vZGU+MzwvcGhvdG9zaG9wOkNvbG9yTW9kZT4KICAgICAgICAgPHRpZmY6T3JpZW50YXRpb24+MTwvdGlmZjpPcmllbnRhdGlvbj4KICAgICAgICAgPHRpZmY6WFJlc29sdXRpb24+MTQ0MDAwMC8xMDAwMDwvdGlmZjpYUmVzb2x1dGlvbj4KICAgICAgICAgPHRpZmY6WVJlc29sdXRp' +
'b24+MTQ0MDAwMC8xMDAwMDwvdGlmZjpZUmVzb2x1dGlvbj4KICAgICAgICAgPHRpZmY6UmVzb2x1dGlvblVuaXQ+MjwvdGlmZjpSZXNvbHV0aW9uVW5pdD4KICAgICAgICAgPGV4aWY6Q29sb3JTcGFjZT42NTUzNTwvZXhpZjpDb2xvclNwYWNlPgogICAgICAgICA8ZXhpZjpQaXhlbFhEaW1lbnNpb24+MzI8L2V4aWY6UGl4ZWxYRGltZW5zaW9uPgogICAgICAgICA8ZXhpZjpQaXhlbFlEaW1lbnNpb24+MzI8L2V4aWY6UGl4ZWxZ' +
'RGltZW5zaW9uPgogICAgICA8L3JkZjpEZXNjcmlwdGlvbj4KICAgPC9yZGY6UkRGPgo8L3g6eG1wbWV0YT4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
'ICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAg' +
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAK' +
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
'ICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAg' +
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAg' +
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
'ICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAg' +
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAg' +
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
'ICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAg' +
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
'ICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAg' +
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
'ICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
'ICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAg' +
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
'ICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
'ICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAg' +
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
'CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
'ICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAg' +
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAg' +
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
'ICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAg' +
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAg' +
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
'ICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAg' +
'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAKPD94cGFja2V0IGVuZD0idyI/PlQH85QAAAAgY0hSTQAAeiUAAICD' +
'AAD5/wAAgOkAAHUwAADqYAAAOpgAABdvkl/FRgAAAc5JREFUeNrsl7FOAkEQhr9biSaEi5hYaaUliYWND2DrS/gCVlZ21iTSUVvyBD4EsTDB0GostAUPQpREzmYuGZbdYyV3WOifbPaY2X93bvef2QPy0QBepDUIx6q8BTSBVFqzDF5F+jpwDBj5/Qw8AVM1Nns+BA4884XyZsADMAQ4BQYq4hRoycBrZbsWW8sauypvAJwaoCM7oDHO2bWifHWgY4Bdx+AP6beVbdvyUQBv1wATh2NL+p6y9SwfBfAmAInjLPtq0IW0DP0cDfyUl/gCSIG2' +
'I+J2zuKr8JJIAog9W/oI3MnzGXAUWAdCeaNlAZSNkeGXUbEq1o1VxcrAJnApPVqEwzW++DATod4BI1oYARFQ81SzVHJ60/JNgc8AbqzunLkd0GKsAa9iy9qrmvjK8iViC+HGes2KZ4sMsGfZdOQ7jszZCeQuLORCKkcxlzJix1O+J4HcoAAixxvGYgeoOjjVQK43DTVmwJs10UjsyF1uv+UgkLsAlwjLxJwIf70S+gIoMw2DNPCfhn8zDd/XKP53fRcYSzzZeY092RHJeX9Zvg05hmVcLUgTKXGkS/5YFIma1kQ34Eu3rNaNgH3gFjjJyYqi' +
'MQPugfPvAQDFEQJT9lX76gAAAABJRU5ErkJggg==';
console.log(` | dropdown=false templateImage=${icon}`);
console.log('---');
}
var npmDeps = 'home-config googleapis google-auth-library hapi moment open';
var dirHome = (process.env.HOME || process.env.HOMEPATH || process.env.USERPROFILE);
var dirPlugins = process.argv[1].split('/').slice(0, -1).join('/');
try {
var cfg = Object.assign({}, defaults, require('home-config').load('.bitbarrc').googlecal);
var fs = require('fs');
var { google } = require('googleapis');
var Hapi = require('@hapi/hapi');
var moment = require('moment');
var open = require('open');
var oauth2Client = new google.auth.OAuth2(cfg.clientId, cfg.clientSecret, cfg.clientRedirect);
} catch(e) {
if (process.env.BitBar) {
console.log(`Run Installation | bash="cd ${dirPlugins} && npm install ${npmDeps} && rm package-lock.json || true && node ${process.argv[1]} getNewToken"`);
footer();
} else {
console.log(e);
}
process.exit(1);
}
cfg.tokenFile = cfg.tokenFile.replace('~', dirHome);
if (cfg.tokenFile.indexOf('/') < 0) { cfg.tokenFile = dirPlugins + '/' + cfg.tokenFile; }
function refresh() {
open('bitbar://refreshPlugin?name=googlecal.*?.js');
}
function getNewToken() {
var authUrl = oauth2Client.generateAuthUrl({
access_type: 'offline',
scope: ['https://www.googleapis.com/auth/calendar.readonly']
});
open(authUrl);
console.log('');
console.log('If your browser did not do so automatically, please visit the following URL:');
console.log(authUrl);
console.log('');
var server = new Hapi.Server({ port: cfg.serverPort, host: cfg.serverHost });
server.route({
method: 'GET',
path: '/',
handler: function(request, h) {
var code = request.query.code;
return new Promise((resolve, reject) => {
oauth2Client.getToken(code, function(error, token) {
if (!error) {
fs.writeFileSync(cfg.tokenFile, JSON.stringify(token));
refresh();
console.log(JSON.stringify(token));
msg = 'We\'re all done here! You may now close this window.';
} else {
msg = 'An error occured while trying to get your authorization code: ' + error.message;
reject();
}
console.log(msg);
server.stop({ timeout: 2000 });
resolve(msg);
});
});
}
});
server.start(function(error) {
if (error) {
console.log('An error occured while trying to start the server: ' + error.message);
process.exit(1);
} else {
console.log('Server running at ' + server.info.uri);
console.log('Waiting for authorization...');
}
});
}
function refreshToken(oauth2Client, cb) {
oauth2Client.refreshAccessToken(function(error, token) {
if (!error) {
oauth2Client.credentials = Object.assign({}, oauth2Client.credentials, token);
fs.writeFile(cfg.tokenFile, JSON.stringify(oauth2Client.credentials), function(error, data) {
if (!error) {
cb(oauth2Client);
} else {
footer([error.message]);
process.exit(1);
}
});
} else {
footer([error.message]);
process.exit(1);
}
});
}
function listEvents(oauth2Client) {
var calendar = google.calendar({ version: 'v3', auth: oauth2Client });
var processedCalendars = 0;
var today = moment().format('L');
var tomorrow = moment().add(1, 'days').format('L');
var start = moment(new Date(cfg.startDate));
var dateLimit, evnts = {}, errors = [];
if (!(cfg.calendarId instanceof Array)) {
cfg.calendarId = cfg.calendarId.split(',');
}
if (cfg.days) {
dateLimit = moment(start).add((cfg.days - 1), 'days').format('L');
if (cfg.showEmptyDays) {
for (var x = 0; x < cfg.days; x++) {
evnts[moment(start).add(x, 'days').format('L')] = [];
}
}
}
for (var i = 0; i < cfg.calendarId.length; i++) {
calendar.events.list({
calendarId: cfg.calendarId[i],
timeMin: (cfg.showAllOfFirstDay ? (new Date(moment(start).format('L'))) : (new Date(moment(start)))).toISOString(),
maxResults: cfg.limit,
singleEvents: true,
orderBy: 'startTime'
}, function(error, response) {
processedCalendars++;
if (!error) {
fs.writeFileSync('/Users/chris.castle/google-out-temp.json', JSON.stringify(response));
var events = response.data.items;
if (events.length) {
for (var j = 0; j < events.length; j++) {
var event = events[j];
var eventStart = moment(event.start.dateTime || event.start.date).format('L');
var eventEnd = moment(event.end.dateTime || event.end.date).format('L');
if (cfg.days && eventStart > dateLimit) { break; }
if (!evnts[eventStart]) { evnts[eventStart] = []; }
event.date = eventStart;
event.time = moment(event.start.dateTime || event.start.date).format(cfg.timeFormat);
evnts[eventStart].push(event);
if (cfg.expandEvents && eventStart != eventEnd) {
var day = new Date(eventStart);
while (new Date(day) <= new Date(eventEnd)) {
var me = JSON.parse(JSON.stringify(event));
day.setDate(day.getDate() + 1);
me.date = moment(day).format('L');
me.time = moment(day).format(cfg.timeFormat);
if ((cfg.days && day > dateLimit) || (event.end.date && me.date == moment(event.end.date).format('L'))) { break; }
if (!evnts[me.date]) { evnts[me.date] = []; }
evnts[me.date].push(me);
}
}
}
}
if (processedCalendars >= cfg.calendarId.length) {
var dates = Object.keys(evnts);
var date, d, l, e = 0;
dates.sort();
for (var di = 0; di < dates.length; di++) {
d = dates[di];
if (!evnts.hasOwnProperty(d)) { continue; }
if (e >= cfg.limit) { break; }
if (date != d) {
if (date) { console.log('---'); }
date = moment(new Date(d).toISOString()).format(cfg.dateFormat);
if (d == today) { date += cfg.textToday; }
if (d == tomorrow) { date += cfg.textTomorrow; }
if (process.env.BitBar) {
date += ' |';
if (cfg.dateColor) { date += ` color=${cfg.dateColor}`; }
if (cfg.dateFont) { date += ` font=${cfg.dateFont}`; }
if (cfg.dateSize) { date += ` size=${cfg.dateSize}`; }
}
console.log(date);
}
if (evnts[d].length) {
evnts[d].sort(function(a, b) {
return moment(`${a.date} ${a.time}`, `MM/DD/YYYY ${cfg.timeFormat}`) - moment(`${b.date} ${b.time}`, `MM/DD/YYYY ${cfg.timeFormat}`);
});
for (var s = 0; (s < evnts[d].length && s < cfg.limit); s++) {
var str = `${evnts[d][s].time} - ${evnts[d][s].summary}`;
if (process.env.BitBar) {
str += ' |';
if (cfg.eventColor) { str += ` color=${cfg.eventColor}`; }
if (cfg.eventFont) { str += ` font=${cfg.eventFont}`; }
if (cfg.eventLength) { str += ` length=${cfg.eventLength}`; }
if (cfg.eventSize) { str += ` size=${cfg.eventSize}`; }
altStr = str;
str += ` href=${evnts[d][s].htmlLink}`;
altStr += evnts[d][s].hangoutLink ? ` href=${evnts[d][s].hangoutLink}` : '';
altStr += ' alternate=true';
}
console.log(str);
console.log(altStr);
e++;
}
}
}
if (Object.keys(evnts).length === 0) {
console.log('No upcoming events found.');
}
}
} else {
errors.push(error.message + ' (calendar: ' + cfg.calendarId[i] +')');
}
if (processedCalendars >= cfg.calendarId.length) {
footer(errors);
}
});
}
}
function run() {
if (fs.existsSync(cfg.tokenFile)) {
var token = fs.readFileSync(cfg.tokenFile, 'utf8');
if (token) { oauth2Client.credentials = JSON.parse(token); }
if (!oauth2Client.credentials.refresh_token) {
fs.unlinkSync(cfg.tokenFile);
console.log('No refresh token set');
console.log('You need to re-authorize this plugin with Google');
if (process.env.BitBar) {
console.log('Click here to view your currently authorized apps | href=https://myaccount.google.com/permissions');
} else {
console.log('Visit this URL to view your currently authorized apps: https://myaccount.google.com/permissions');
}
console.log('You will want to find this plugin and click \'Remove\'');
if (process.env.BitBar) {
console.log(`After you have done that, click here to re-authorize this plugin | bash=${process.argv[1]} param1=getNewToken refresh=false terminal=true`);
} else {
console.log('After you have done that, refresh this plugin and run the setup process again');
}
footer();
process.exit(1);
} else if (new Date(Date.now()) > oauth2Client.credentials.expiry_date) {
refreshToken(oauth2Client, listEvents);
} else {
listEvents(oauth2Client);
}
} else {
if (process.env.BitBar) {
console.log(`Login To Google | bash=${process.argv[1]} param1=getNewToken refresh=false terminal=true`);
footer();
} else {
console.log('Google login required.');
getNewToken();
}
}
}
function footer(errors) {
if (errors && errors.length) {
console.log('---');
console.log('Errors:');
for (var e = 0; e < errors.length; e++) {
console.log(errors[e]);
}
}
if (process.env.BitBar) {
console.log('---');
console.log(`BitBar Google Calendar Plugin v${ver}`);
console.log('--by Kodie Grantham | href=http://kodieg.com');
console.log('-----');
console.log('--GitHub Page | href=https://github.com/kodie/bitbar-googlecal');
console.log('--Changelog | href=https://github.com/kodie/bitbar-googlecal/blob/master/CHANGELOG.md');
console.log('-----');
console.log('--Refresh | refresh=true terminal=false');
}
}
if (process.argv[2] == 'getNewToken') {
getNewToken();
} else if (process.argv[2] == 'refresh') {
refresh();
} else {
run();
}
#!/usr/bin/env /usr/bin/ruby
# <bitbar.title>Heroku</bitbar.title>
# <bitbar.version>v0.2</bitbar.version>
# <bitbar.author>Deluan Quintao</bitbar.author>
# <bitbar.author.github>deluan</bitbar.author.github>
# <bitbar.desc>Currently this plugin displays Heroku service status and open issues</bitbar.desc>
# <bitbar.image>http://i.imgur.com/B7A1wvm.png</bitbar.image>
# <bitbar.dependencies>ruby</bitbar.dependencies>
require 'json'
require 'open-uri'
HEROKU_CMD="/usr/local/bin/heroku"
ICON="iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAAlwSFlzAAAWJQAAFiUBSVIk8AAABCRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IlhNUCBDb3JlIDUuNC4wIj4KICAgPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICAgICAgPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIKICAgICAgICAgICAgeG1sbnM6dGlmZj0iaHR0cDovL25zLmFkb2JlLmNvbS90aWZmLzEuMC8iCiAgICAgICAgICAgIHhtbG5zOmV4aWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20vZXhpZi8xLjAvIgogICAgICAgICAgICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgICAgICAgICAgIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyI+CiAgICAgICAgIDx0aWZmOlJlc29sdXRpb25Vbml0PjI8L3RpZmY6UmVzb2x1dGlvblVuaXQ+CiAgICAgICAgIDx0aWZmOkNvbXByZXNzaW9uPjU8L3RpZmY6Q29tcHJlc3Npb24+CiAgICAgICAgIDx0aWZmOlhSZXNvbHV0aW9uPjE0NDwvdGlmZjpYUmVzb2x1dGlvbj4KICAgICAgICAgPHRpZmY6T3JpZW50YXRpb24+MTwvdGlmZjpPcmllbnRhdGlvbj4KICAgICAgICAgPHRpZmY6WVJlc29sdXRpb24+MTQ0PC90aWZmOllSZXNvbHV0aW9uPgogICAgICAgICA8ZXhpZjpQaXhlbFhEaW1lbnNpb24+MzI8L2V4aWY6UGl4ZWxYRGltZW5zaW9uPgogICAgICAgICA8ZXhpZjpDb2xvclNwYWNlPjE8L2V4aWY6Q29sb3JTcGFjZT4KICAgICAgICAgPGV4aWY6UGl4ZWxZRGltZW5zaW9uPjMyPC9leGlmOlBpeGVsWURpbWVuc2lvbj4KICAgICAgICAgPGRjOnN1YmplY3Q+CiAgICAgICAgICAgIDxyZGY6QmFnLz4KICAgICAgICAgPC9kYzpzdWJqZWN0PgogICAgICAgICA8eG1wOk1vZGlmeURhdGU+MjAxNi0xMi0yNlQyMzoxMjoyODwveG1wOk1vZGlmeURhdGU+CiAgICAgICAgIDx4bXA6Q3JlYXRvclRvb2w+UGl4ZWxtYXRvciAzLjY8L3htcDpDcmVhdG9yVG9vbD4KICAgICAgPC9yZGY6RGVzY3JpcHRpb24+CiAgIDwvcmRmOlJERj4KPC94OnhtcG1ldGE+Cm0tugEAAAUiSURBVFjDjZfLb1R1FMc/v8dMW0qFysNWUAtCCCVEukFXQHRhZEVcyMaFiXThwkdY8QewQIzoxhADiQtdCCYSF+jKHXaBAglEY5sWebY82o5lpo+Ze+/vuLgz9z0jdzNzb373fM/je875XkXz+vbTSzt6Sj1HA+dGxYlyIiCCiBD+FYTWs+a9ZO6Jz8fvNu8RcIhodabh/FOfnHxrHEABnP/8ymGjzWmF6q97K4UGisBDB/4fPHYerCkROFcJvMYHH546eE59f/KPl7Xmmlamz/MbhM7mvZdOkUcOdAKP77UyBM6vohmxCnfMmq6+urdSCC4iBL6LjCitClNPdDaIgTQJm7GzvvMomXKf560cswJH6l49PFkAXu42rO7vBRGCQKg8rOFcE5A48jAyWPfCGlRYcf59XGNlySP0IV22hldHhCOWXNSxQd8L2LStn9cP7wRgZdHjx69+x68FNAsTpd1vBGzdvZE3330FpcBrBJz7Yoylaj3KWpYzADbN9hi8ebIZS3xFhhSpmisFw3s3oVR47u7ELPMPa2ijOhLWFrZLlNaWM6QijonZjN4LGNzSz+Zt6yInr1+6nQ4oVbL4XVsUebr1IJOC2KnE/5EDQ2gThn/zz0fcmZiNou/UqrpT5MlapUpAXDbfc2zfM8DQzg0hT5Y8xi6OP+WcAFsYeYaxKQdakYc/KA0Lc0tc/OYqIlBbWGb+QQ2l1VMNKVsETgFbW+gigrjwqQscToR7k/M451AKlFEYraISdpyQCLYIPL5vES52wG8ECLCqr0zP6jJdPSW0UTTqPtXKMguzi/i+S7G/2HbonM2PWFKzP+mBKWleO7id9YN9rFm/iq5uG6a6eTVWfKZvzjP28zjTtyoYq6LIye6V1m7IgyfTlqZguduy69XNtLvK3Zah4Y0MvLSWC19f5t7UHKYoE4ms6xx4pgTpGqSvIHAsVesszC2xVKtHz7t7y+w/NIwxClcQebLTbA6c7JZLt+Dcgxr3J+eY/qfC/MMai09W8D2H0oodI4Psf3sXxmgGhvp5dmA1j+4uxKO4YKXbPLikFpNW4HuOiWvT/HX5Ho/vPaG+7CEISqmmohBcIFwfu83Iga30b+hFa0Xf2h5mblcwSrfVEzYCJp32cJ0qZmeqXDh9mZlbFQC0VpiSznCGaAc430UZU1qFLWvaixmb7dMkW9FQebRIEDiM1TmOkCGsyrFECvVAvOuSo7hIiHgBg1vW8tyLa/C9oI1KSpDKZcc2xZETl1xLm3UsIjgn9D7TzRvv7Karx+ICFxt1BTIsu7wLdEa21XU2NfH4lUiUrH++j32HhnEuQdYceBxdcm+ka56ZMQL6qaQ3MLx3M3v2DSVKkd5qqTWdFS/R4MvPGJsTIynw2JjvBVQry5napg2qgplV9M2QLLuWAoYmU9Yy8uv5G4xfvR+KjjacaZeBZNqznWbjZskba704dvFvrv92C1MybXV/i4TG6HgOKFXcugnSWueKwRHQRnNn4jGTN2YwJd3xowPABcIv312h3GUR4P7UbHMZkeNMi6BWkLMlUz4S6vSEGGlmpbHiR6mVwpWadn7yxkzULcYoUCqvBRCMLhF49bPaiTvh+Y2q1iZ1ILuMsuDtOKONxlqNLekCcIk+zfygUZVATuiPPjs4JYEbRaRSMuXONcsIlTx58+M5m3ZrSohIRURGj597byoa319+/NMOpUtHRdyoSPh5XiSj2onXvKBJtxuAE0TBGak3Th3/4f1xgP8A6fG25jZNOt0AAAAASUVORK5CYII="
def status_icon(icon="", ok=true)
if icon.respond_to?('each')
msg = ""
icon.each do |i|
msg += "#{i} | image=#{ICON} dropdown=false\n"
end
else
msg = "#{icon} | image=#{ICON} dropdown=false\n"
msg += "#{icon} | image=#{ICON} dropdown=false color=red\n" unless ok
end
msg + "---"
end
def status
begin
@status ||= (content = URI("https://status.heroku.com/api/v3/current-status").read; JSON.parse(content))
rescue => e
puts status_icon ":interrobang:", false
puts "Error: #{e} | color=red"
puts "---"
puts "Refresh... | refresh=true"
exit
end
end
def issues
@issues ||= [].tap do |resp|
status["issues"].each do |issue|
href = issue["full_url"]
title = issue["title"]
color = issue["status_prod"]
resp << "#{title} | color=#{color} href=#{href}"
end
end
end
if status["status"]["Production"] != "green"
puts status_icon [":grey_exclamation:", ":exclamation:"], false
else
puts status_icon
end
puts "---"
if issues.size > 0
issues.each do |issue|
puts issue
end
else
puts "All good. Relax | href=https://status.heroku.com/ color=green"
end
puts "---"
puts "Refresh... | refresh=true"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment