gam7 7.3.6__tar.gz → 7.3.8__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of gam7 might be problematic. Click here for more details.

Files changed (109) hide show
  1. {gam7-7.3.6 → gam7-7.3.8}/.github/workflows/pypi.yml +1 -0
  2. {gam7-7.3.6 → gam7-7.3.8}/PKG-INFO +11 -2
  3. {gam7-7.3.6 → gam7-7.3.8}/pyproject.toml +26 -5
  4. {gam7-7.3.6 → gam7-7.3.8}/src/GamCommands.txt +13 -5
  5. {gam7-7.3.6 → gam7-7.3.8}/src/GamUpdate.txt +11 -2
  6. {gam7-7.3.6 → gam7-7.3.8}/src/gam/__init__.py +71 -39
  7. {gam7-7.3.6 → gam7-7.3.8}/.github/ISSUE_TEMPLATE/aa-question.md +0 -0
  8. {gam7-7.3.6 → gam7-7.3.8}/.github/ISSUE_TEMPLATE/za-bug-report.md +0 -0
  9. {gam7-7.3.6 → gam7-7.3.8}/.github/ISSUE_TEMPLATE/zz-feature-request.md +0 -0
  10. {gam7-7.3.6 → gam7-7.3.8}/.github/ISSUE_TEMPLATE.txt +0 -0
  11. {gam7-7.3.6 → gam7-7.3.8}/.github/actions/creds.tar.xz.gpg +0 -0
  12. {gam7-7.3.6 → gam7-7.3.8}/.github/actions/decrypt.sh +0 -0
  13. {gam7-7.3.6 → gam7-7.3.8}/.github/actions/entitlements.plist +0 -0
  14. {gam7-7.3.6 → gam7-7.3.8}/.github/actions/package_exclusions.txt +0 -0
  15. {gam7-7.3.6 → gam7-7.3.8}/.github/stale.yml +0 -0
  16. {gam7-7.3.6 → gam7-7.3.8}/.github/workflows/build.yml +0 -0
  17. {gam7-7.3.6 → gam7-7.3.8}/.github/workflows/codeql-analysis.yml +0 -0
  18. {gam7-7.3.6 → gam7-7.3.8}/.github/workflows/get-cacerts.yml +0 -0
  19. {gam7-7.3.6 → gam7-7.3.8}/.pre-commit-config.yaml +0 -0
  20. {gam7-7.3.6 → gam7-7.3.8}/LICENSE +0 -0
  21. {gam7-7.3.6 → gam7-7.3.8}/README.md +0 -0
  22. {gam7-7.3.6 → gam7-7.3.8}/src/.gitignore +0 -0
  23. {gam7-7.3.6 → gam7-7.3.8}/src/LICENSE +0 -0
  24. {gam7-7.3.6 → gam7-7.3.8}/src/cacerts.pem +0 -0
  25. {gam7-7.3.6 → gam7-7.3.8}/src/callgam.py +0 -0
  26. {gam7-7.3.6 → gam7-7.3.8}/src/gam/__main__.py +0 -0
  27. {gam7-7.3.6 → gam7-7.3.8}/src/gam/atom/__init__.py +0 -0
  28. {gam7-7.3.6 → gam7-7.3.8}/src/gam/atom/auth.py +0 -0
  29. {gam7-7.3.6 → gam7-7.3.8}/src/gam/atom/client.py +0 -0
  30. {gam7-7.3.6 → gam7-7.3.8}/src/gam/atom/core.py +0 -0
  31. {gam7-7.3.6 → gam7-7.3.8}/src/gam/atom/data.py +0 -0
  32. {gam7-7.3.6 → gam7-7.3.8}/src/gam/atom/http.py +0 -0
  33. {gam7-7.3.6 → gam7-7.3.8}/src/gam/atom/http_core.py +0 -0
  34. {gam7-7.3.6 → gam7-7.3.8}/src/gam/atom/http_interface.py +0 -0
  35. {gam7-7.3.6 → gam7-7.3.8}/src/gam/atom/mock_http.py +0 -0
  36. {gam7-7.3.6 → gam7-7.3.8}/src/gam/atom/mock_http_core.py +0 -0
  37. {gam7-7.3.6 → gam7-7.3.8}/src/gam/atom/mock_service.py +0 -0
  38. {gam7-7.3.6 → gam7-7.3.8}/src/gam/atom/service.py +0 -0
  39. {gam7-7.3.6 → gam7-7.3.8}/src/gam/atom/token_store.py +0 -0
  40. {gam7-7.3.6 → gam7-7.3.8}/src/gam/atom/url.py +0 -0
  41. {gam7-7.3.6 → gam7-7.3.8}/src/gam/cacerts.pem +0 -0
  42. {gam7-7.3.6 → gam7-7.3.8}/src/gam/cbcm-v1.1beta1.json +0 -0
  43. {gam7-7.3.6 → gam7-7.3.8}/src/gam/contactdelegation-v1.json +0 -0
  44. {gam7-7.3.6 → gam7-7.3.8}/src/gam/datastudio-v1.json +0 -0
  45. {gam7-7.3.6 → gam7-7.3.8}/src/gam/gamlib/__init__.py +0 -0
  46. {gam7-7.3.6 → gam7-7.3.8}/src/gam/gamlib/glaction.py +0 -0
  47. {gam7-7.3.6 → gam7-7.3.8}/src/gam/gamlib/glapi.py +0 -0
  48. {gam7-7.3.6 → gam7-7.3.8}/src/gam/gamlib/glcfg.py +0 -0
  49. {gam7-7.3.6 → gam7-7.3.8}/src/gam/gamlib/glclargs.py +1 -1
  50. {gam7-7.3.6 → gam7-7.3.8}/src/gam/gamlib/glentity.py +0 -0
  51. {gam7-7.3.6 → gam7-7.3.8}/src/gam/gamlib/glgapi.py +0 -0
  52. {gam7-7.3.6 → gam7-7.3.8}/src/gam/gamlib/glgdata.py +0 -0
  53. {gam7-7.3.6 → gam7-7.3.8}/src/gam/gamlib/glglobals.py +0 -0
  54. {gam7-7.3.6 → gam7-7.3.8}/src/gam/gamlib/glindent.py +0 -0
  55. {gam7-7.3.6 → gam7-7.3.8}/src/gam/gamlib/glmsgs.py +0 -0
  56. {gam7-7.3.6 → gam7-7.3.8}/src/gam/gamlib/glskus.py +0 -0
  57. {gam7-7.3.6 → gam7-7.3.8}/src/gam/gamlib/gluprop.py +0 -0
  58. {gam7-7.3.6 → gam7-7.3.8}/src/gam/gamlib/glverlibs.py +0 -0
  59. {gam7-7.3.6 → gam7-7.3.8}/src/gam/gamlib/yubikey.py +0 -0
  60. {gam7-7.3.6 → gam7-7.3.8}/src/gam/gdata/__init__.py +0 -0
  61. {gam7-7.3.6 → gam7-7.3.8}/src/gam/gdata/alt/__init__.py +0 -0
  62. {gam7-7.3.6 → gam7-7.3.8}/src/gam/gdata/alt/app_engine.py +0 -0
  63. {gam7-7.3.6 → gam7-7.3.8}/src/gam/gdata/alt/appengine.py +0 -0
  64. {gam7-7.3.6 → gam7-7.3.8}/src/gam/gdata/apps/__init__.py +0 -0
  65. {gam7-7.3.6 → gam7-7.3.8}/src/gam/gdata/apps/audit/__init__.py +0 -0
  66. {gam7-7.3.6 → gam7-7.3.8}/src/gam/gdata/apps/audit/service.py +0 -0
  67. {gam7-7.3.6 → gam7-7.3.8}/src/gam/gdata/apps/contacts/__init__.py +0 -0
  68. {gam7-7.3.6 → gam7-7.3.8}/src/gam/gdata/apps/contacts/service.py +0 -0
  69. {gam7-7.3.6 → gam7-7.3.8}/src/gam/gdata/apps/service.py +0 -0
  70. {gam7-7.3.6 → gam7-7.3.8}/src/gam/gdata/apps/sites/__init__.py +0 -0
  71. {gam7-7.3.6 → gam7-7.3.8}/src/gam/gdata/apps/sites/service.py +0 -0
  72. {gam7-7.3.6 → gam7-7.3.8}/src/gam/gdata/service.py +0 -0
  73. {gam7-7.3.6 → gam7-7.3.8}/src/gam/gdata/urlfetch.py +0 -0
  74. {gam7-7.3.6 → gam7-7.3.8}/src/gam/googleapiclient/__init__.py +0 -0
  75. {gam7-7.3.6 → gam7-7.3.8}/src/gam/googleapiclient/_auth.py +0 -0
  76. {gam7-7.3.6 → gam7-7.3.8}/src/gam/googleapiclient/_helpers.py +0 -0
  77. {gam7-7.3.6 → gam7-7.3.8}/src/gam/googleapiclient/channel.py +0 -0
  78. {gam7-7.3.6 → gam7-7.3.8}/src/gam/googleapiclient/discovery.py +0 -0
  79. {gam7-7.3.6 → gam7-7.3.8}/src/gam/googleapiclient/discovery_cache/__init__.py +0 -0
  80. {gam7-7.3.6 → gam7-7.3.8}/src/gam/googleapiclient/discovery_cache/appengine_memcache.py +0 -0
  81. {gam7-7.3.6 → gam7-7.3.8}/src/gam/googleapiclient/discovery_cache/base.py +0 -0
  82. {gam7-7.3.6 → gam7-7.3.8}/src/gam/googleapiclient/discovery_cache/file_cache.py +0 -0
  83. {gam7-7.3.6 → gam7-7.3.8}/src/gam/googleapiclient/errors.py +0 -0
  84. {gam7-7.3.6 → gam7-7.3.8}/src/gam/googleapiclient/http.py +0 -0
  85. {gam7-7.3.6 → gam7-7.3.8}/src/gam/googleapiclient/mimeparse.py +0 -0
  86. {gam7-7.3.6 → gam7-7.3.8}/src/gam/googleapiclient/model.py +0 -0
  87. {gam7-7.3.6 → gam7-7.3.8}/src/gam/googleapiclient/schema.py +0 -0
  88. {gam7-7.3.6 → gam7-7.3.8}/src/gam/googleapiclient/version.py +0 -0
  89. {gam7-7.3.6 → gam7-7.3.8}/src/gam/iso8601/__init__.py +0 -0
  90. {gam7-7.3.6 → gam7-7.3.8}/src/gam/iso8601/iso8601.py +0 -0
  91. {gam7-7.3.6 → gam7-7.3.8}/src/gam/serviceaccountlookup-v1.json +0 -0
  92. {gam7-7.3.6 → gam7-7.3.8}/src/gam/six.py +0 -0
  93. {gam7-7.3.6 → gam7-7.3.8}/src/gam-install.sh +0 -0
  94. {gam7-7.3.6 → gam7-7.3.8}/src/gam-setup.bat +0 -0
  95. {gam7-7.3.6 → gam7-7.3.8}/src/gam.exe.manifest +0 -0
  96. {gam7-7.3.6 → gam7-7.3.8}/src/gam.py +0 -0
  97. {gam7-7.3.6 → gam7-7.3.8}/src/gam.spec +0 -0
  98. {gam7-7.3.6 → gam7-7.3.8}/src/gam.wxs +0 -0
  99. {gam7-7.3.6 → gam7-7.3.8}/src/license.rtf +0 -0
  100. {gam7-7.3.6 → gam7-7.3.8}/src/project-apis.txt +0 -0
  101. {gam7-7.3.6 → gam7-7.3.8}/src/requirements-dev.txt +0 -0
  102. {gam7-7.3.6 → gam7-7.3.8}/src/requirements.txt +0 -0
  103. {gam7-7.3.6 → gam7-7.3.8}/src/setup.cfg +0 -0
  104. {gam7-7.3.6 → gam7-7.3.8}/src/setup.py +0 -0
  105. {gam7-7.3.6 → gam7-7.3.8}/src/tools/a_atleast_b.py +0 -0
  106. {gam7-7.3.6 → gam7-7.3.8}/src/tools/gen-wix-xml-filelist.py +0 -0
  107. {gam7-7.3.6 → gam7-7.3.8}/src/tools/mkGamRef.py +0 -0
  108. {gam7-7.3.6 → gam7-7.3.8}/src/tools/openssl.props +0 -0
  109. {gam7-7.3.6 → gam7-7.3.8}/src/version_info.txt.in +0 -0
