Added support for displaying users YouTube channels.

Pyinstaller 6.0.0 causes errors. You can tweak build.yml to revert to 5.13.2
This commit is contained in:
Ross Scroggs
2023-09-26 21:10:52 -07:00
parent 37a968a142
commit 086c7469c5
16 changed files with 256 additions and 10 deletions

View File

@ -114,7 +114,7 @@ jobs:
path: |
bin.tar.xz
src/cpython
key: gam-${{ matrix.jid }}-20230825
key: gam-${{ matrix.jid }}-20230626
- name: Untar Cache archive
if: matrix.goal == 'build' && steps.cache-python-ssl.outputs.cache-hit == 'true'
@ -480,6 +480,8 @@ jobs:
cd pyinstaller
export latest_release=$(git tag --list | grep -v dev | grep -v rc | sort -Vr | head -n1)
git checkout "${latest_release}"
#V6.0.0 causes errors, comment above and uncomment below to use 5.13.2
#git checkout "v5.13.2"
# remove pre-compiled bootloaders so we fail if bootloader compile fails
rm -rvf PyInstaller/bootloader/*-*/*
cd bootloader

View File

@ -611,4 +611,5 @@
(file|textfile|htmlfile <FileName> [charset <Charset>])|
(gdoc|ghtml <UserGoogleDoc>)|
(gcsdoc|gcshtml <StorageBucketObjectName>)
<YouTubeChannelID> ::= <String>
```

View File

@ -10,6 +10,12 @@ Add the `-s` option to the end of the above commands to suppress creating the `g
See [Downloads](https://github.com/taers232c/GAMADV-XTD3/wiki/Downloads) for Windows or other options, including manual installation.
### 6.64.00
Added support for displaying users YouTube channels.
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-YouTube
### 6.63.19
Fixed bug in `gam print vacation` where `endDate` value was not converted to `yyyy-mm-dd` format.

View File

@ -334,7 +334,7 @@ writes the credentials into the file oauth2.txt.
admin@server:/Users/admin/bin/gamadv-xtd3$ rm -f /Users/admin/GAMConfig/oauth2.txt
admin@server:/Users/admin/bin/gamadv-xtd3$ ./gam version
WARNING: Config File: /Users/admin/GAMConfig/gam.cfg, Section: DEFAULT, Item: oauth2_txt, Value: /Users/admin/GAMConfig/oauth2.txt, Not Found
GAMADV-XTD3 6.63.19 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
GAMADV-XTD3 6.64.00 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
Ross Scroggs <ross.scroggs@gmail.com>
Python 3.10.8 64-bit final
MacOS High Sierra 10.13.6 x86_64
@ -984,7 +984,7 @@ writes the credentials into the file oauth2.txt.
C:\GAMADV-XTD3>del C:\GAMConfig\oauth2.txt
C:\GAMADV-XTD3>gam version
WARNING: Config File: C:\GAMConfig\gam.cfg, Section: DEFAULT, Item: oauth2_txt, Value: C:\GAMConfig\oauth2.txt, Not Found
GAMADV-XTD3 6.63.19 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
GAMADV-XTD3 6.64.00 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
Ross Scroggs <ross.scroggs@gmail.com>
Python 3.11.5 64-bit final
Windows-10-10.0.17134 AMD64

View File

@ -97,6 +97,7 @@
<ThreadIDList> ::= "<ThreadID>(,<ThreadID>)*"
<TimeList> ::= "<Time>(,<Time>)*"
<UserList> ::= "<UserItem>(,<UserItem>)*"
<YouTubeChannelIDList> ::= "<YouTubeChannelID>(,<YouTubeChannelID>)*"
```
## List quoting rules
Items in a list can be separated by commas or spaces; if an item itself contains a comma, a space or a single quote, special quoting must be used.

View File

@ -137,6 +137,9 @@ By default, only tasks with status `needsAction` are displayed.
* `showcompleted` - Add completed tasks to the display. `showHidden` must also be True to show tasks completed in first party clients, such as the web UI and Google's mobile apps.
* `showall` - Equivalent to `showdeleted` `showhidden` `showcompleted`
By default, Gam displays the information as columns of fields; the following option causes the output to be in JSON format,
* `formatjson` - Display the fields in JSON format.
By default, when writing CSV files, Gam uses a quote character of double quote `"`. The quote character is used to enclose columns that contain
the quote character itself, the column delimiter (comma by default) and new-line characters. Any quote characters within the column are doubled.
When using the `formatjson` option, double quotes are used extensively in the data resulting in hard to read/process output.
@ -194,6 +197,9 @@ By default, Gam displays the task lists as an indented list of keys and values.
gam <UserTypeEntity> print tasklists [todrive <ToDriveAttribute>*]
[countsonly | (formatjson [quotechar <Character>])]
```
By default, Gam displays the information as columns of fields; the following option causes the output to be in JSON format,
* `formatjson` - Display the fields in JSON format.
By default, when writing CSV files, Gam uses a quote character of double quote `"`. The quote character is used to enclose columns that contain
the quote character itself, the column delimiter (comma by default) and new-line characters. Any quote characters within the column are doubled.
When using the `formatjson` option, double quotes are used extensively in the data resulting in hard to read/process output.

93
docs/Users-YouTube.md Normal file
View File

@ -0,0 +1,93 @@
# Users - YouTube
- [API documentation](#api-documentation)
- [Notes](#notes)
- [Definitions](#definitions)
- [Display Selected YouTube Channels](#display_selected-youtube_channels)
- [Display Owned YouTube Channels](#display-owned-youtube_channels)
## API documentation
* https://developers.google.com/youtube/v3/docs/channels/list
## Notes
To use these commands you must add the 'YouTube API' to your project and update your service account authorization.
```
gam update project
gam user user@domain.com update serviceaccount
```
## Definitions
* [`<UserTypeEntity>`](Collections-of-Users)
```
<YouTubeChannelID> ::= <String>
<YouTubeChannelIDList> ::= "<YouTubeChannelID>(,<YouTubeChannelID>)*"
<YouTubeChannelFieldName> ::=
brandingsettings|
contentdetails|
contentownerdetails|
id|
localizations|
snippet|
statistics|
status|
topicdetails
<YouTubeChannelFieldNameList> ::= "<YouTubeChannelFieldName>(,<YouTubeChannelFieldName>)*"
```
## Display Selected YouTube Channels
Display YouTube channels selected by ID.
```
gam <UserTypeEntity> show youtubechannels
channels <YouTubeChannelIDList>
[allfields|(fields <YouTubeChannelFieldNameList>)]
[formatjson]
```
By default, only the YouTube channel ID is displayed; use `allfields|fields` to selct additional fields for display.
By default, Gam displays the YouTube channels as an indented list of keys and values.
* `formatjson` - Display the YouTube channels in JSON format
```
gam <UserTypeEntity> print youtubechannels [todrive <ToDriveAttribute>*]
[channels <YouTubeChannelIDList>]
[allfields|(fields <YouTubeChannelFieldNameList>)]
[formatjson [quotechar <Character>]]
```
By default, only the YouTube channel ID is displayed; use `allfields|fields` to selct additional fields for display.
By default, Gam displays the information as columns of fields; the following option causes the output to be in JSON format,
* `formatjson` - Display the fields in JSON format.
By default, when writing CSV files, Gam uses a quote character of double quote `"`. The quote character is used to enclose columns that contain
the quote character itself, the column delimiter (comma by default) and new-line characters. Any quote characters within the column are doubled.
When using the `formatjson` option, double quotes are used extensively in the data resulting in hard to read/proces output.
The `quotechar <Character>` option allows you to choose an alternate quote character, single quote for instance, that makes for readable/procesable output.
`quotechar` defaults to `gam.cfg/csv_output_quote_char`. When uploading CSV files to Google, double quote `"` should be used.
## Display Owned YouTube Channels
Display YouTube channels owned by a user.
```
gam <UserTypeEntity> show youtubechannels
[allfields|(fields <YouTubeChannelFieldNameList>)]
[formatjson]
```
By default, only the YouTube channel ID is displayed; use `allfields|fields` to selct additional fields for display.
By default, Gam displays the YouTube channels as an indented list of keys and values.
* `formatjson` - Display the YouTube channels in JSON format
```
gam <UserTypeEntity> print youtubechannels [todrive <ToDriveAttribute>*]
[allfields|(fields <YouTubeChannelFieldNameList>)]
[formatjson [quotechar <Character>]]
```
By default, only the YouTube channel ID is displayed; use `allfields|fields` to selct additional fields for display.
By default, Gam displays the information as columns of fields; the following option causes the output to be in JSON format,
* `formatjson` - Display the fields in JSON format.
By default, when writing CSV files, Gam uses a quote character of double quote `"`. The quote character is used to enclose columns that contain
the quote character itself, the column delimiter (comma by default) and new-line characters. Any quote characters within the column are doubled.
When using the `formatjson` option, double quotes are used extensively in the data resulting in hard to read/proces output.
The `quotechar <Character>` option allows you to choose an alternate quote character, single quote for instance, that makes for readable/procesable output.
`quotechar` defaults to `gam.cfg/csv_output_quote_char`. When uploading CSV files to Google, double quote `"` should be used.

View File

@ -3,7 +3,7 @@
Print the current version of Gam with details
```
gam version
GAMADV-XTD3 6.63.19 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
GAMADV-XTD3 6.64.00 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
Ross Scroggs <ross.scroggs@gmail.com>
Python 3.11.5 64-bit final
MacOS Monterey 12.6.6 x86_64
@ -15,7 +15,7 @@ Time: 2023-06-02T21:10:00-07:00
Print the current version of Gam with details and time offset information
```
gam version timeoffset
GAMADV-XTD3 6.63.19 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
GAMADV-XTD3 6.64.00 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
Ross Scroggs <ross.scroggs@gmail.com>
Python 3.11.5 64-bit final
MacOS Monterey 12.6.6 x86_64
@ -27,7 +27,7 @@ Your system time differs from www.googleapis.com by less than 1 second
Print the current version of Gam with extended details and SSL information
```
gam version extended
GAMADV-XTD3 6.63.19 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
GAMADV-XTD3 6.64.00 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
Ross Scroggs <ross.scroggs@gmail.com>
Python 3.11.5 64-bit final
MacOS Monterey 12.6.6 x86_64
@ -64,7 +64,7 @@ MacOS High Sierra 10.13.6 x86_64
Path: /Users/Admin/bin/gamadv-xtd3
Version Check:
Current: 5.35.08
Latest: 6.63.19
Latest: 6.64.00
echo $?
1
```
@ -72,7 +72,7 @@ echo $?
Print the current version number without details
```
gam version simple
6.63.19
6.64.00
```
In Linux/MacOS you can do:
```
@ -82,7 +82,7 @@ echo $VER
Print the current version of Gam and address of this Wiki
```
gam help
GAM 6.63.19 - https://github.com/taers232c/GAMADV-XTD3
GAM 6.64.00 - https://github.com/taers232c/GAMADV-XTD3
Ross Scroggs <ross.scroggs@gmail.com>
Python 3.11.5 64-bit final
MacOS Monterey 12.6.6 x86_64

View File

@ -159,3 +159,4 @@ Service Account Access
* [Users - Spreadsheets](Users-Spreadsheets)
* [Users - Tasks](Users-Tasks)
* [Users - Tokens](Users-Tokens)
* [Users - YouTube](Users-YouTube)

View File

@ -628,6 +628,7 @@ If an item contains spaces, it should be surrounded by ".
(file|textfile|htmlfile <FileName> [charset <Charset>])|
(gdoc|ghtml <UserGoogleDoc>)|
(gcsdoc|gcshtml <StorageBucketObjectName>)
<YouTubeChannelID> ::= <String>
## Lists of basic items
<APIScopeURLList> ::= "<APIScopeURL>(,<APIScopeURL>)*"
@ -721,6 +722,7 @@ If an item contains spaces, it should be surrounded by ".
<ThreadIDList> ::= "<ThreadID>(,<ThreadID>)*"
<TimeList> ::= "<Time>(,<Time>)*"
<UserList> ::= "<UserItem>(,<UserItem>)*"
<YouTubeChannelIDList> ::= "<YouTubeChannelID>(,<YouTubeChannelID>)*"
## Quoting rules
@ -7255,7 +7257,7 @@ gam <UserTypeEntity> print contacts [todrive <ToDriveAttribute>*]
names|
phonenumbers|
photos
<OtherContactsFieldNameList> ::= "<OtherContactsFieldName>(,<OtherContactFieldName>)*"
<OtherContactsFieldNameList> ::= "<OtherContactsFieldName>(,<OtherContactsFieldName>)*"
<OtherContactsSelection> ::=
[query <QueryContact>]
@ -7597,6 +7599,32 @@ gam print tokens|token [todrive <ToDriveAttribute>*] [clientid <ClientID>]
[aggregateby|orderby clientid|id|appname|displaytext] [delimiter <Character>]
[<UserTypeEntity>]
# Users - YouTube
<YouTubeChannelID> ::= <String>
<YouTubeChannelIDList> ::= "<YouTubeChannelID>(,<YouTubeChannelID>)*"
<YouTubeChannelFieldName> ::=
brandingsettings|
contentdetails|
contentownerdetails|
id|
localizations|
snippet|
statistics|
status|
topicdetails
<YouTubeChannelFieldNameList> ::= "<YouTubeChannelFieldName>(,<YouTubeChannelFieldName>)*"
gam <UserTypeEntity> show youtubechannels
[channels <YouTubeChannelIDList>]
[allfields|(fields <YouTubeChannelFieldNameList>)]
[formatjson]
gam <UserTypeEntity> print youtubechannels [todrive <ToDriveAttribute>*]
[channels <YouTubeChannelIDList>]
[allfields|(fields <YouTubeChannelFieldNameList>)]
[formatjson [quotechar <Character>]]
# Verifications
gam create|add verify|verification <DomainName>

View File

@ -2,6 +2,12 @@
Merged GAM-Team version
6.64.00
Added support for displaying users YouTube channels.
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-YouTube
6.63.19
Fixed bug in `gam print vacation` where `endDate` value was not converted to `yyyy-mm-dd` format.

View File

@ -48418,6 +48418,92 @@ def printShowWorkingLocation(users):
if csvPF:
csvPF.writeCSVfile('Calendar Working Locations')
YOUTUBE_CHANNEL_FIELDS_CHOICE_MAP = {
'brandingsettings': 'brandingSettings',
'contentdetails': 'contentDetails',
'contentownerdetails': 'contentOwnerDetails',
'id': 'id',
'localizations': 'localizations',
'snippet': 'snippet',
'statistics': 'statistics',
'status': 'status',
'topicdetails': 'topicDetails',
}
YOUTUBE_CHANNEL_TIME_OBJECTS = {'publishedAt'}
# gam <UserTypeEntity> show youtubechannels
# [channels <YouTubeChannelIDList>]
# [allfields|(fields <YouTubeChannelFieldNameList>)]
# [formatjson]
# gam <UserTypeEntity> print youtubechannels [todrive <ToDriveAttribute>*]
# [channels <YouTubeChannelIDList>]
# [allfields|(fields <YouTubeChannelFieldNameList>)]
# [formatjson [quotechar <Character>]]
def printShowYouTubeChannel(users):
csvPF = CSVPrintFile(['User', 'id'], 'sortall') if Act.csvFormat() else None
FJQC = FormatJSONQuoteChar(csvPF)
kwargs = {'mine': True}
fieldsList = ['id']
while Cmd.ArgumentsRemaining():
myarg = getArgument()
if csvPF and myarg == 'todrive':
csvPF.GetTodriveParameters()
elif myarg == 'channels':
kwargs.pop('mine', None)
kwargs['id'] = ','.join(getEntityList(Cmd.OB_YOUTUBE_CHANNEL_ID_LIST))
elif getFieldsList(myarg, YOUTUBE_CHANNEL_FIELDS_CHOICE_MAP, fieldsList):
pass
elif myarg == 'allfields':
for field in YOUTUBE_CHANNEL_FIELDS_CHOICE_MAP:
addFieldToFieldsList(field, YOUTUBE_CHANNEL_FIELDS_CHOICE_MAP, fieldsList)
else:
FJQC.GetFormatJSONQuoteChar(myarg, True)
kwargs['part'] = ','.join(set(fieldsList))
i, count, users = getEntityArgument(users)
for user in users:
i += 1
user, yt = buildGAPIServiceObject(API.YOUTUBE, user, i, count)
if not yt:
continue
try:
channels = callGAPIpages(yt.channels(), 'list', 'items',
throwReasons=GAPI.YOUTUBE_THROW_REASONS,
fields='nextPageToken,items', **kwargs)
except (GAPI.serviceNotAvailable, GAPI.authError):
entityServiceNotApplicableWarning(Ent.USER, user, i, count)
break
if not csvPF:
jcount = len(channels)
if not FJQC.formatJSON:
entityPerformActionNumItems([Ent.USER, user], jcount, Ent.YOUTUBE_CHANNEL, i, count)
Ind.Increment()
j = 0
for channel in channels:
j += 1
if FJQC.formatJSON:
printLine(json.dumps(cleanJSON(channel, timeObjects=YOUTUBE_CHANNEL_TIME_OBJECTS),
ensure_ascii=False, sort_keys=True))
break
printEntity([Ent.YOUTUBE_CHANNEL, channel['id']], j, jcount)
Ind.Increment()
showJSON(None, channel, skipObjects={'id'}, timeObjects=YOUTUBE_CHANNEL_TIME_OBJECTS)
Ind.Decrement()
Ind.Decrement()
else:
for channel in channels:
row = {'User': user, 'id': channel['id']}
flattenJSON(channel, flattened=row, timeObjects=YOUTUBE_CHANNEL_TIME_OBJECTS)
if not FJQC.formatJSON:
csvPF.WriteRowTitles(row)
elif csvPF.CheckRowTitles(row):
row = {'User': user, 'id': channel['id'],
'JSON': json.dumps(cleanJSON(channel, timeObjects=YOUTUBE_CHANNEL_TIME_OBJECTS),
ensure_ascii=False, sort_keys=True)}
csvPF.WriteRowNoFilter(row)
if csvPF:
csvPF.writeCSVfile('YouTube Channels')
def _getEntityMimeType(fileEntry):
if fileEntry['mimeType'] == MIMETYPE_GA_FOLDER:
return Ent.DRIVE_FOLDER
@ -70980,6 +71066,7 @@ USER_COMMANDS_WITH_OBJECTS = {
Cmd.ARG_VACATION: printShowVacation,
Cmd.ARG_VAULTHOLD: printShowUserVaultHolds,
Cmd.ARG_WORKINGLOCATION: printShowWorkingLocation,
Cmd.ARG_YOUTUBECHANNEL: printShowYouTubeChannel,
}
),
'process':
@ -71071,6 +71158,7 @@ USER_COMMANDS_WITH_OBJECTS = {
Cmd.ARG_VAULTHOLD: printShowUserVaultHolds,
Cmd.ARG_VACATION: printShowVacation,
Cmd.ARG_WORKINGLOCATION: printShowWorkingLocation,
Cmd.ARG_YOUTUBECHANNEL: printShowYouTubeChannel,
}
),
'spam':
@ -71293,6 +71381,7 @@ USER_COMMANDS_OBJ_ALIASES = {
Cmd.ARG_VAULTHOLDS: Cmd.ARG_VAULTHOLD,
Cmd.ARG_VERIFICATIONCODES: Cmd.ARG_BACKUPCODE,
Cmd.ARG_WORKINGLOCATIONS: Cmd.ARG_WORKINGLOCATION,
Cmd.ARG_YOUTUBECHANNELS: Cmd.ARG_YOUTUBECHANNEL,
}
def showAPICallsRetryData():

View File

@ -88,6 +88,7 @@ STORAGEREAD = 'storageread'
STORAGEWRITE = 'storagewrite'
TASKS = 'tasks'
VAULT = 'vault'
YOUTUBE = 'youtube'
#
CHROMEVERSIONHISTORY_URL = 'https://versionhistory.googleapis.com/v1/chrome/platforms'
DRIVE_SCOPE = 'https://www.googleapis.com/auth/drive'
@ -177,6 +178,7 @@ PROJECT_APIS = [
'storage-api.googleapis.com',
'tasks.googleapis.com',
'vault.googleapis.com',
'youtube.googleapis.com',
]
_INFO = {
@ -246,6 +248,7 @@ _INFO = {
STORAGEWRITE: {'name': 'Cloud Storage API - Write', 'version': 'v1', 'v2discovery': True, 'mappedAPI': STORAGE},
TASKS: {'name': 'Tasks API', 'version': 'v1', 'v2discovery': True},
VAULT: {'name': 'Vault API', 'version': 'v1', 'v2discovery': True},
YOUTUBE: {'name': 'Youtube API', 'version': 'v3', 'v2discovery': True},
}
READONLY = ['readonly',]
@ -626,6 +629,10 @@ _SVCACCT_SCOPES = [
'api': TASKS,
'subscopes': READONLY,
'scope': 'https://www.googleapis.com/auth/tasks'},
{'name': 'Youtube API - read only',
'api': YOUTUBE,
'subscopes': [],
'scope': 'https://www.googleapis.com/auth/youtube.readonly'},
]
_SVCACCT_SPECIAL_SCOPES = [

View File

@ -777,6 +777,8 @@ class GamCLArgs():
ARG_VERIFY = 'verify'
ARG_WORKINGLOCATION = 'workinglocation'
ARG_WORKINGLOCATIONS = 'workinglocations'
ARG_YOUTUBECHANNEL = 'youtubechannel'
ARG_YOUTUBECHANNELS = 'youtubechannels'
# Lists of arguments for use in checkArgumentPresent
CLEAR_NONE_ARGUMENT = ['clear', 'none',]
@ -985,6 +987,7 @@ class GamCLArgs():
OB_USER_ENTITY = 'UserEntity'
OB_USER_ITEM = 'UserItem'
OB_USER_NAME = 'UserName'
OB_YOUTUBE_CHANNEL_ID_LIST = 'YouTubeChannelIDlist'
#
# Error message types; keys into ARGUMENT_ERROR_NAMES; arbitrary values but must be unique

View File

@ -363,6 +363,7 @@ class GamEntity():
VAULT_QUERY = 'vltq'
WEBCLIPS_ENABLED = 'webc'
WORKING_LOCATION = 'wrkl'
YOUTUBE_CHANNEL = 'ytch'
# _NAMES[0] is plural, _NAMES[1] is singular unless the item name is explicitly plural (Calendar Settings)
# For items with Boolean values, both entries are singular (Forward, POP)
# These values can be translated into other languages
@ -689,6 +690,7 @@ class GamEntity():
VAULT_QUERY: ['Vault Queries', 'Vault Query'],
WEBCLIPS_ENABLED: ['Web Clips Enabled', 'Web Clips Enabled'],
WORKING_LOCATION: ['Working Locations', 'Working Location'],
YOUTUBE_CHANNEL: ['YouTube Channels', 'YouTube Channel'],
ROLE_MANAGER: ['Managers', 'Manager'],
ROLE_MEMBER: ['Members', 'Member'],
ROLE_OWNER: ['Owners', 'Owner'],

View File

@ -262,6 +262,7 @@ SHEETS_ACCESS_THROW_REASONS = DRIVE_USER_THROW_REASONS+[NOT_FOUND, PERMISSION_DE
TASK_THROW_REASONS = [SERVICE_NOT_AVAILABLE, BAD_REQUEST, PERMISSION_DENIED, INVALID, NOT_FOUND, ACCESS_NOT_CONFIGURED]
TASKLIST_THROW_REASONS = [SERVICE_NOT_AVAILABLE, BAD_REQUEST, PERMISSION_DENIED, INVALID, NOT_FOUND, ACCESS_NOT_CONFIGURED]
USER_GET_THROW_REASONS = [USER_NOT_FOUND, DOMAIN_NOT_FOUND, DOMAIN_CANNOT_USE_APIS, FORBIDDEN, BAD_REQUEST, SYSTEM_ERROR]
YOUTUBE_THROW_REASONS = [SERVICE_NOT_AVAILABLE, AUTH_ERROR]
REASON_MESSAGE_MAP = {
ABORTED: [