]> git.proxmox.com Git - mirror_ovs.git/blob - python/compat/uuid.py
nroff: Fix the escape of '.'.
[mirror_ovs.git] / python / compat / uuid.py
1 # This file is from Python 2.5. It has been modified by adding this
2 # license header, which is copied from the LICENSE file distributed
3 # with Python.
4 #
5 # PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
6 # --------------------------------------------
7 #
8 # 1. This LICENSE AGREEMENT is between the Python Software Foundation
9 # ("PSF"), and the Individual or Organization ("Licensee") accessing and
10 # otherwise using this software ("Python") in source or binary form and
11 # its associated documentation.
12 #
13 # 2. Subject to the terms and conditions of this License Agreement, PSF
14 # hereby grants Licensee a nonexclusive, royalty-free, world-wide
15 # license to reproduce, analyze, test, perform and/or display publicly,
16 # prepare derivative works, distribute, and otherwise use Python
17 # alone or in any derivative version, provided, however, that PSF's
18 # License Agreement and PSF's notice of copyright, i.e., "Copyright (c)
19 # 2001, 2002, 2003, 2004, 2005, 2006, 2007 Python Software Foundation;
20 # All Rights Reserved" are retained in Python alone or in any derivative
21 # version prepared by Licensee.
22 #
23 # 3. In the event Licensee prepares a derivative work that is based on
24 # or incorporates Python or any part thereof, and wants to make
25 # the derivative work available to others as provided herein, then
26 # Licensee hereby agrees to include in any such work a brief summary of
27 # the changes made to Python.
28 #
29 # 4. PSF is making Python available to Licensee on an "AS IS"
30 # basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
31 # IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND
32 # DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
33 # FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT
34 # INFRINGE ANY THIRD PARTY RIGHTS.
35 #
36 # 5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
37 # FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
38 # A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON,
39 # OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
40 #
41 # 6. This License Agreement will automatically terminate upon a material
42 # breach of its terms and conditions.
43 #
44 # 7. Nothing in this License Agreement shall be deemed to create any
45 # relationship of agency, partnership, or joint venture between PSF and
46 # Licensee. This License Agreement does not grant permission to use PSF
47 # trademarks or trade name in a trademark sense to endorse or promote
48 # products or services of Licensee, or any third party.
49 #
50 # 8. By copying, installing or otherwise using Python, Licensee
51 # agrees to be bound by the terms and conditions of this License
52 # Agreement.
53
54 r"""UUID objects (universally unique identifiers) according to RFC 4122.
55
56 This module provides immutable UUID objects (class UUID) and the functions
57 uuid1(), uuid3(), uuid4(), uuid5() for generating version 1, 3, 4, and 5
58 UUIDs as specified in RFC 4122.
59
60 If all you want is a unique ID, you should probably call uuid1() or uuid4().
61 Note that uuid1() may compromise privacy since it creates a UUID containing
62 the computer's network address. uuid4() creates a random UUID.
63
64 Typical usage:
65
66 >>> import uuid
67
68 # make a UUID based on the host ID and current time
69 >>> uuid.uuid1()
70 UUID('a8098c1a-f86e-11da-bd1a-00112444be1e')
71
72 # make a UUID using an MD5 hash of a namespace UUID and a name
73 >>> uuid.uuid3(uuid.NAMESPACE_DNS, 'python.org')
74 UUID('6fa459ea-ee8a-3ca4-894e-db77e160355e')
75
76 # make a random UUID
77 >>> uuid.uuid4()
78 UUID('16fd2706-8baf-433b-82eb-8c7fada847da')
79
80 # make a UUID using a SHA-1 hash of a namespace UUID and a name
81 >>> uuid.uuid5(uuid.NAMESPACE_DNS, 'python.org')
82 UUID('886313e1-3b8a-5372-9b90-0c9aee199e5d')
83
84 # make a UUID from a string of hex digits (braces and hyphens ignored)
85 >>> x = uuid.UUID('{00010203-0405-0607-0809-0a0b0c0d0e0f}')
86
87 # convert a UUID to a string of hex digits in standard form
88 >>> str(x)
89 '00010203-0405-0607-0809-0a0b0c0d0e0f'
90
91 # get the raw 16 bytes of the UUID
92 >>> x.bytes
93 '\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f'
94
95 # make a UUID from a 16-byte string
96 >>> uuid.UUID(bytes=x.bytes)
97 UUID('00010203-0405-0607-0809-0a0b0c0d0e0f')
98 """
99
100 __author__ = 'Ka-Ping Yee <ping@zesty.ca>'
101
102 RESERVED_NCS, RFC_4122, RESERVED_MICROSOFT, RESERVED_FUTURE = [
103 'reserved for NCS compatibility', 'specified in RFC 4122',
104 'reserved for Microsoft compatibility', 'reserved for future definition']
105
106 class UUID(object):
107 """Instances of the UUID class represent UUIDs as specified in RFC 4122.
108 UUID objects are immutable, hashable, and usable as dictionary keys.
109 Converting a UUID to a string with str() yields something in the form
110 '12345678-1234-1234-1234-123456789abc'. The UUID constructor accepts
111 five possible forms: a similar string of hexadecimal digits, or a tuple
112 of six integer fields (with 32-bit, 16-bit, 16-bit, 8-bit, 8-bit, and
113 48-bit values respectively) as an argument named 'fields', or a string
114 of 16 bytes (with all the integer fields in big-endian order) as an
115 argument named 'bytes', or a string of 16 bytes (with the first three
116 fields in little-endian order) as an argument named 'bytes_le', or a
117 single 128-bit integer as an argument named 'int'.
118
119 UUIDs have these read-only attributes:
120
121 bytes the UUID as a 16-byte string (containing the six
122 integer fields in big-endian byte order)
123
124 bytes_le the UUID as a 16-byte string (with time_low, time_mid,
125 and time_hi_version in little-endian byte order)
126
127 fields a tuple of the six integer fields of the UUID,
128 which are also available as six individual attributes
129 and two derived attributes:
130
131 time_low the first 32 bits of the UUID
132 time_mid the next 16 bits of the UUID
133 time_hi_version the next 16 bits of the UUID
134 clock_seq_hi_variant the next 8 bits of the UUID
135 clock_seq_low the next 8 bits of the UUID
136 node the last 48 bits of the UUID
137
138 time the 60-bit timestamp
139 clock_seq the 14-bit sequence number
140
141 hex the UUID as a 32-character hexadecimal string
142
143 int the UUID as a 128-bit integer
144
145 urn the UUID as a URN as specified in RFC 4122
146
147 variant the UUID variant (one of the constants RESERVED_NCS,
148 RFC_4122, RESERVED_MICROSOFT, or RESERVED_FUTURE)
149
150 version the UUID version number (1 through 5, meaningful only
151 when the variant is RFC_4122)
152 """
153
154 def __init__(self, hex=None, bytes=None, bytes_le=None, fields=None,
155 int=None, version=None):
156 r"""Create a UUID from either a string of 32 hexadecimal digits,
157 a string of 16 bytes as the 'bytes' argument, a string of 16 bytes
158 in little-endian order as the 'bytes_le' argument, a tuple of six
159 integers (32-bit time_low, 16-bit time_mid, 16-bit time_hi_version,
160 8-bit clock_seq_hi_variant, 8-bit clock_seq_low, 48-bit node) as
161 the 'fields' argument, or a single 128-bit integer as the 'int'
162 argument. When a string of hex digits is given, curly braces,
163 hyphens, and a URN prefix are all optional. For example, these
164 expressions all yield the same UUID:
165
166 UUID('{12345678-1234-5678-1234-567812345678}')
167 UUID('12345678123456781234567812345678')
168 UUID('urn:uuid:12345678-1234-5678-1234-567812345678')
169 UUID(bytes='\x12\x34\x56\x78'*4)
170 UUID(bytes_le='\x78\x56\x34\x12\x34\x12\x78\x56' +
171 '\x12\x34\x56\x78\x12\x34\x56\x78')
172 UUID(fields=(0x12345678, 0x1234, 0x5678, 0x12, 0x34, 0x567812345678))
173 UUID(int=0x12345678123456781234567812345678)
174
175 Exactly one of 'hex', 'bytes', 'bytes_le', 'fields', or 'int' must
176 be given. The 'version' argument is optional; if given, the resulting
177 UUID will have its variant and version set according to RFC 4122,
178 overriding the given 'hex', 'bytes', 'bytes_le', 'fields', or 'int'.
179 """
180
181 if [hex, bytes, bytes_le, fields, int].count(None) != 4:
182 raise TypeError('need one of hex, bytes, bytes_le, fields, or int')
183 if hex is not None:
184 hex = hex.replace('urn:', '').replace('uuid:', '')
185 hex = hex.strip('{}').replace('-', '')
186 if len(hex) != 32:
187 raise ValueError('badly formed hexadecimal UUID string')
188 int = long(hex, 16)
189 if bytes_le is not None:
190 if len(bytes_le) != 16:
191 raise ValueError('bytes_le is not a 16-char string')
192 bytes = (bytes_le[3] + bytes_le[2] + bytes_le[1] + bytes_le[0] +
193 bytes_le[5] + bytes_le[4] + bytes_le[7] + bytes_le[6] +
194 bytes_le[8:])
195 if bytes is not None:
196 if len(bytes) != 16:
197 raise ValueError('bytes is not a 16-char string')
198 int = long(('%02x'*16) % tuple(map(ord, bytes)), 16)
199 if fields is not None:
200 if len(fields) != 6:
201 raise ValueError('fields is not a 6-tuple')
202 (time_low, time_mid, time_hi_version,
203 clock_seq_hi_variant, clock_seq_low, node) = fields
204 if not 0 <= time_low < 1<<32L:
205 raise ValueError('field 1 out of range (need a 32-bit value)')
206 if not 0 <= time_mid < 1<<16L:
207 raise ValueError('field 2 out of range (need a 16-bit value)')
208 if not 0 <= time_hi_version < 1<<16L:
209 raise ValueError('field 3 out of range (need a 16-bit value)')
210 if not 0 <= clock_seq_hi_variant < 1<<8L:
211 raise ValueError('field 4 out of range (need an 8-bit value)')
212 if not 0 <= clock_seq_low < 1<<8L:
213 raise ValueError('field 5 out of range (need an 8-bit value)')
214 if not 0 <= node < 1<<48L:
215 raise ValueError('field 6 out of range (need a 48-bit value)')
216 clock_seq = (clock_seq_hi_variant << 8L) | clock_seq_low
217 int = ((time_low << 96L) | (time_mid << 80L) |
218 (time_hi_version << 64L) | (clock_seq << 48L) | node)
219 if int is not None:
220 if not 0 <= int < 1<<128L:
221 raise ValueError('int is out of range (need a 128-bit value)')
222 if version is not None:
223 if not 1 <= version <= 5:
224 raise ValueError('illegal version number')
225 # Set the variant to RFC 4122.
226 int &= ~(0xc000 << 48L)
227 int |= 0x8000 << 48L
228 # Set the version number.
229 int &= ~(0xf000 << 64L)
230 int |= version << 76L
231 self.__dict__['int'] = int
232
233 def __cmp__(self, other):
234 if isinstance(other, UUID):
235 return cmp(self.int, other.int)
236 return NotImplemented
237
238 def __hash__(self):
239 return hash(self.int)
240
241 def __int__(self):
242 return self.int
243
244 def __repr__(self):
245 return 'UUID(%r)' % str(self)
246
247 def __setattr__(self, name, value):
248 raise TypeError('UUID objects are immutable')
249
250 def __str__(self):
251 hex = '%032x' % self.int
252 return '%s-%s-%s-%s-%s' % (
253 hex[:8], hex[8:12], hex[12:16], hex[16:20], hex[20:])
254
255 def get_bytes(self):
256 bytes = ''
257 for shift in range(0, 128, 8):
258 bytes = chr((self.int >> shift) & 0xff) + bytes
259 return bytes
260
261 bytes = property(get_bytes)
262
263 def get_bytes_le(self):
264 bytes = self.bytes
265 return (bytes[3] + bytes[2] + bytes[1] + bytes[0] +
266 bytes[5] + bytes[4] + bytes[7] + bytes[6] + bytes[8:])
267
268 bytes_le = property(get_bytes_le)
269
270 def get_fields(self):
271 return (self.time_low, self.time_mid, self.time_hi_version,
272 self.clock_seq_hi_variant, self.clock_seq_low, self.node)
273
274 fields = property(get_fields)
275
276 def get_time_low(self):
277 return self.int >> 96L
278
279 time_low = property(get_time_low)
280
281 def get_time_mid(self):
282 return (self.int >> 80L) & 0xffff
283
284 time_mid = property(get_time_mid)
285
286 def get_time_hi_version(self):
287 return (self.int >> 64L) & 0xffff
288
289 time_hi_version = property(get_time_hi_version)
290
291 def get_clock_seq_hi_variant(self):
292 return (self.int >> 56L) & 0xff
293
294 clock_seq_hi_variant = property(get_clock_seq_hi_variant)
295
296 def get_clock_seq_low(self):
297 return (self.int >> 48L) & 0xff
298
299 clock_seq_low = property(get_clock_seq_low)
300
301 def get_time(self):
302 return (((self.time_hi_version & 0x0fffL) << 48L) |
303 (self.time_mid << 32L) | self.time_low)
304
305 time = property(get_time)
306
307 def get_clock_seq(self):
308 return (((self.clock_seq_hi_variant & 0x3fL) << 8L) |
309 self.clock_seq_low)
310
311 clock_seq = property(get_clock_seq)
312
313 def get_node(self):
314 return self.int & 0xffffffffffff
315
316 node = property(get_node)
317
318 def get_hex(self):
319 return '%032x' % self.int
320
321 hex = property(get_hex)
322
323 def get_urn(self):
324 return 'urn:uuid:' + str(self)
325
326 urn = property(get_urn)
327
328 def get_variant(self):
329 if not self.int & (0x8000 << 48L):
330 return RESERVED_NCS
331 elif not self.int & (0x4000 << 48L):
332 return RFC_4122
333 elif not self.int & (0x2000 << 48L):
334 return RESERVED_MICROSOFT
335 else:
336 return RESERVED_FUTURE
337
338 variant = property(get_variant)
339
340 def get_version(self):
341 # The version bits are only meaningful for RFC 4122 UUIDs.
342 if self.variant == RFC_4122:
343 return int((self.int >> 76L) & 0xf)
344
345 version = property(get_version)
346
347 def _find_mac(command, args, hw_identifiers, get_index):
348 import os
349 for dir in ['', '/sbin/', '/usr/sbin']:
350 executable = os.path.join(dir, command)
351 if not os.path.exists(executable):
352 continue
353
354 try:
355 # LC_ALL to get English output, 2>/dev/null to
356 # prevent output on stderr
357 cmd = 'LC_ALL=C %s %s 2>/dev/null' % (executable, args)
358 pipe = os.popen(cmd)
359 except IOError:
360 continue
361
362 for line in pipe:
363 words = line.lower().split()
364 for i in range(len(words)):
365 if words[i] in hw_identifiers:
366 return int(words[get_index(i)].replace(':', ''), 16)
367 return None
368
369 def _ifconfig_getnode():
370 """Get the hardware address on Unix by running ifconfig."""
371
372 # This works on Linux ('' or '-a'), Tru64 ('-av'), but not all Unixes.
373 for args in ('', '-a', '-av'):
374 mac = _find_mac('ifconfig', args, ['hwaddr', 'ether'], lambda i: i+1)
375 if mac:
376 return mac
377
378 import socket
379 ip_addr = socket.gethostbyname(socket.gethostname())
380
381 # Try getting the MAC addr from arp based on our IP address (Solaris).
382 mac = _find_mac('arp', '-an', [ip_addr], lambda i: -1)
383 if mac:
384 return mac
385
386 # This might work on HP-UX.
387 mac = _find_mac('lanscan', '-ai', ['lan0'], lambda i: 0)
388 if mac:
389 return mac
390
391 return None
392
393 def _ipconfig_getnode():
394 """Get the hardware address on Windows by running ipconfig.exe."""
395 import os, re
396 dirs = ['', r'c:\windows\system32', r'c:\winnt\system32']
397 try:
398 import ctypes
399 buffer = ctypes.create_string_buffer(300)
400 ctypes.windll.kernel32.GetSystemDirectoryA(buffer, 300)
401 dirs.insert(0, buffer.value.decode('mbcs'))
402 except:
403 pass
404 for dir in dirs:
405 try:
406 pipe = os.popen(os.path.join(dir, 'ipconfig') + ' /all')
407 except IOError:
408 continue
409 for line in pipe:
410 value = line.split(':')[-1].strip().lower()
411 if re.match('([0-9a-f][0-9a-f]-){5}[0-9a-f][0-9a-f]', value):
412 return int(value.replace('-', ''), 16)
413
414 def _netbios_getnode():
415 """Get the hardware address on Windows using NetBIOS calls.
416 See http://support.microsoft.com/kb/118623 for details."""
417 import win32wnet, netbios
418 ncb = netbios.NCB()
419 ncb.Command = netbios.NCBENUM
420 ncb.Buffer = adapters = netbios.LANA_ENUM()
421 adapters._pack()
422 if win32wnet.Netbios(ncb) != 0:
423 return
424 adapters._unpack()
425 for i in range(adapters.length):
426 ncb.Reset()
427 ncb.Command = netbios.NCBRESET
428 ncb.Lana_num = ord(adapters.lana[i])
429 if win32wnet.Netbios(ncb) != 0:
430 continue
431 ncb.Reset()
432 ncb.Command = netbios.NCBASTAT
433 ncb.Lana_num = ord(adapters.lana[i])
434 ncb.Callname = '*'.ljust(16)
435 ncb.Buffer = status = netbios.ADAPTER_STATUS()
436 if win32wnet.Netbios(ncb) != 0:
437 continue
438 status._unpack()
439 bytes = map(ord, status.adapter_address)
440 return ((bytes[0]<<40L) + (bytes[1]<<32L) + (bytes[2]<<24L) +
441 (bytes[3]<<16L) + (bytes[4]<<8L) + bytes[5])
442
443 # Thanks to Thomas Heller for ctypes and for his help with its use here.
444
445 # If ctypes is available, use it to find system routines for UUID generation.
446 _uuid_generate_random = _uuid_generate_time = _UuidCreate = None
447 try:
448 import ctypes, ctypes.util
449 _buffer = ctypes.create_string_buffer(16)
450
451 # The uuid_generate_* routines are provided by libuuid on at least
452 # Linux and FreeBSD, and provided by libc on Mac OS X.
453 for libname in ['uuid', 'c']:
454 try:
455 lib = ctypes.CDLL(ctypes.util.find_library(libname))
456 except:
457 continue
458 if hasattr(lib, 'uuid_generate_random'):
459 _uuid_generate_random = lib.uuid_generate_random
460 if hasattr(lib, 'uuid_generate_time'):
461 _uuid_generate_time = lib.uuid_generate_time
462
463 # On Windows prior to 2000, UuidCreate gives a UUID containing the
464 # hardware address. On Windows 2000 and later, UuidCreate makes a
465 # random UUID and UuidCreateSequential gives a UUID containing the
466 # hardware address. These routines are provided by the RPC runtime.
467 # NOTE: at least on Tim's WinXP Pro SP2 desktop box, while the last
468 # 6 bytes returned by UuidCreateSequential are fixed, they don't appear
469 # to bear any relationship to the MAC address of any network device
470 # on the box.
471 try:
472 lib = ctypes.windll.rpcrt4
473 except:
474 lib = None
475 _UuidCreate = getattr(lib, 'UuidCreateSequential',
476 getattr(lib, 'UuidCreate', None))
477 except:
478 pass
479
480 def _unixdll_getnode():
481 """Get the hardware address on Unix using ctypes."""
482 _uuid_generate_time(_buffer)
483 return UUID(bytes=_buffer.raw).node
484
485 def _windll_getnode():
486 """Get the hardware address on Windows using ctypes."""
487 if _UuidCreate(_buffer) == 0:
488 return UUID(bytes=_buffer.raw).node
489
490 def _random_getnode():
491 """Get a random node ID, with eighth bit set as suggested by RFC 4122."""
492 import random
493 return random.randrange(0, 1<<48L) | 0x010000000000L
494
495 _node = None
496
497 def getnode():
498 """Get the hardware address as a 48-bit positive integer.
499
500 The first time this runs, it may launch a separate program, which could
501 be quite slow. If all attempts to obtain the hardware address fail, we
502 choose a random 48-bit number with its eighth bit set to 1 as recommended
503 in RFC 4122.
504 """
505
506 global _node
507 if _node is not None:
508 return _node
509
510 import sys
511 if sys.platform == 'win32':
512 getters = [_windll_getnode, _netbios_getnode, _ipconfig_getnode]
513 else:
514 getters = [_unixdll_getnode, _ifconfig_getnode]
515
516 for getter in getters + [_random_getnode]:
517 try:
518 _node = getter()
519 except:
520 continue
521 if _node is not None:
522 return _node
523
524 _last_timestamp = None
525
526 def uuid1(node=None, clock_seq=None):
527 """Generate a UUID from a host ID, sequence number, and the current time.
528 If 'node' is not given, getnode() is used to obtain the hardware
529 address. If 'clock_seq' is given, it is used as the sequence number;
530 otherwise a random 14-bit sequence number is chosen."""
531
532 # When the system provides a version-1 UUID generator, use it (but don't
533 # use UuidCreate here because its UUIDs don't conform to RFC 4122).
534 if _uuid_generate_time and node is clock_seq is None:
535 _uuid_generate_time(_buffer)
536 return UUID(bytes=_buffer.raw)
537
538 global _last_timestamp
539 import time
540 nanoseconds = int(time.time() * 1e9)
541 # 0x01b21dd213814000 is the number of 100-ns intervals between the
542 # UUID epoch 1582-10-15 00:00:00 and the Unix epoch 1970-01-01 00:00:00.
543 timestamp = int(nanoseconds/100) + 0x01b21dd213814000L
544 if timestamp <= _last_timestamp:
545 timestamp = _last_timestamp + 1
546 _last_timestamp = timestamp
547 if clock_seq is None:
548 import random
549 clock_seq = random.randrange(1<<14L) # instead of stable storage
550 time_low = timestamp & 0xffffffffL
551 time_mid = (timestamp >> 32L) & 0xffffL
552 time_hi_version = (timestamp >> 48L) & 0x0fffL
553 clock_seq_low = clock_seq & 0xffL
554 clock_seq_hi_variant = (clock_seq >> 8L) & 0x3fL
555 if node is None:
556 node = getnode()
557 return UUID(fields=(time_low, time_mid, time_hi_version,
558 clock_seq_hi_variant, clock_seq_low, node), version=1)
559
560 def uuid3(namespace, name):
561 """Generate a UUID from the MD5 hash of a namespace UUID and a name."""
562 import md5
563 hash = md5.md5(namespace.bytes + name).digest()
564 return UUID(bytes=hash[:16], version=3)
565
566 def uuid4():
567 """Generate a random UUID."""
568
569 # When the system provides a version-4 UUID generator, use it.
570 if _uuid_generate_random:
571 _uuid_generate_random(_buffer)
572 return UUID(bytes=_buffer.raw)
573
574 # Otherwise, get randomness from urandom or the 'random' module.
575 try:
576 import os
577 return UUID(bytes=os.urandom(16), version=4)
578 except:
579 import random
580 bytes = [chr(random.randrange(256)) for i in range(16)]
581 return UUID(bytes=bytes, version=4)
582
583 def uuid5(namespace, name):
584 """Generate a UUID from the SHA-1 hash of a namespace UUID and a name."""
585 import sha
586 hash = sha.sha(namespace.bytes + name).digest()
587 return UUID(bytes=hash[:16], version=5)
588
589 # The following standard UUIDs are for use with uuid3() or uuid5().
590
591 NAMESPACE_DNS = UUID('6ba7b810-9dad-11d1-80b4-00c04fd430c8')
592 NAMESPACE_URL = UUID('6ba7b811-9dad-11d1-80b4-00c04fd430c8')
593 NAMESPACE_OID = UUID('6ba7b812-9dad-11d1-80b4-00c04fd430c8')
594 NAMESPACE_X500 = UUID('6ba7b814-9dad-11d1-80b4-00c04fd430c8')