@@ -3,6 +3,7 @@ on:
3
3
  push:
4
4
  tags:
5
5
  - 'v[0-9]+.[0-9]+.[0-9]+'
6
+ workflow_dispatch:
6
7
 
7
8
  jobs:
8
9
  pypi:
@@ -1,14 +1,22 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gam7
3
- Version: 7.3.6
3
+ Version: 7.3.8
4
4
  Summary: CLI tool to manage Google Workspace
5
5
  Project-URL: Homepage, https://github.com/GAM-team/GAM
6
6
  Project-URL: Issues, https://github.com/GAM-team/GAM/issues
7
+ Project-URL: Discussion, https://groups.google.com/group/google-apps-manager
8
+ Project-URL: Chat, https://git.io/gam-chat
7
9
  Author-email: Jay Lee <jay0lee@gmail.com>, Ross Scroggs <Ross.Scroggs@gmail.com>
8
10
  License: Apache License (2.0)
9
11
  License-File: LICENSE
10
12
  Classifier: Operating System :: OS Independent
11
13
  Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3 :: Only
15
+ Classifier: Programming Language :: Python :: 3.9
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
12
20
  Requires-Python: >=3.9
13
21
  Requires-Dist: chardet
14
22
  Requires-Dist: cryptography
@@ -23,7 +31,8 @@ Requires-Dist: lxml
23
31
  Requires-Dist: passlib>=1.7.2
24
32
  Requires-Dist: pathvalidate
25
33
  Requires-Dist: python-dateutil
26
- Requires-Dist: yubikey-manager[yubikey]>=5.0
34
+ Provides-Extra: yubikey
35
+ Requires-Dist: yubikey-manager>=5.0; extra == 'yubikey'
27
36
  Description-Content-Type: text/markdown
28
37
 
29
38
  GAM is a command line tool for Google Workspace admins to manage domain and user settings quickly and easily.
@@ -1,29 +1,54 @@
1
1
  [project]
2
2
  name = "gam7"
3
3
  dynamic = [
4
- "dependencies",
5
4
  "version",
6
5
  ]
7
6
  authors = [
8
7
  { name="Jay Lee", email="jay0lee@gmail.com" },
9
8
  { name="Ross Scroggs", email="Ross.Scroggs@gmail.com" },
10
9
  ]
10
+ dependencies = [
11
+ "chardet",
12
+ "cryptography",
13
+ "distro; sys_platform=='linux'",
14
+ "filelock",
15
+ "google-api-python-client>=2.1",
16
+ "google-auth-httplib2",
17
+ "google-auth-oauthlib>=0.4.1",
18
+ "google-auth>=2.3.2",
19
+ "httplib2>=0.17.0",
20
+ "lxml",
21
+ "passlib>=1.7.2",
22
+ "pathvalidate",
23
+ "python-dateutil",
24
+ ]
11
25
  description = "CLI tool to manage Google Workspace"
12
26
  readme = "README.md"
13
27
  requires-python = ">=3.9"
14
28
  classifiers = [
15
29
  "Programming Language :: Python :: 3",
30
+ "Programming Language :: Python :: 3 :: Only",
31
+ "Programming Language :: Python :: 3.9",
32
+ "Programming Language :: Python :: 3.10",
33
+ "Programming Language :: Python :: 3.11",
34
+ "Programming Language :: Python :: 3.12",
35
+ "Programming Language :: Python :: 3.13",
16
36
  "Operating System :: OS Independent",
17
37
  ]
18
38
  license = {text = "Apache License (2.0)"}
19
39
  license-files = ["LICEN[CS]E*"]
20
40
 
41
+ [project.optional-dependencies]
42
+ yubikey = ["yubikey-manager>=5.0"]
43
+
21
44
  [project.scripts]
22
45
  gam = "gam.__main__:main"
23
46
 
24
47
  [project.urls]
25
48
  Homepage = "https://github.com/GAM-team/GAM"
26
49
  Issues = "https://github.com/GAM-team/GAM/issues"
50
+ Discussion = "https://groups.google.com/group/google-apps-manager"
51
+ Chat = "https://git.io/gam-chat"
27
52
 
28
53
  [tool.hatch.version]
29
54
  path = "src/gam/__init__.py"
@@ -31,12 +56,8 @@ path = "src/gam/__init__.py"
31
56
  [tool.hatch.build.targets.wheel]
32
57
  packages = ["src/gam"]
33
58
 
34
- [tool.hatch.metadata.hooks.requirements_txt]
35
- files = ["src/requirements.txt"]
36
-
37
59
  [build-system]
38
60
  requires = [
39
61
  "hatchling",
40
- "hatch-requirements_txt",
41
62
  ]
42
63
  build-backend = "hatchling.build"
@@ -2090,19 +2090,25 @@ gam move browsers ou|org|orgunit <OrgUnitPath>
2090
2090
  [batchsize <Integer>]
2091
2091
 
2092
2092
  gam info browser <DeviceID>
2093
- [basic|full|annotated] <BrowserFieldName>* [fields <BrowserFieldNameList>]
2093
+ (basic|full|annotated |
2094
+ (<BrowserFieldName>* [fields <BrowserFieldNameList>]) |
2095
+ (rawfields "<BrowserFieldNameList>"))
2094
2096
  [formatjson]
2095
2097
  gam show browsers
2096
2098
  ([ou|org|orgunit|browserou <OrgUnitPath>] [(query <QueryBrowser>)|(queries <QueryBrowserList>))|(select <BrowserEntity>))
2097
2099
  [querytime<String> <Time>]
2098
2100
  [orderby <BrowserOrderByFieldName> [ascending|descending]]
2099
- [basic|full|allfields|annotated] <BrowserFieldName>* [fields <BrowserFieldNameList>] [rawfields <BrowserFieldsString>]
2101
+ (basic|full|annotated |
2102
+ (<BrowserFieldName>* [fields <BrowserFieldNameList>]) |
2103
+ (rawfields "<BrowserFieldNameList>"))
2100
2104
  [formatjson]
2101
2105
  gam print browsers [todrive <ToDriveAttribute>*]
2102
2106
  ([ou|org|orgunit|browserou <OrgUnitPath>] [(query <QueryBrowser>)|(queries <QueryBrowserList>))|(select <BrowserEntity>))
2103
2107
  [querytime<String> <Time>]
2104
2108
  [orderby <BrowserOrderByFieldName> [ascending|descending]]
2105
- [basic|full|allfields|annotated] <BrowserFieldName>* [fields <BrowserFieldNameList>] [rawfields <BrowserFieldsString>]
2109
+ (basic|full|annotated |
2110
+ (<BrowserFieldName>* [fields <BrowserFieldNameList>]) |
2111
+ (rawfields "<BrowserFieldNameList>"))
2106
2112
  [sortheaders]
2107
2113
  [formatjson [quotechar <Character>]]
2108
2114
 
@@ -5264,7 +5270,7 @@ gam print vaultcounts [todrive <ToDriveAttributes>*]
5264
5270
  gam print vaultcounts [todrive <ToDriveAttributes>*]
5265
5271
  matter <MatterItem> operation <String> [wait <Integer>]
5266
5272
 
5267
- gam create vaultexport|export matter <MatterItem> [name <String>] corpus calendar|drive|mail|groups|hangouts_chat|voice
5273
+ gam create vaultexport|export matter <MatterItem> [name <String>] corpus calendar|drive|gemini|groups|hangouts_chat|mail|voice
5268
5274
  (accounts <EmailAddressEntity>) | (orgunit|org|ou <OrgUnitPath>) | everyone
5269
5275
  (shareddrives|teamdrives <SharedDriveIDList>) | (rooms <RoomList>) | (sitesurl <URLList>)
5270
5276
  [scope all_data|held_data|unprocessed_data]
@@ -5272,10 +5278,12 @@ gam create vaultexport|export matter <MatterItem> [name <String>] corpus calenda
5272
5278
  [locationquery <StringList>] [peoplequery <StringList>] [minuswords <StringList>]
5273
5279
  [responsestatuses <AttendeeStatus>(,<AttendeeStatus>)*] [calendarversiondate <Date>|<Time>]
5274
5280
  [includeshareddrives <Boolean>] [driveversiondate <Date>|<Time>] [includeaccessinfo <Boolean>]
5281
+ [driveclientsideencryption any|encrypted|unencrypted]
5275
5282
  [includerooms <Boolean>]
5276
- [excludedrafts <Boolean>] [format mbox|pst]
5283
+ [excludedrafts <Boolean>] [mailclientsideencryption any|encrypted|unencrypted]
5277
5284
  [showconfidentialmodecontent <Boolean>] [usenewexport <Boolean>] [exportlinkeddrivefiles <Boolean>]
5278
5285
  [covereddata calllogs|textmessages|voicemails]
5286
+ [format ics|mbox|pst|xml]
5279
5287
  [region any|europe|us] [showdetails|returnidonly]
5280
5288
  gam delete vaultexport|export <ExportItem> matter <MatterItem>
5281
5289
  gam delete vaultexport|export <MatterItem> <ExportItem>
@@ -1,6 +1,15 @@
1
+ 7.03.07
2
+
3
+ Updated `gam create vaultexport` to include `corpus gemini`.
4
+
5
+ * See: https://workspaceupdates.googleblog.com/2025/02/google-vault-now-supports-gemini.html
6
+
1
7
  7.03.06
2
8
 
3
- gam print browsers rawfields - specify complex values for the fields argument
9
+ Added option `rawfields "<BrowserFieldNameList>"` to `gam info|print|show browsers` that allows
10
+ specification of complex field lists with selected subfields.
11
+
12
+ * See: https://github.com/GAM-team/GAM/wiki/Chrome-Browser-Cloud-Management#raw-fields
4
13
 
5
14
  7.03.05
6
15
 
@@ -11,7 +20,7 @@ Make GAM pip-installable: "pip install gam7"
11
20
  Added option `security` to `gam create cigroup` that allows creation of a security group
12
21
  in a single command.
13
22
 
14
- Updated to Python 3.13.2 where possible.
23
+ Updated to Python 3.13.2.
15
24
 
16
25
  7.03.03
17
26
 
@@ -25,7 +25,7 @@ https://github.com/GAM-team/GAM/wiki
25
25
  """
26
26
 
27
27
  __author__ = 'GAM Team <google-apps-manager@googlegroups.com>'
28
- __version__ = '7.03.06'
28
+ __version__ = '7.03.08'
29
29
  __license__ = 'Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0)'
30
30
 
31
31
  #pylint: disable=wrong-import-position
@@ -7356,6 +7356,12 @@ def addFieldToFieldsList(fieldName, fieldsChoiceMap, fieldsList):
7356
7356
  def _getFieldsList():
7357
7357
  return getString(Cmd.OB_FIELD_NAME_LIST).lower().replace('_', '').replace(',', ' ').split()
7358
7358
 
7359
+ def _getRawFields(requiredField=None):
7360
+ rawFields = getString(Cmd.OB_FIELDS)
7361
+ if requiredField is None or requiredField in rawFields:
7362
+ return rawFields
7363
+ return f'{requiredField},{rawFields}'
7364
+
7359
7365
  def _addInitialField(fieldsList, initialField):
7360
7366
  if isinstance(initialField, list):
7361
7367
  fieldsList.extend(initialField)
@@ -7768,9 +7774,6 @@ def RowFilterMatch(row, titlesList, rowFilter, rowFilterModeAll, rowDropFilter,
7768
7774
  return False
7769
7775
  return True
7770
7776
 
7771
- def getFieldsRaw():
7772
- return getString(Cmd.OB_FIELDS)
7773
-
7774
7777
  # myarg is command line argument
7775
7778
  # fieldChoiceMap maps myarg to API field names
7776
7779
  #FIELD_CHOICE_MAP = {
@@ -16571,7 +16574,7 @@ def doInfoAdminRole():
16571
16574
  fieldsList.append('rolePrivileges')
16572
16575
  else:
16573
16576
  unknownArgumentExit()
16574
- fields = ','.join(set(fieldsList))
16577
+ fields = getFieldsFromFieldsList(fieldsList)
16575
16578
  try:
16576
16579
  role = callGAPI(cd.roles(), 'get',
16577
16580
  throwReasons=[GAPI.NOT_FOUND, GAPI.FORBIDDEN, GAPI.FAILED_PRECONDITION,
@@ -17708,9 +17711,9 @@ def _getOrgUnits(cd, orgUnitPath, fieldsList, listType, showParent, batchSubOrgs
17708
17711
  if 'parentOrgUnitId' not in fieldsList:
17709
17712
  localFieldsList.append('parentOrgUnitId')
17710
17713
  deleteParentOrgUnitId = True
17711
- fields = ','.join(set(localFieldsList))
17714
+ fields = getFieldsFromFieldsList(localFieldsList)
17712
17715
  else:
17713
- fields = ','.join(set(fieldsList))
17716
+ fields = getFieldsFromFieldsList(fieldsList)
17714
17717
  listfields = f'organizationUnits({fields})'
17715
17718
  if listType == 'all' and orgUnitPath == '/':
17716
17719
  printGettingAllAccountEntities(Ent.ORGANIZATIONAL_UNIT)
@@ -22172,8 +22175,7 @@ def printShowUserPeopleContacts(users):
22172
22175
  if not fieldsList:
22173
22176
  ofields = _getPersonFields(PEOPLE_OTHER_CONTACTS_FIELDS_CHOICE_MAP, PEOPLE_CONTACTS_DEFAULT_FIELDS, fieldsList, parameters)
22174
22177
  else:
22175
- fieldsList = [PEOPLE_OTHER_CONTACTS_FIELDS_CHOICE_MAP[field.lower()] for field in fieldsList if field.lower() in PEOPLE_OTHER_CONTACTS_FIELDS_CHOICE_MAP]
22176
- ofields = ','.join(set(fieldsList))
22178
+ ofields = getFieldsFromFieldsList([PEOPLE_OTHER_CONTACTS_FIELDS_CHOICE_MAP[field.lower()] for field in fieldsList if field.lower() in PEOPLE_OTHER_CONTACTS_FIELDS_CHOICE_MAP])
22177
22179
  i, count, users = getEntityArgument(users)
22178
22180
  for user in users:
22179
22181
  i += 1
@@ -24787,7 +24789,7 @@ def doPrintCrOSActivity(entityList=None):
24787
24789
  else:
24788
24790
  sortRows = True
24789
24791
  jcount = len(entityList)
24790
- fields = ','.join(set(fieldsList))
24792
+ fields = getFieldsFromFieldsList(fieldsList)
24791
24793
  svcargs = dict([('customerId', GC.Values[GC.CUSTOMER_ID]), ('deviceId', None), ('projection', projection), ('fields', fields)]+GM.Globals[GM.EXTRA_ARGS_LIST])
24792
24794
  method = getattr(cd.chromeosdevices(), 'get')
24793
24795
  dbatch = cd.new_batch_http_request(callback=_callbackPrintCrOS)
@@ -25077,7 +25079,7 @@ def _showBrowser(browser, FJQC, i=0, count=0):
25077
25079
  return
25078
25080
  printEntity([Ent.CHROME_BROWSER, browser['deviceId']], i, count)
25079
25081
  Ind.Increment()
25080
- showJSON(None, browser, timeObjects=BROWSER_TIME_OBJECTS)
25082
+ showJSON(None, browser, timeObjects=BROWSER_TIME_OBJECTS, dictObjectsKey={'machinePolicies': 'name'})
25081
25083
  Ind.Decrement()
25082
25084
 
25083
25085
  BROWSER_FIELDS_CHOICE_MAP = {
@@ -25117,11 +25119,13 @@ BROWSER_FIELDS_CHOICE_MAP = {
25117
25119
  'user': 'annotatedUser',
25118
25120
  'virtualdeviceid': 'virtualDeviceId',
25119
25121
  }
25120
- BROWSER_ANNOTATED_FIELDS_LIST = ['annotatedAssetId', 'annotatedLocation', 'annotatedNotes', 'annotatedUser']
25122
+ BROWSER_ANNOTATED_FIELDS_LIST = ['annotatedAssetId', 'annotatedLocation', 'annotatedNotes', 'annotatedUser', 'deviceId']
25121
25123
  BROWSER_FULL_ACCESS_FIELDS = {'browsers', 'lastDeviceUsers', 'lastStatusReportTime', 'machinePolicies'}
25122
25124
 
25123
25125
  # gam info browser <DeviceID>
25124
- # [basic|full|annotated] <BrowserFieldName>* [fields <BrowserFieldNameList>]
25126
+ # (basic|full|annotated |
25127
+ # (<BrowserFieldName>* [fields <BrowserFieldNameList>]) |
25128
+ # (rawfields <BrowserFieldNameList>))
25125
25129
  # [formatjson]
25126
25130
  def doInfoBrowsers():
25127
25131
  cbcm = buildGAPIObject(API.CBCM)
@@ -25129,6 +25133,7 @@ def doInfoBrowsers():
25129
25133
  deviceId = getString(Cmd.OB_DEVICE_ID)
25130
25134
  projection = 'BASIC'
25131
25135
  fieldsList = []
25136
+ rawFields = None
25132
25137
  FJQC = FormatJSONQuoteChar()
25133
25138
  while Cmd.ArgumentsRemaining():
25134
25139
  myarg = getArgument()
@@ -25140,16 +25145,21 @@ def doInfoBrowsers():
25140
25145
  fieldsList = []
25141
25146
  elif getFieldsList(myarg, BROWSER_FIELDS_CHOICE_MAP, fieldsList, initialField='deviceId'):
25142
25147
  pass
25148
+ elif myarg == 'rawfields':
25149
+ projection = 'FULL'
25150
+ rawFields = _getRawFields('deviceId')
25143
25151
  else:
25144
25152
  FJQC.GetFormatJSON(myarg)
25145
25153
  if projection == 'BASIC' and set(fieldsList).intersection(BROWSER_FULL_ACCESS_FIELDS):
25146
25154
  projection = 'FULL'
25147
- fields = ','.join(set(fieldsList))
25155
+ fields = getFieldsFromFieldsList(fieldsList) if not rawFields else rawFields
25148
25156
  try:
25149
25157
  browser = callGAPI(cbcm.chromebrowsers(), 'get',
25150
- throwReasons=[GAPI.BAD_REQUEST, GAPI.RESOURCE_NOT_FOUND, GAPI.FORBIDDEN],
25158
+ throwReasons=[GAPI.BAD_REQUEST, GAPI.RESOURCE_NOT_FOUND, GAPI.INVALID_ARGUMENT, GAPI.FORBIDDEN],
25151
25159
  customer=customerId, deviceId=deviceId, projection=projection, fields=fields)
25152
25160
  _showBrowser(browser, FJQC)
25161
+ except GAPI.invalidArgument as e:
25162
+ entityActionFailedWarning([Ent.CHROME_BROWSER, deviceId], str(e))
25153
25163
  except (GAPI.badRequest, GAPI.resourceNotFound, GAPI.forbidden):
25154
25164
  checkEntityAFDNEorAccessErrorExit(None, Ent.CHROME_BROWSER, deviceId)
25155
25165
 
@@ -25350,7 +25360,7 @@ def doInfoChromeProfile():
25350
25360
  pass
25351
25361
  else:
25352
25362
  FJQC.GetFormatJSON(myarg)
25353
- fields = ','.join(set(fieldsList))
25363
+ fields = getFieldsFromFieldsList(fieldsList)
25354
25364
  try:
25355
25365
  profile = callGAPI(cm.customers().profiles(), 'get',
25356
25366
  throwReasons=[GAPI.INVALID_ARGUMENT, GAPI.NOT_FOUND, GAPI.PERMISSION_DENIED],
@@ -25482,13 +25492,19 @@ BROWSER_ORDERBY_CHOICE_MAP = {
25482
25492
  # ([ou|org|orgunit|browserou <OrgUnitPath>] [(query <QueryBrowser)|(queries <QueryBrowserList>))|(select <BrowserEntity>))
25483
25493
  # [querytime<String> <Time>]
25484
25494
  # [orderby <BrowserOrderByFieldName> [ascending|descending]]
25485
- # [basic|full|allfields|annotated] <BrowserFieldName>* [fields <BrowserFieldNameList>]
25495
+ # (basic|full|annotated |
25496
+ # (<BrowserFieldName>* [fields <BrowserFieldNameList>]) |
25497
+ # (rawfields <BrowserFieldNameList>))
25498
+ # (<BrowserFieldName>* [fields <BrowserFieldNameList>]|(rawfields <BrowserFieldNameList>)
25486
25499
  # [formatjson]
25487
25500
  # gam print browsers [todrive <ToDriveAttribute>*]
25488
25501
  # ([ou|org|orgunit|browserou <OrgUnitPath>] [(query <QueryBrowser)|(queries <QueryBrowserList>))|(select <BrowserEntity>))
25489
25502
  # [querytime<String> <Time>]
25490
25503
  # [orderby <BrowserOrderByFieldName> [ascending|descending]]
25491
- # [basic|full|allfields|annotated] <BrowserFieldName>* [fields <BrowserFieldNameList>]
25504
+ # (basic|full|annotated |
25505
+ # (<BrowserFieldName>* [fields <BrowserFieldNameList>]) |
25506
+ # (rawfields <BrowserFieldNameList>))
25507
+ # (<BrowserFieldName>* [fields <BrowserFieldNameList>]|(rawfields <BrowserFieldNameList>)
25492
25508
  # [sortheaders] [formatjson [quotechar <Character>]]
25493
25509
  def doPrintShowBrowsers():
25494
25510
  def _printBrowser(browser):
@@ -25505,7 +25521,7 @@ def doPrintShowBrowsers():
25505
25521
  csvPF = CSVPrintFile(['deviceId']) if Act.csvFormat() else None
25506
25522
  FJQC = FormatJSONQuoteChar(csvPF)
25507
25523
  fieldsList = []
25508
- fields = None
25524
+ rawFields = None
25509
25525
  projection = 'BASIC'
25510
25526
  orderBy = 'id'
25511
25527
  sortOrder = 'ASCENDING'
@@ -25542,29 +25558,27 @@ def doPrintShowBrowsers():
25542
25558
  fieldsList = []
25543
25559
  elif myarg == 'sortheaders':
25544
25560
  sortHeaders = True
25545
- elif myarg == 'rawfields':
25546
- projection = 'FULL'
25547
- fields = getFieldsRaw()
25548
25561
  elif getFieldsList(myarg, BROWSER_FIELDS_CHOICE_MAP, fieldsList, initialField='deviceId'):
25549
25562
  pass
25563
+ elif myarg == 'rawfields':
25564
+ projection = 'FULL'
25565
+ rawFields = _getRawFields('deviceId')
25550
25566
  else:
25551
25567
  FJQC.GetFormatJSONQuoteChar(myarg, True)
25552
25568
  if projection == 'BASIC' and set(fieldsList).intersection(BROWSER_FULL_ACCESS_FIELDS):
25553
25569
  projection = 'FULL'
25554
- if not fields:
25555
- fields = getItemFieldsFromFieldsList('browsers', fieldsList)
25556
- print(f'fields: {fields}')
25557
25570
  if FJQC.formatJSON:
25558
25571
  sortHeaders = False
25559
25572
  substituteQueryTimes(queries, queryTimes)
25560
25573
  if entityList is None:
25574
+ fields = getItemFieldsFromFieldsList('browsers', fieldsList) if not rawFields else f'nextPageToken,browsers({rawFields})'
25561
25575
  for query in queries:
25562
25576
  printGettingAllAccountEntities(Ent.CHROME_BROWSER, query)
25563
25577
  pageMessage = getPageMessage()
25564
25578
  try:
25565
25579
  feed = yieldGAPIpages(cbcm.chromebrowsers(), 'list', 'browsers',
25566
25580
  pageMessage=pageMessage, messageAttribute='deviceId',
25567
- throwReasons=[GAPI.INVALID_INPUT, GAPI.BAD_REQUEST, GAPI.INVALID_ORGUNIT, GAPI.FORBIDDEN],
25581
+ throwReasons=[GAPI.INVALID_INPUT, GAPI.BAD_REQUEST, GAPI.INVALID_ARGUMENT, GAPI.INVALID_ORGUNIT, GAPI.FORBIDDEN],
25568
25582
  retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
25569
25583
  customer=customerId, orgUnitPath=orgUnitPath, query=query, projection=projection,
25570
25584
  orderBy=orderBy, sortOrder=sortOrder, fields=fields)
@@ -25588,7 +25602,7 @@ def doPrintShowBrowsers():
25588
25602
  else:
25589
25603
  entityActionFailedWarning([Ent.CHROME_BROWSER, None], str(e))
25590
25604
  return
25591
- except (GAPI.invalidOrgunit, GAPI.forbidden) as e:
25605
+ except (GAPI.invalidArgument, GAPI.invalidOrgunit, GAPI.forbidden) as e:
25592
25606
  entityActionFailedWarning([Ent.CHROME_BROWSER, None], str(e))
25593
25607
  return
25594
25608
  except (GAPI.badRequest, GAPI.resourceNotFound):
@@ -25596,15 +25610,17 @@ def doPrintShowBrowsers():
25596
25610
  else:
25597
25611
  sortRows = True
25598
25612
  jcount = len(entityList)
25599
- fields = getFieldsFromFieldsList(fieldsList)
25613
+ fields = getFieldsFromFieldsList(fieldsList) if not rawFields else rawFields
25600
25614
  j = 0
25601
25615
  for deviceId in entityList:
25602
25616
  j += 1
25603
25617
  try:
25604
25618
  browser = callGAPI(cbcm.chromebrowsers(), 'get',
25605
- throwReasons=[GAPI.BAD_REQUEST, GAPI.RESOURCE_NOT_FOUND, GAPI.FORBIDDEN],
25619
+ throwReasons=[GAPI.BAD_REQUEST, GAPI.RESOURCE_NOT_FOUND, GAPI.INVALID_ARGUMENT, GAPI.FORBIDDEN],
25606
25620
  customer=customerId, deviceId=deviceId, projection=projection, fields=fields)
25607
25621
  _printBrowser(browser)
25622
+ except GAPI.invalidArgument as e:
25623
+ entityActionFailedWarning([Ent.CHROME_BROWSER, deviceId], str(e))
25608
25624
  except (GAPI.badRequest, GAPI.resourceNotFound, GAPI.forbidden):
25609
25625
  checkEntityAFDNEorAccessErrorExit(None, Ent.CHROME_BROWSER, deviceId)
25610
25626
  if csvPF:
@@ -40439,9 +40455,10 @@ VAULT_SEARCH_METHODS_MAP = {
40439
40455
  VAULT_CORPUS_ARGUMENT_MAP = {
40440
40456
  'calendar': 'CALENDAR',
40441
40457
  'drive': 'DRIVE',
40442
- 'mail': 'MAIL',
40458
+ 'gemini': 'GEMINI',
40443
40459
  'groups': 'GROUPS',
40444
40460
  'hangoutschat': 'HANGOUTS_CHAT',
40461
+ 'mail': 'MAIL',
40445
40462
  'voice': 'VOICE',
40446
40463
  }
40447
40464
  VAULT_COUNTS_CORPUS_ARGUMENT_MAP = {
@@ -40468,15 +40485,22 @@ VAULT_EXPORT_FORMAT_MAP = {
40468
40485
  'ics': 'ICS',
40469
40486
  'mbox': 'MBOX',
40470
40487
  'pst': 'PST',
40488
+ 'xml': 'XML',
40471
40489
  }
40472
40490
  VAULT_CORPUS_EXPORT_FORMATS = {
40473
40491
  'CALENDAR': ['ICS', 'PST'],
40474
40492
  'DRIVE': [],
40493
+ 'GEMINI': ['XML'],
40475
40494
  'GROUPS': ['MBOX', 'PST'],
40476
40495
  'HANGOUTS_CHAT': ['MBOX', 'PST'],
40477
40496
  'MAIL': ['MBOX', 'PST'],
40478
40497
  'VOICE' : ['MBOX', 'PST'],
40479
40498
  }
40499
+ VAULT_CSE_OPTION_MAP = {
40500
+ 'any': 'CLIENT_SIDE_ENCRYPTED_OPTION_ANY',
40501
+ 'encrypted': 'CLIENT_SIDE_ENCRYPTED_OPTION_ENCRYPTED',
40502
+ 'unencrypted': 'CLIENT_SIDE_ENCRYPTED_OPTION_UNENCRYPTED',
40503
+ }
40480
40504
  VAULT_EXPORT_REGION_MAP = {
40481
40505
  'any': 'ANY',
40482
40506
  'europe': 'EUROPE',
@@ -40485,16 +40509,18 @@ VAULT_EXPORT_REGION_MAP = {
40485
40509
  VAULT_CORPUS_OPTIONS_MAP = {
40486
40510
  'CALENDAR': 'calendarOptions',
40487
40511
  'DRIVE': 'driveOptions',
40488
- 'MAIL': 'mailOptions',
40512
+ 'GEMINI': 'geminiOptions',
40489
40513
  'GROUPS': 'groupsOptions',
40490
40514
  'HANGOUTS_CHAT': 'hangoutsChatOptions',
40515
+ 'MAIL': 'mailOptions',
40491
40516
  'VOICE': 'voiceOptions',
40492
40517
  }
40493
40518
  VAULT_CORPUS_QUERY_MAP = {
40494
40519
  'CALENDAR': None,
40495
40520
  'DRIVE': 'driveQuery',
40496
- 'MAIL': 'mailQuery',
40521
+ 'GEMINI': None,
40497
40522
  'GROUPS': 'groupsQuery',
40523
+ 'MAIL': 'mailQuery',
40498
40524
  'HANGOUTS_CHAT': 'hangoutsChatQuery',
40499
40525
  'VOICE': 'voiceQuery',
40500
40526
  }
@@ -40503,11 +40529,11 @@ VAULT_QUERY_ARGS = [
40503
40529
  # calendar
40504
40530
  'locationquery', 'peoplequery', 'minuswords', 'responsestatuses', 'caldendarversiondate',
40505
40531
  # drive
40506
- 'driveversiondate', 'includeshareddrives', 'includeteamdrives',
40532
+ 'driveclientsideencryption', 'driveversiondate', 'includeshareddrives', 'includeteamdrives',
40507
40533
  # hangoutsChat
40508
40534
  'includerooms',
40509
40535
  # mail
40510
- 'excludedrafts',
40536
+ 'mailclientsideencryption', 'excludedrafts',
40511
40537
  # voice
40512
40538
  'covereddata',
40513
40539
  ] + list(VAULT_SEARCH_METHODS_MAP.keys())
@@ -40564,12 +40590,16 @@ def _buildVaultQuery(myarg, query, corpusArgumentMap):
40564
40590
  query.setdefault('driveOptions', {})['versionDate'] = getTimeOrDeltaFromNow()
40565
40591
  elif myarg in {'includeshareddrives', 'includeteamdrives'}:
40566
40592
  query.setdefault('driveOptions', {})['includeSharedDrives'] = getBoolean()
40593
+ elif myarg == 'driveclientsideencryption':
40594
+ query.setdefault('driveOptions', {})['clientSideEncryptedOption'] = getChoice(VAULT_CSE_OPTION_MAP, mapChoice=True)
40567
40595
  # hangoutsChat
40568
40596
  elif myarg == 'includerooms':
40569
40597
  query['hangoutsChatOptions'] = {'includeRooms': getBoolean()}
40570
40598
  # mail
40571
40599
  elif myarg == 'excludedrafts':
40572
40600
  query['mailOptions'] = {'excludeDrafts': getBoolean()}
40601
+ elif myarg == 'mailclientsideencryption':
40602
+ query.setdefault('mailOptions', {})['clientSideEncryptedOption'] = getChoice(VAULT_CSE_OPTION_MAP, mapChoice=True)
40573
40603
  # voice
40574
40604
  elif myarg == 'covereddata':
40575
40605
  query['voiceOptions'] = {'coveredData': getChoice(VAULT_VOICE_COVERED_DATA_MAP, mapChoice=True)}
@@ -40584,7 +40614,7 @@ def _validateVaultQuery(body, corpusArgumentMap):
40584
40614
  if body['query']['corpus'] != corpus:
40585
40615
  body['exportOptions'].pop(options, None)
40586
40616
 
40587
- # gam create vaultexport|export matter <MatterItem> [name <String>] corpus calendar|drive|mail|groups|hangouts_chat|voice
40617
+ # gam create vaultexport|export matter <MatterItem> [name <String>] corpus calendar|drive|gemini|groups|hangouts_chat|mail|voice
40588
40618
  # (accounts <EmailAddressEntity>) | (orgunit|org|ou <OrgUnitPath>) | everyone
40589
40619
  # (shareddrives|teamdrives <TeamDriveIDList>) | (rooms <RoomList>) | (sitesurl <URLList>)
40590
40620
  # [scope <all_data|held_data|unprocessed_data>]
@@ -40592,10 +40622,12 @@ def _validateVaultQuery(body, corpusArgumentMap):
40592
40622
  # [locationquery <StringList>] [peoplequery <StringList>] [minuswords <StringList>]
40593
40623
  # [responsestatuses <AttendeeStatus>(,<AttendeeStatus>)*] [calendarversiondate <Date>|<Time>]
40594
40624
  # [includeshareddrives <Boolean>] [driveversiondate <Date>|<Time>] [includeaccessinfo <Boolean>]
40625
+ # [driveclientsideencryption any|encrypted|unencrypted]
40595
40626
  # [includerooms <Boolean>]
40596
- # [excludedrafts <Boolean>] [format mbox|pst]
40627
+ # [excludedrafts <Boolean>] [mailclientsideencryption any|encrypted|unencrypted]
40597
40628
  # [showconfidentialmodecontent <Boolean>] [usenewexport <Boolean>] [exportlinkeddrivefiles <Boolean>]
40598
40629
  # [covereddata calllogs|textmessages|voicemails]
40630
+ # [format ics|mbox|pst|xml]
40599
40631
  # [region any|europe|us] [showdetails|returnidonly]
40600
40632
  def doCreateVaultExport():
40601
40633
  v = buildGAPIObject(API.VAULT)
@@ -48255,7 +48287,7 @@ def doPrintCourseTopics():
48255
48287
  jcount = len(courseTopicIds)
48256
48288
  if jcount == 0:
48257
48289
  continue
48258
- fields = f'{",".join(set(fieldsList))}'
48290
+ fields = getFieldsFromFieldsList(fieldsList)
48259
48291
  j = 0
48260
48292
  for courseTopicId in courseTopicIds:
48261
48293
  j += 1
@@ -48490,7 +48522,7 @@ def doPrintCourseWM(entityIDType, entityStateType):
48490
48522
  jcount = len(courseWMIds)
48491
48523
  if jcount == 0:
48492
48524
  continue
48493
- fields = f'{",".join(set(fieldsList))}' if fieldsList else None
48525
+ fields = getFieldsFromFieldsList(fieldsList)
48494
48526
  j = 0
48495
48527
  for courseWMId in courseWMIds:
48496
48528
  j += 1
@@ -65510,7 +65542,7 @@ def infoSharedDrive(users, useDomainAdminAccess=False):
65510
65542
  guiRoles = getBoolean()
65511
65543
  else:
65512
65544
  FJQC.GetFormatJSON(myarg)
65513
- fields = ','.join(set(fieldsList)) if fieldsList else '*'
65545
+ fields = getFieldsFromFieldsList(fieldsList) if fieldsList else '*'
65514
65546
  i, count, users = getEntityArgument(users)
65515
65547
  for user in users:
65516
65548
  i += 1
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -922,9 +922,9 @@ class GamCLArgs():
922
922
  OB_EVENT_ID_ENTITY = 'EventIDEntity'
923
923
  OB_EVENT_NAME_LIST = "EventNameList"
924
924
  OB_EXPORT_ITEM = 'ExportItem'
925
- OB_FIELDS = 'Fields'
926
925
  OB_FIELD_NAME = 'FieldName'
927
926
  OB_FIELD_NAME_LIST = "FieldNameList"
927
+ OB_FIELDS = 'Fields'
928
928
  OB_FILE_NAME = 'FileName'
929
929
  OB_FILE_NAME_FIELD_NAME = OB_FILE_NAME+'(:'+OB_FIELD_NAME+')+'
930
930
  OB_FILE_NAME_OR_URL = 'FileName|URL'
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes