prasb commited on
Commit
a5b25a6
·
verified ·
1 Parent(s): 40da3e8

Add files using upload-large-folder tool

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. my_container_sandbox/workspace/anaconda3/lib/python3.8/__pycache__/__future__.cpython-38.pyc +0 -0
  2. my_container_sandbox/workspace/anaconda3/lib/python3.8/__pycache__/_bootlocale.cpython-38.pyc +0 -0
  3. my_container_sandbox/workspace/anaconda3/lib/python3.8/__pycache__/_sitebuiltins.cpython-38.pyc +0 -0
  4. my_container_sandbox/workspace/anaconda3/lib/python3.8/__pycache__/_strptime.cpython-38.pyc +0 -0
  5. my_container_sandbox/workspace/anaconda3/lib/python3.8/__pycache__/_sysconfigdata_i686_conda_linux_gnu.cpython-38.pyc +0 -0
  6. my_container_sandbox/workspace/anaconda3/lib/python3.8/__pycache__/asynchat.cpython-38.pyc +0 -0
  7. my_container_sandbox/workspace/anaconda3/lib/python3.8/__pycache__/code.cpython-38.pyc +0 -0
  8. my_container_sandbox/workspace/anaconda3/lib/python3.8/__pycache__/codecs.cpython-38.pyc +0 -0
  9. my_container_sandbox/workspace/anaconda3/lib/python3.8/__pycache__/codeop.cpython-38.pyc +0 -0
  10. my_container_sandbox/workspace/anaconda3/lib/python3.8/__pycache__/compileall.cpython-38.pyc +0 -0
  11. my_container_sandbox/workspace/anaconda3/lib/python3.8/__pycache__/dis.cpython-38.pyc +0 -0
  12. my_container_sandbox/workspace/anaconda3/lib/python3.8/__pycache__/filecmp.cpython-38.pyc +0 -0
  13. my_container_sandbox/workspace/anaconda3/lib/python3.8/__pycache__/imp.cpython-38.pyc +0 -0
  14. my_container_sandbox/workspace/anaconda3/lib/python3.8/__pycache__/inspect.cpython-38.pyc +0 -0
  15. my_container_sandbox/workspace/anaconda3/lib/python3.8/__pycache__/posixpath.cpython-38.pyc +0 -0
  16. my_container_sandbox/workspace/anaconda3/lib/python3.8/__pycache__/rlcompleter.cpython-38.pyc +0 -0
  17. my_container_sandbox/workspace/anaconda3/lib/python3.8/__pycache__/runpy.cpython-38.pyc +0 -0
  18. my_container_sandbox/workspace/anaconda3/lib/python3.8/__pycache__/secrets.cpython-38.pyc +0 -0
  19. my_container_sandbox/workspace/anaconda3/lib/python3.8/__pycache__/typing.cpython-38.pyc +0 -0
  20. my_container_sandbox/workspace/anaconda3/lib/python3.8/__pycache__/wave.cpython-38.pyc +0 -0
  21. my_container_sandbox/workspace/anaconda3/lib/python3.8/ctypes/__init__.py +560 -0
  22. my_container_sandbox/workspace/anaconda3/lib/python3.8/ctypes/_aix.py +331 -0
  23. my_container_sandbox/workspace/anaconda3/lib/python3.8/ctypes/_endian.py +61 -0
  24. my_container_sandbox/workspace/anaconda3/lib/python3.8/ctypes/util.py +397 -0
  25. my_container_sandbox/workspace/anaconda3/lib/python3.8/ctypes/wintypes.py +202 -0
  26. my_container_sandbox/workspace/anaconda3/lib/python3.8/http/__init__.py +142 -0
  27. my_container_sandbox/workspace/anaconda3/lib/python3.8/http/client.py +1496 -0
  28. my_container_sandbox/workspace/anaconda3/lib/python3.8/http/cookiejar.py +2113 -0
  29. my_container_sandbox/workspace/anaconda3/lib/python3.8/http/cookies.py +609 -0
  30. my_container_sandbox/workspace/anaconda3/lib/python3.8/http/server.py +1316 -0
  31. my_container_sandbox/workspace/anaconda3/lib/tcl8/8.4/platform-1.0.18.tm +439 -0
  32. my_container_sandbox/workspace/anaconda3/lib/tcl8/8.4/platform/shell-1.1.4.tm +241 -0
  33. my_container_sandbox/workspace/anaconda3/lib/tcl8/8.5/msgcat-1.6.1.tm +1210 -0
  34. my_container_sandbox/workspace/anaconda3/lib/tcl8/8.5/tcltest-2.5.3.tm +0 -0
  35. my_container_sandbox/workspace/anaconda3/lib/tcl8/8.6/http-2.9.5.tm +0 -0
  36. my_container_sandbox/workspace/anaconda3/lib/tcl8/8.6/tdbc/sqlite3-1.1.3.tm +715 -0
  37. my_container_sandbox/workspace/anaconda3/lib/tk8.6/demos/images/earth.gif +0 -0
  38. my_container_sandbox/workspace/anaconda3/lib/tk8.6/demos/images/earthmenu.png +0 -0
  39. my_container_sandbox/workspace/anaconda3/lib/tk8.6/demos/images/earthris.gif +0 -0
  40. my_container_sandbox/workspace/anaconda3/lib/tk8.6/demos/images/flagdown.xbm +27 -0
  41. my_container_sandbox/workspace/anaconda3/lib/tk8.6/demos/images/flagup.xbm +27 -0
  42. my_container_sandbox/workspace/anaconda3/lib/tk8.6/demos/images/gray25.xbm +6 -0
  43. my_container_sandbox/workspace/anaconda3/lib/tk8.6/demos/images/letters.xbm +27 -0
  44. my_container_sandbox/workspace/anaconda3/lib/tk8.6/demos/images/noletter.xbm +27 -0
  45. my_container_sandbox/workspace/anaconda3/lib/tk8.6/demos/images/ouster.png +0 -0
  46. my_container_sandbox/workspace/anaconda3/lib/tk8.6/demos/images/pattern.xbm +6 -0
  47. my_container_sandbox/workspace/anaconda3/lib/tk8.6/demos/images/tcllogo.gif +0 -0
  48. my_container_sandbox/workspace/anaconda3/lib/tk8.6/images/README +7 -0
  49. my_container_sandbox/workspace/anaconda3/lib/tk8.6/images/logo.eps +2091 -0
  50. my_container_sandbox/workspace/anaconda3/lib/tk8.6/images/logo100.gif +0 -0
my_container_sandbox/workspace/anaconda3/lib/python3.8/__pycache__/__future__.cpython-38.pyc ADDED
Binary file (4.15 kB). View file
 
my_container_sandbox/workspace/anaconda3/lib/python3.8/__pycache__/_bootlocale.cpython-38.pyc ADDED
Binary file (1.24 kB). View file
 
my_container_sandbox/workspace/anaconda3/lib/python3.8/__pycache__/_sitebuiltins.cpython-38.pyc ADDED
Binary file (3.48 kB). View file
 
my_container_sandbox/workspace/anaconda3/lib/python3.8/__pycache__/_strptime.cpython-38.pyc ADDED
Binary file (16 kB). View file
 
my_container_sandbox/workspace/anaconda3/lib/python3.8/__pycache__/_sysconfigdata_i686_conda_linux_gnu.cpython-38.pyc ADDED
Binary file (20.6 kB). View file
 
my_container_sandbox/workspace/anaconda3/lib/python3.8/__pycache__/asynchat.cpython-38.pyc ADDED
Binary file (6.85 kB). View file
 
my_container_sandbox/workspace/anaconda3/lib/python3.8/__pycache__/code.cpython-38.pyc ADDED
Binary file (9.91 kB). View file
 
my_container_sandbox/workspace/anaconda3/lib/python3.8/__pycache__/codecs.cpython-38.pyc ADDED
Binary file (34 kB). View file
 
my_container_sandbox/workspace/anaconda3/lib/python3.8/__pycache__/codeop.cpython-38.pyc ADDED
Binary file (6.41 kB). View file
 
my_container_sandbox/workspace/anaconda3/lib/python3.8/__pycache__/compileall.cpython-38.pyc ADDED
Binary file (9.41 kB). View file
 
my_container_sandbox/workspace/anaconda3/lib/python3.8/__pycache__/dis.cpython-38.pyc ADDED
Binary file (15.8 kB). View file
 
my_container_sandbox/workspace/anaconda3/lib/python3.8/__pycache__/filecmp.cpython-38.pyc ADDED
Binary file (8.42 kB). View file
 
my_container_sandbox/workspace/anaconda3/lib/python3.8/__pycache__/imp.cpython-38.pyc ADDED
Binary file (9.8 kB). View file
 
my_container_sandbox/workspace/anaconda3/lib/python3.8/__pycache__/inspect.cpython-38.pyc ADDED
Binary file (80.6 kB). View file
 
my_container_sandbox/workspace/anaconda3/lib/python3.8/__pycache__/posixpath.cpython-38.pyc ADDED
Binary file (10.4 kB). View file
 
my_container_sandbox/workspace/anaconda3/lib/python3.8/__pycache__/rlcompleter.cpython-38.pyc ADDED
Binary file (5.75 kB). View file
 
my_container_sandbox/workspace/anaconda3/lib/python3.8/__pycache__/runpy.cpython-38.pyc ADDED
Binary file (8.18 kB). View file
 
my_container_sandbox/workspace/anaconda3/lib/python3.8/__pycache__/secrets.cpython-38.pyc ADDED
Binary file (2.19 kB). View file
 
my_container_sandbox/workspace/anaconda3/lib/python3.8/__pycache__/typing.cpython-38.pyc ADDED
Binary file (62.4 kB). View file
 
my_container_sandbox/workspace/anaconda3/lib/python3.8/__pycache__/wave.cpython-38.pyc ADDED
Binary file (18.1 kB). View file
 
my_container_sandbox/workspace/anaconda3/lib/python3.8/ctypes/__init__.py ADDED
@@ -0,0 +1,560 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """create and manipulate C data types in Python"""
2
+
3
+ import os as _os, sys as _sys
4
+
5
+ __version__ = "1.1.0"
6
+
7
+ from _ctypes import Union, Structure, Array
8
+ from _ctypes import _Pointer
9
+ from _ctypes import CFuncPtr as _CFuncPtr
10
+ from _ctypes import __version__ as _ctypes_version
11
+ from _ctypes import RTLD_LOCAL, RTLD_GLOBAL
12
+ from _ctypes import ArgumentError
13
+
14
+ from struct import calcsize as _calcsize
15
+
16
+ if __version__ != _ctypes_version:
17
+ raise Exception("Version number mismatch", __version__, _ctypes_version)
18
+
19
+ if _os.name == "nt":
20
+ from _ctypes import FormatError
21
+
22
+ DEFAULT_MODE = RTLD_LOCAL
23
+ if _os.name == "posix" and _sys.platform == "darwin":
24
+ # On OS X 10.3, we use RTLD_GLOBAL as default mode
25
+ # because RTLD_LOCAL does not work at least on some
26
+ # libraries. OS X 10.3 is Darwin 7, so we check for
27
+ # that.
28
+
29
+ if int(_os.uname().release.split('.')[0]) < 8:
30
+ DEFAULT_MODE = RTLD_GLOBAL
31
+
32
+ from _ctypes import FUNCFLAG_CDECL as _FUNCFLAG_CDECL, \
33
+ FUNCFLAG_PYTHONAPI as _FUNCFLAG_PYTHONAPI, \
34
+ FUNCFLAG_USE_ERRNO as _FUNCFLAG_USE_ERRNO, \
35
+ FUNCFLAG_USE_LASTERROR as _FUNCFLAG_USE_LASTERROR
36
+
37
+ # WINOLEAPI -> HRESULT
38
+ # WINOLEAPI_(type)
39
+ #
40
+ # STDMETHODCALLTYPE
41
+ #
42
+ # STDMETHOD(name)
43
+ # STDMETHOD_(type, name)
44
+ #
45
+ # STDAPICALLTYPE
46
+
47
+ def create_string_buffer(init, size=None):
48
+ """create_string_buffer(aBytes) -> character array
49
+ create_string_buffer(anInteger) -> character array
50
+ create_string_buffer(aBytes, anInteger) -> character array
51
+ """
52
+ if isinstance(init, bytes):
53
+ if size is None:
54
+ size = len(init)+1
55
+ _sys.audit("ctypes.create_string_buffer", init, size)
56
+ buftype = c_char * size
57
+ buf = buftype()
58
+ buf.value = init
59
+ return buf
60
+ elif isinstance(init, int):
61
+ _sys.audit("ctypes.create_string_buffer", None, init)
62
+ buftype = c_char * init
63
+ buf = buftype()
64
+ return buf
65
+ raise TypeError(init)
66
+
67
+ def c_buffer(init, size=None):
68
+ ## "deprecated, use create_string_buffer instead"
69
+ ## import warnings
70
+ ## warnings.warn("c_buffer is deprecated, use create_string_buffer instead",
71
+ ## DeprecationWarning, stacklevel=2)
72
+ return create_string_buffer(init, size)
73
+
74
+ _c_functype_cache = {}
75
+ def CFUNCTYPE(restype, *argtypes, **kw):
76
+ """CFUNCTYPE(restype, *argtypes,
77
+ use_errno=False, use_last_error=False) -> function prototype.
78
+
79
+ restype: the result type
80
+ argtypes: a sequence specifying the argument types
81
+
82
+ The function prototype can be called in different ways to create a
83
+ callable object:
84
+
85
+ prototype(integer address) -> foreign function
86
+ prototype(callable) -> create and return a C callable function from callable
87
+ prototype(integer index, method name[, paramflags]) -> foreign function calling a COM method
88
+ prototype((ordinal number, dll object)[, paramflags]) -> foreign function exported by ordinal
89
+ prototype((function name, dll object)[, paramflags]) -> foreign function exported by name
90
+ """
91
+ flags = _FUNCFLAG_CDECL
92
+ if kw.pop("use_errno", False):
93
+ flags |= _FUNCFLAG_USE_ERRNO
94
+ if kw.pop("use_last_error", False):
95
+ flags |= _FUNCFLAG_USE_LASTERROR
96
+ if kw:
97
+ raise ValueError("unexpected keyword argument(s) %s" % kw.keys())
98
+ try:
99
+ return _c_functype_cache[(restype, argtypes, flags)]
100
+ except KeyError:
101
+ class CFunctionType(_CFuncPtr):
102
+ _argtypes_ = argtypes
103
+ _restype_ = restype
104
+ _flags_ = flags
105
+ _c_functype_cache[(restype, argtypes, flags)] = CFunctionType
106
+ return CFunctionType
107
+
108
+ if _os.name == "nt":
109
+ from _ctypes import LoadLibrary as _dlopen
110
+ from _ctypes import FUNCFLAG_STDCALL as _FUNCFLAG_STDCALL
111
+
112
+ _win_functype_cache = {}
113
+ def WINFUNCTYPE(restype, *argtypes, **kw):
114
+ # docstring set later (very similar to CFUNCTYPE.__doc__)
115
+ flags = _FUNCFLAG_STDCALL
116
+ if kw.pop("use_errno", False):
117
+ flags |= _FUNCFLAG_USE_ERRNO
118
+ if kw.pop("use_last_error", False):
119
+ flags |= _FUNCFLAG_USE_LASTERROR
120
+ if kw:
121
+ raise ValueError("unexpected keyword argument(s) %s" % kw.keys())
122
+ try:
123
+ return _win_functype_cache[(restype, argtypes, flags)]
124
+ except KeyError:
125
+ class WinFunctionType(_CFuncPtr):
126
+ _argtypes_ = argtypes
127
+ _restype_ = restype
128
+ _flags_ = flags
129
+ _win_functype_cache[(restype, argtypes, flags)] = WinFunctionType
130
+ return WinFunctionType
131
+ if WINFUNCTYPE.__doc__:
132
+ WINFUNCTYPE.__doc__ = CFUNCTYPE.__doc__.replace("CFUNCTYPE", "WINFUNCTYPE")
133
+
134
+ elif _os.name == "posix":
135
+ from _ctypes import dlopen as _dlopen
136
+
137
+ from _ctypes import sizeof, byref, addressof, alignment, resize
138
+ from _ctypes import get_errno, set_errno
139
+ from _ctypes import _SimpleCData
140
+
141
+ def _check_size(typ, typecode=None):
142
+ # Check if sizeof(ctypes_type) against struct.calcsize. This
143
+ # should protect somewhat against a misconfigured libffi.
144
+ from struct import calcsize
145
+ if typecode is None:
146
+ # Most _type_ codes are the same as used in struct
147
+ typecode = typ._type_
148
+ actual, required = sizeof(typ), calcsize(typecode)
149
+ if actual != required:
150
+ raise SystemError("sizeof(%s) wrong: %d instead of %d" % \
151
+ (typ, actual, required))
152
+
153
+ class py_object(_SimpleCData):
154
+ _type_ = "O"
155
+ def __repr__(self):
156
+ try:
157
+ return super().__repr__()
158
+ except ValueError:
159
+ return "%s(<NULL>)" % type(self).__name__
160
+ _check_size(py_object, "P")
161
+
162
+ class c_short(_SimpleCData):
163
+ _type_ = "h"
164
+ _check_size(c_short)
165
+
166
+ class c_ushort(_SimpleCData):
167
+ _type_ = "H"
168
+ _check_size(c_ushort)
169
+
170
+ class c_long(_SimpleCData):
171
+ _type_ = "l"
172
+ _check_size(c_long)
173
+
174
+ class c_ulong(_SimpleCData):
175
+ _type_ = "L"
176
+ _check_size(c_ulong)
177
+
178
+ if _calcsize("i") == _calcsize("l"):
179
+ # if int and long have the same size, make c_int an alias for c_long
180
+ c_int = c_long
181
+ c_uint = c_ulong
182
+ else:
183
+ class c_int(_SimpleCData):
184
+ _type_ = "i"
185
+ _check_size(c_int)
186
+
187
+ class c_uint(_SimpleCData):
188
+ _type_ = "I"
189
+ _check_size(c_uint)
190
+
191
+ class c_float(_SimpleCData):
192
+ _type_ = "f"
193
+ _check_size(c_float)
194
+
195
+ class c_double(_SimpleCData):
196
+ _type_ = "d"
197
+ _check_size(c_double)
198
+
199
+ class c_longdouble(_SimpleCData):
200
+ _type_ = "g"
201
+ if sizeof(c_longdouble) == sizeof(c_double):
202
+ c_longdouble = c_double
203
+
204
+ if _calcsize("l") == _calcsize("q"):
205
+ # if long and long long have the same size, make c_longlong an alias for c_long
206
+ c_longlong = c_long
207
+ c_ulonglong = c_ulong
208
+ else:
209
+ class c_longlong(_SimpleCData):
210
+ _type_ = "q"
211
+ _check_size(c_longlong)
212
+
213
+ class c_ulonglong(_SimpleCData):
214
+ _type_ = "Q"
215
+ ## def from_param(cls, val):
216
+ ## return ('d', float(val), val)
217
+ ## from_param = classmethod(from_param)
218
+ _check_size(c_ulonglong)
219
+
220
+ class c_ubyte(_SimpleCData):
221
+ _type_ = "B"
222
+ c_ubyte.__ctype_le__ = c_ubyte.__ctype_be__ = c_ubyte
223
+ # backward compatibility:
224
+ ##c_uchar = c_ubyte
225
+ _check_size(c_ubyte)
226
+
227
+ class c_byte(_SimpleCData):
228
+ _type_ = "b"
229
+ c_byte.__ctype_le__ = c_byte.__ctype_be__ = c_byte
230
+ _check_size(c_byte)
231
+
232
+ class c_char(_SimpleCData):
233
+ _type_ = "c"
234
+ c_char.__ctype_le__ = c_char.__ctype_be__ = c_char
235
+ _check_size(c_char)
236
+
237
+ class c_char_p(_SimpleCData):
238
+ _type_ = "z"
239
+ def __repr__(self):
240
+ return "%s(%s)" % (self.__class__.__name__, c_void_p.from_buffer(self).value)
241
+ _check_size(c_char_p, "P")
242
+
243
+ class c_void_p(_SimpleCData):
244
+ _type_ = "P"
245
+ c_voidp = c_void_p # backwards compatibility (to a bug)
246
+ _check_size(c_void_p)
247
+
248
+ class c_bool(_SimpleCData):
249
+ _type_ = "?"
250
+
251
+ from _ctypes import POINTER, pointer, _pointer_type_cache
252
+
253
+ class c_wchar_p(_SimpleCData):
254
+ _type_ = "Z"
255
+ def __repr__(self):
256
+ return "%s(%s)" % (self.__class__.__name__, c_void_p.from_buffer(self).value)
257
+
258
+ class c_wchar(_SimpleCData):
259
+ _type_ = "u"
260
+
261
+ def _reset_cache():
262
+ _pointer_type_cache.clear()
263
+ _c_functype_cache.clear()
264
+ if _os.name == "nt":
265
+ _win_functype_cache.clear()
266
+ # _SimpleCData.c_wchar_p_from_param
267
+ POINTER(c_wchar).from_param = c_wchar_p.from_param
268
+ # _SimpleCData.c_char_p_from_param
269
+ POINTER(c_char).from_param = c_char_p.from_param
270
+ _pointer_type_cache[None] = c_void_p
271
+
272
+ def create_unicode_buffer(init, size=None):
273
+ """create_unicode_buffer(aString) -> character array
274
+ create_unicode_buffer(anInteger) -> character array
275
+ create_unicode_buffer(aString, anInteger) -> character array
276
+ """
277
+ if isinstance(init, str):
278
+ if size is None:
279
+ if sizeof(c_wchar) == 2:
280
+ # UTF-16 requires a surrogate pair (2 wchar_t) for non-BMP
281
+ # characters (outside [U+0000; U+FFFF] range). +1 for trailing
282
+ # NUL character.
283
+ size = sum(2 if ord(c) > 0xFFFF else 1 for c in init) + 1
284
+ else:
285
+ # 32-bit wchar_t (1 wchar_t per Unicode character). +1 for
286
+ # trailing NUL character.
287
+ size = len(init) + 1
288
+ _sys.audit("ctypes.create_unicode_buffer", init, size)
289
+ buftype = c_wchar * size
290
+ buf = buftype()
291
+ buf.value = init
292
+ return buf
293
+ elif isinstance(init, int):
294
+ _sys.audit("ctypes.create_unicode_buffer", None, init)
295
+ buftype = c_wchar * init
296
+ buf = buftype()
297
+ return buf
298
+ raise TypeError(init)
299
+
300
+
301
+ # XXX Deprecated
302
+ def SetPointerType(pointer, cls):
303
+ if _pointer_type_cache.get(cls, None) is not None:
304
+ raise RuntimeError("This type already exists in the cache")
305
+ if id(pointer) not in _pointer_type_cache:
306
+ raise RuntimeError("What's this???")
307
+ pointer.set_type(cls)
308
+ _pointer_type_cache[cls] = pointer
309
+ del _pointer_type_cache[id(pointer)]
310
+
311
+ # XXX Deprecated
312
+ def ARRAY(typ, len):
313
+ return typ * len
314
+
315
+ ################################################################
316
+
317
+
318
+ class CDLL(object):
319
+ """An instance of this class represents a loaded dll/shared
320
+ library, exporting functions using the standard C calling
321
+ convention (named 'cdecl' on Windows).
322
+
323
+ The exported functions can be accessed as attributes, or by
324
+ indexing with the function name. Examples:
325
+
326
+ <obj>.qsort -> callable object
327
+ <obj>['qsort'] -> callable object
328
+
329
+ Calling the functions releases the Python GIL during the call and
330
+ reacquires it afterwards.
331
+ """
332
+ _func_flags_ = _FUNCFLAG_CDECL
333
+ _func_restype_ = c_int
334
+ # default values for repr
335
+ _name = '<uninitialized>'
336
+ _handle = 0
337
+ _FuncPtr = None
338
+
339
+ def __init__(self, name, mode=DEFAULT_MODE, handle=None,
340
+ use_errno=False,
341
+ use_last_error=False,
342
+ winmode=None):
343
+ self._name = name
344
+ flags = self._func_flags_
345
+ if use_errno:
346
+ flags |= _FUNCFLAG_USE_ERRNO
347
+ if use_last_error:
348
+ flags |= _FUNCFLAG_USE_LASTERROR
349
+ if _sys.platform.startswith("aix"):
350
+ """When the name contains ".a(" and ends with ")",
351
+ e.g., "libFOO.a(libFOO.so)" - this is taken to be an
352
+ archive(member) syntax for dlopen(), and the mode is adjusted.
353
+ Otherwise, name is presented to dlopen() as a file argument.
354
+ """
355
+ if name and name.endswith(")") and ".a(" in name:
356
+ mode |= ( _os.RTLD_MEMBER | _os.RTLD_NOW )
357
+ if _os.name == "nt":
358
+ if winmode is not None:
359
+ mode = winmode
360
+ else:
361
+ import nt
362
+ mode = nt._LOAD_LIBRARY_SEARCH_DEFAULT_DIRS
363
+ if '/' in name or '\\' in name:
364
+ self._name = nt._getfullpathname(self._name)
365
+ mode |= nt._LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR
366
+
367
+ class _FuncPtr(_CFuncPtr):
368
+ _flags_ = flags
369
+ _restype_ = self._func_restype_
370
+ self._FuncPtr = _FuncPtr
371
+
372
+ if handle is None:
373
+ self._handle = _dlopen(self._name, mode)
374
+ else:
375
+ self._handle = handle
376
+
377
+ def __repr__(self):
378
+ return "<%s '%s', handle %x at %#x>" % \
379
+ (self.__class__.__name__, self._name,
380
+ (self._handle & (_sys.maxsize*2 + 1)),
381
+ id(self) & (_sys.maxsize*2 + 1))
382
+
383
+ def __getattr__(self, name):
384
+ if name.startswith('__') and name.endswith('__'):
385
+ raise AttributeError(name)
386
+ func = self.__getitem__(name)
387
+ setattr(self, name, func)
388
+ return func
389
+
390
+ def __getitem__(self, name_or_ordinal):
391
+ func = self._FuncPtr((name_or_ordinal, self))
392
+ if not isinstance(name_or_ordinal, int):
393
+ func.__name__ = name_or_ordinal
394
+ return func
395
+
396
+ class PyDLL(CDLL):
397
+ """This class represents the Python library itself. It allows
398
+ accessing Python API functions. The GIL is not released, and
399
+ Python exceptions are handled correctly.
400
+ """
401
+ _func_flags_ = _FUNCFLAG_CDECL | _FUNCFLAG_PYTHONAPI
402
+
403
+ if _os.name == "nt":
404
+
405
+ class WinDLL(CDLL):
406
+ """This class represents a dll exporting functions using the
407
+ Windows stdcall calling convention.
408
+ """
409
+ _func_flags_ = _FUNCFLAG_STDCALL
410
+
411
+ # XXX Hm, what about HRESULT as normal parameter?
412
+ # Mustn't it derive from c_long then?
413
+ from _ctypes import _check_HRESULT, _SimpleCData
414
+ class HRESULT(_SimpleCData):
415
+ _type_ = "l"
416
+ # _check_retval_ is called with the function's result when it
417
+ # is used as restype. It checks for the FAILED bit, and
418
+ # raises an OSError if it is set.
419
+ #
420
+ # The _check_retval_ method is implemented in C, so that the
421
+ # method definition itself is not included in the traceback
422
+ # when it raises an error - that is what we want (and Python
423
+ # doesn't have a way to raise an exception in the caller's
424
+ # frame).
425
+ _check_retval_ = _check_HRESULT
426
+
427
+ class OleDLL(CDLL):
428
+ """This class represents a dll exporting functions using the
429
+ Windows stdcall calling convention, and returning HRESULT.
430
+ HRESULT error values are automatically raised as OSError
431
+ exceptions.
432
+ """
433
+ _func_flags_ = _FUNCFLAG_STDCALL
434
+ _func_restype_ = HRESULT
435
+
436
+ class LibraryLoader(object):
437
+ def __init__(self, dlltype):
438
+ self._dlltype = dlltype
439
+
440
+ def __getattr__(self, name):
441
+ if name[0] == '_':
442
+ raise AttributeError(name)
443
+ dll = self._dlltype(name)
444
+ setattr(self, name, dll)
445
+ return dll
446
+
447
+ def __getitem__(self, name):
448
+ return getattr(self, name)
449
+
450
+ def LoadLibrary(self, name):
451
+ return self._dlltype(name)
452
+
453
+ cdll = LibraryLoader(CDLL)
454
+ pydll = LibraryLoader(PyDLL)
455
+
456
+ if _os.name == "nt":
457
+ pythonapi = PyDLL("python dll", None, _sys.dllhandle)
458
+ elif _sys.platform == "cygwin":
459
+ pythonapi = PyDLL("libpython%d.%d.dll" % _sys.version_info[:2])
460
+ else:
461
+ pythonapi = PyDLL(None)
462
+
463
+
464
+ if _os.name == "nt":
465
+ windll = LibraryLoader(WinDLL)
466
+ oledll = LibraryLoader(OleDLL)
467
+
468
+ GetLastError = windll.kernel32.GetLastError
469
+ from _ctypes import get_last_error, set_last_error
470
+
471
+ def WinError(code=None, descr=None):
472
+ if code is None:
473
+ code = GetLastError()
474
+ if descr is None:
475
+ descr = FormatError(code).strip()
476
+ return OSError(None, descr, None, code)
477
+
478
+ if sizeof(c_uint) == sizeof(c_void_p):
479
+ c_size_t = c_uint
480
+ c_ssize_t = c_int
481
+ elif sizeof(c_ulong) == sizeof(c_void_p):
482
+ c_size_t = c_ulong
483
+ c_ssize_t = c_long
484
+ elif sizeof(c_ulonglong) == sizeof(c_void_p):
485
+ c_size_t = c_ulonglong
486
+ c_ssize_t = c_longlong
487
+
488
+ # functions
489
+
490
+ from _ctypes import _memmove_addr, _memset_addr, _string_at_addr, _cast_addr
491
+
492
+ ## void *memmove(void *, const void *, size_t);
493
+ memmove = CFUNCTYPE(c_void_p, c_void_p, c_void_p, c_size_t)(_memmove_addr)
494
+
495
+ ## void *memset(void *, int, size_t)
496
+ memset = CFUNCTYPE(c_void_p, c_void_p, c_int, c_size_t)(_memset_addr)
497
+
498
+ def PYFUNCTYPE(restype, *argtypes):
499
+ class CFunctionType(_CFuncPtr):
500
+ _argtypes_ = argtypes
501
+ _restype_ = restype
502
+ _flags_ = _FUNCFLAG_CDECL | _FUNCFLAG_PYTHONAPI
503
+ return CFunctionType
504
+
505
+ _cast = PYFUNCTYPE(py_object, c_void_p, py_object, py_object)(_cast_addr)
506
+ def cast(obj, typ):
507
+ return _cast(obj, obj, typ)
508
+
509
+ _string_at = PYFUNCTYPE(py_object, c_void_p, c_int)(_string_at_addr)
510
+ def string_at(ptr, size=-1):
511
+ """string_at(addr[, size]) -> string
512
+
513
+ Return the string at addr."""
514
+ return _string_at(ptr, size)
515
+
516
+ try:
517
+ from _ctypes import _wstring_at_addr
518
+ except ImportError:
519
+ pass
520
+ else:
521
+ _wstring_at = PYFUNCTYPE(py_object, c_void_p, c_int)(_wstring_at_addr)
522
+ def wstring_at(ptr, size=-1):
523
+ """wstring_at(addr[, size]) -> string
524
+
525
+ Return the string at addr."""
526
+ return _wstring_at(ptr, size)
527
+
528
+
529
+ if _os.name == "nt": # COM stuff
530
+ def DllGetClassObject(rclsid, riid, ppv):
531
+ try:
532
+ ccom = __import__("comtypes.server.inprocserver", globals(), locals(), ['*'])
533
+ except ImportError:
534
+ return -2147221231 # CLASS_E_CLASSNOTAVAILABLE
535
+ else:
536
+ return ccom.DllGetClassObject(rclsid, riid, ppv)
537
+
538
+ def DllCanUnloadNow():
539
+ try:
540
+ ccom = __import__("comtypes.server.inprocserver", globals(), locals(), ['*'])
541
+ except ImportError:
542
+ return 0 # S_OK
543
+ return ccom.DllCanUnloadNow()
544
+
545
+ from ctypes._endian import BigEndianStructure, LittleEndianStructure
546
+
547
+ # Fill in specifically-sized types
548
+ c_int8 = c_byte
549
+ c_uint8 = c_ubyte
550
+ for kind in [c_short, c_int, c_long, c_longlong]:
551
+ if sizeof(kind) == 2: c_int16 = kind
552
+ elif sizeof(kind) == 4: c_int32 = kind
553
+ elif sizeof(kind) == 8: c_int64 = kind
554
+ for kind in [c_ushort, c_uint, c_ulong, c_ulonglong]:
555
+ if sizeof(kind) == 2: c_uint16 = kind
556
+ elif sizeof(kind) == 4: c_uint32 = kind
557
+ elif sizeof(kind) == 8: c_uint64 = kind
558
+ del(kind)
559
+
560
+ _reset_cache()
my_container_sandbox/workspace/anaconda3/lib/python3.8/ctypes/_aix.py ADDED
@@ -0,0 +1,331 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Lib/ctypes.util.find_library() support for AIX
3
+ Similar approach as done for Darwin support by using separate files
4
+ but unlike Darwin - no extension such as ctypes.macholib.*
5
+
6
+ dlopen() is an interface to AIX initAndLoad() - primary documentation at:
7
+ https://www.ibm.com/support/knowledgecenter/en/ssw_aix_61/com.ibm.aix.basetrf1/dlopen.htm
8
+ https://www.ibm.com/support/knowledgecenter/en/ssw_aix_61/com.ibm.aix.basetrf1/load.htm
9
+
10
+ AIX supports two styles for dlopen(): svr4 (System V Release 4) which is common on posix
11
+ platforms, but also a BSD style - aka SVR3.
12
+
13
+ From AIX 5.3 Difference Addendum (December 2004)
14
+ 2.9 SVR4 linking affinity
15
+ Nowadays, there are two major object file formats used by the operating systems:
16
+ XCOFF: The COFF enhanced by IBM and others. The original COFF (Common
17
+ Object File Format) was the base of SVR3 and BSD 4.2 systems.
18
+ ELF: Executable and Linking Format that was developed by AT&T and is a
19
+ base for SVR4 UNIX.
20
+
21
+ While the shared library content is identical on AIX - one is located as a filepath name
22
+ (svr4 style) and the other is located as a member of an archive (and the archive
23
+ is located as a filepath name).
24
+
25
+ The key difference arises when supporting multiple abi formats (i.e., 32 and 64 bit).
26
+ For svr4 either only one ABI is supported, or there are two directories, or there
27
+ are different file names. The most common solution for multiple ABI is multiple
28
+ directories.
29
+
30
+ For the XCOFF (aka AIX) style - one directory (one archive file) is sufficient
31
+ as multiple shared libraries can be in the archive - even sharing the same name.
32
+ In documentation the archive is also referred to as the "base" and the shared
33
+ library object is referred to as the "member".
34
+
35
+ For dlopen() on AIX (read initAndLoad()) the calls are similar.
36
+ Default activity occurs when no path information is provided. When path
37
+ information is provided dlopen() does not search any other directories.
38
+
39
+ For SVR4 - the shared library name is the name of the file expected: libFOO.so
40
+ For AIX - the shared library is expressed as base(member). The search is for the
41
+ base (e.g., libFOO.a) and once the base is found the shared library - identified by
42
+ member (e.g., libFOO.so, or shr.o) is located and loaded.
43
+
44
+ The mode bit RTLD_MEMBER tells initAndLoad() that it needs to use the AIX (SVR3)
45
+ naming style.
46
+ """
47
+ __author__ = "Michael Felt <aixtools@felt.demon.nl>"
48
+
49
+ import re
50
+ from os import environ, path
51
+ from sys import executable
52
+ from ctypes import c_void_p, sizeof
53
+ from subprocess import Popen, PIPE, DEVNULL
54
+
55
+ # Executable bit size - 32 or 64
56
+ # Used to filter the search in an archive by size, e.g., -X64
57
+ AIX_ABI = sizeof(c_void_p) * 8
58
+
59
+
60
+ from sys import maxsize
61
+ def _last_version(libnames, sep):
62
+ def _num_version(libname):
63
+ # "libxyz.so.MAJOR.MINOR" => [MAJOR, MINOR]
64
+ parts = libname.split(sep)
65
+ nums = []
66
+ try:
67
+ while parts:
68
+ nums.insert(0, int(parts.pop()))
69
+ except ValueError:
70
+ pass
71
+ return nums or [maxsize]
72
+ return max(reversed(libnames), key=_num_version)
73
+
74
+ def get_ld_header(p):
75
+ # "nested-function, but placed at module level
76
+ ld_header = None
77
+ for line in p.stdout:
78
+ if line.startswith(('/', './', '../')):
79
+ ld_header = line
80
+ elif "INDEX" in line:
81
+ return ld_header.rstrip('\n')
82
+ return None
83
+
84
+ def get_ld_header_info(p):
85
+ # "nested-function, but placed at module level
86
+ # as an ld_header was found, return known paths, archives and members
87
+ # these lines start with a digit
88
+ info = []
89
+ for line in p.stdout:
90
+ if re.match("[0-9]", line):
91
+ info.append(line)
92
+ else:
93
+ # blank line (separator), consume line and end for loop
94
+ break
95
+ return info
96
+
97
+ def get_ld_headers(file):
98
+ """
99
+ Parse the header of the loader section of executable and archives
100
+ This function calls /usr/bin/dump -H as a subprocess
101
+ and returns a list of (ld_header, ld_header_info) tuples.
102
+ """
103
+ # get_ld_headers parsing:
104
+ # 1. Find a line that starts with /, ./, or ../ - set as ld_header
105
+ # 2. If "INDEX" in occurs in a following line - return ld_header
106
+ # 3. get info (lines starting with [0-9])
107
+ ldr_headers = []
108
+ p = Popen(["/usr/bin/dump", f"-X{AIX_ABI}", "-H", file],
109
+ universal_newlines=True, stdout=PIPE, stderr=DEVNULL)
110
+ # be sure to read to the end-of-file - getting all entries
111
+ while True:
112
+ ld_header = get_ld_header(p)
113
+ if ld_header:
114
+ ldr_headers.append((ld_header, get_ld_header_info(p)))
115
+ else:
116
+ break
117
+ p.stdout.close()
118
+ p.wait()
119
+ return ldr_headers
120
+
121
+ def get_shared(ld_headers):
122
+ """
123
+ extract the shareable objects from ld_headers
124
+ character "[" is used to strip off the path information.
125
+ Note: the "[" and "]" characters that are part of dump -H output
126
+ are not removed here.
127
+ """
128
+ shared = []
129
+ for (line, _) in ld_headers:
130
+ # potential member lines contain "["
131
+ # otherwise, no processing needed
132
+ if "[" in line:
133
+ # Strip off trailing colon (:)
134
+ shared.append(line[line.index("["):-1])
135
+ return shared
136
+
137
+ def get_one_match(expr, lines):
138
+ """
139
+ Must be only one match, otherwise result is None.
140
+ When there is a match, strip leading "[" and trailing "]"
141
+ """
142
+ # member names in the ld_headers output are between square brackets
143
+ expr = rf'\[({expr})\]'
144
+ matches = list(filter(None, (re.search(expr, line) for line in lines)))
145
+ if len(matches) == 1:
146
+ return matches[0].group(1)
147
+ else:
148
+ return None
149
+
150
+ # additional processing to deal with AIX legacy names for 64-bit members
151
+ def get_legacy(members):
152
+ """
153
+ This routine provides historical aka legacy naming schemes started
154
+ in AIX4 shared library support for library members names.
155
+ e.g., in /usr/lib/libc.a the member name shr.o for 32-bit binary and
156
+ shr_64.o for 64-bit binary.
157
+ """
158
+ if AIX_ABI == 64:
159
+ # AIX 64-bit member is one of shr64.o, shr_64.o, or shr4_64.o
160
+ expr = r'shr4?_?64\.o'
161
+ member = get_one_match(expr, members)
162
+ if member:
163
+ return member
164
+ else:
165
+ # 32-bit legacy names - both shr.o and shr4.o exist.
166
+ # shr.o is the preffered name so we look for shr.o first
167
+ # i.e., shr4.o is returned only when shr.o does not exist
168
+ for name in ['shr.o', 'shr4.o']:
169
+ member = get_one_match(re.escape(name), members)
170
+ if member:
171
+ return member
172
+ return None
173
+
174
+ def get_version(name, members):
175
+ """
176
+ Sort list of members and return highest numbered version - if it exists.
177
+ This function is called when an unversioned libFOO.a(libFOO.so) has
178
+ not been found.
179
+
180
+ Versioning for the member name is expected to follow
181
+ GNU LIBTOOL conventions: the highest version (x, then X.y, then X.Y.z)
182
+ * find [libFoo.so.X]
183
+ * find [libFoo.so.X.Y]
184
+ * find [libFoo.so.X.Y.Z]
185
+
186
+ Before the GNU convention became the standard scheme regardless of
187
+ binary size AIX packagers used GNU convention "as-is" for 32-bit
188
+ archive members but used an "distinguishing" name for 64-bit members.
189
+ This scheme inserted either 64 or _64 between libFOO and .so
190
+ - generally libFOO_64.so, but occasionally libFOO64.so
191
+ """
192
+ # the expression ending for versions must start as
193
+ # '.so.[0-9]', i.e., *.so.[at least one digit]
194
+ # while multiple, more specific expressions could be specified
195
+ # to search for .so.X, .so.X.Y and .so.X.Y.Z
196
+ # after the first required 'dot' digit
197
+ # any combination of additional 'dot' digits pairs are accepted
198
+ # anything more than libFOO.so.digits.digits.digits
199
+ # should be seen as a member name outside normal expectations
200
+ exprs = [rf'lib{name}\.so\.[0-9]+[0-9.]*',
201
+ rf'lib{name}_?64\.so\.[0-9]+[0-9.]*']
202
+ for expr in exprs:
203
+ versions = []
204
+ for line in members:
205
+ m = re.search(expr, line)
206
+ if m:
207
+ versions.append(m.group(0))
208
+ if versions:
209
+ return _last_version(versions, '.')
210
+ return None
211
+
212
+ def get_member(name, members):
213
+ """
214
+ Return an archive member matching the request in name.
215
+ Name is the library name without any prefix like lib, suffix like .so,
216
+ or version number.
217
+ Given a list of members find and return the most appropriate result
218
+ Priority is given to generic libXXX.so, then a versioned libXXX.so.a.b.c
219
+ and finally, legacy AIX naming scheme.
220
+ """
221
+ # look first for a generic match - prepend lib and append .so
222
+ expr = rf'lib{name}\.so'
223
+ member = get_one_match(expr, members)
224
+ if member:
225
+ return member
226
+ elif AIX_ABI == 64:
227
+ expr = rf'lib{name}64\.so'
228
+ member = get_one_match(expr, members)
229
+ if member:
230
+ return member
231
+ # since an exact match with .so as suffix was not found
232
+ # look for a versioned name
233
+ # If a versioned name is not found, look for AIX legacy member name
234
+ member = get_version(name, members)
235
+ if member:
236
+ return member
237
+ else:
238
+ return get_legacy(members)
239
+
240
+ def get_libpaths():
241
+ """
242
+ On AIX, the buildtime searchpath is stored in the executable.
243
+ as "loader header information".
244
+ The command /usr/bin/dump -H extracts this info.
245
+ Prefix searched libraries with LD_LIBRARY_PATH (preferred),
246
+ or LIBPATH if defined. These paths are appended to the paths
247
+ to libraries the python executable is linked with.
248
+ This mimics AIX dlopen() behavior.
249
+ """
250
+ libpaths = environ.get("LD_LIBRARY_PATH")
251
+ if libpaths is None:
252
+ libpaths = environ.get("LIBPATH")
253
+ if libpaths is None:
254
+ libpaths = []
255
+ else:
256
+ libpaths = libpaths.split(":")
257
+ objects = get_ld_headers(executable)
258
+ for (_, lines) in objects:
259
+ for line in lines:
260
+ # the second (optional) argument is PATH if it includes a /
261
+ path = line.split()[1]
262
+ if "/" in path:
263
+ libpaths.extend(path.split(":"))
264
+ return libpaths
265
+
266
+ def find_shared(paths, name):
267
+ """
268
+ paths is a list of directories to search for an archive.
269
+ name is the abbreviated name given to find_library().
270
+ Process: search "paths" for archive, and if an archive is found
271
+ return the result of get_member().
272
+ If an archive is not found then return None
273
+ """
274
+ for dir in paths:
275
+ # /lib is a symbolic link to /usr/lib, skip it
276
+ if dir == "/lib":
277
+ continue
278
+ # "lib" is prefixed to emulate compiler name resolution,
279
+ # e.g., -lc to libc
280
+ base = f'lib{name}.a'
281
+ archive = path.join(dir, base)
282
+ if path.exists(archive):
283
+ members = get_shared(get_ld_headers(archive))
284
+ member = get_member(re.escape(name), members)
285
+ if member != None:
286
+ return (base, member)
287
+ else:
288
+ return (None, None)
289
+ return (None, None)
290
+
291
+ def find_library(name):
292
+ """AIX implementation of ctypes.util.find_library()
293
+ Find an archive member that will dlopen(). If not available,
294
+ also search for a file (or link) with a .so suffix.
295
+
296
+ AIX supports two types of schemes that can be used with dlopen().
297
+ The so-called SystemV Release4 (svr4) format is commonly suffixed
298
+ with .so while the (default) AIX scheme has the library (archive)
299
+ ending with the suffix .a
300
+ As an archive has multiple members (e.g., 32-bit and 64-bit) in one file
301
+ the argument passed to dlopen must include both the library and
302
+ the member names in a single string.
303
+
304
+ find_library() looks first for an archive (.a) with a suitable member.
305
+ If no archive+member pair is found, look for a .so file.
306
+ """
307
+
308
+ libpaths = get_libpaths()
309
+ (base, member) = find_shared(libpaths, name)
310
+ if base != None:
311
+ return f"{base}({member})"
312
+
313
+ # To get here, a member in an archive has not been found
314
+ # In other words, either:
315
+ # a) a .a file was not found
316
+ # b) a .a file did not have a suitable member
317
+ # So, look for a .so file
318
+ # Check libpaths for .so file
319
+ # Note, the installation must prepare a link from a .so
320
+ # to a versioned file
321
+ # This is common practice by GNU libtool on other platforms
322
+ soname = f"lib{name}.so"
323
+ for dir in libpaths:
324
+ # /lib is a symbolic link to /usr/lib, skip it
325
+ if dir == "/lib":
326
+ continue
327
+ shlib = path.join(dir, soname)
328
+ if path.exists(shlib):
329
+ return soname
330
+ # if we are here, we have not found anything plausible
331
+ return None
my_container_sandbox/workspace/anaconda3/lib/python3.8/ctypes/_endian.py ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import sys
2
+ from ctypes import *
3
+
4
+ _array_type = type(Array)
5
+
6
+ def _other_endian(typ):
7
+ """Return the type with the 'other' byte order. Simple types like
8
+ c_int and so on already have __ctype_be__ and __ctype_le__
9
+ attributes which contain the types, for more complicated types
10
+ arrays and structures are supported.
11
+ """
12
+ # check _OTHER_ENDIAN attribute (present if typ is primitive type)
13
+ if hasattr(typ, _OTHER_ENDIAN):
14
+ return getattr(typ, _OTHER_ENDIAN)
15
+ # if typ is array
16
+ if isinstance(typ, _array_type):
17
+ return _other_endian(typ._type_) * typ._length_
18
+ # if typ is structure
19
+ if issubclass(typ, Structure):
20
+ return typ
21
+ raise TypeError("This type does not support other endian: %s" % typ)
22
+
23
+ class _swapped_meta(type(Structure)):
24
+ def __setattr__(self, attrname, value):
25
+ if attrname == "_fields_":
26
+ fields = []
27
+ for desc in value:
28
+ name = desc[0]
29
+ typ = desc[1]
30
+ rest = desc[2:]
31
+ fields.append((name, _other_endian(typ)) + rest)
32
+ value = fields
33
+ super().__setattr__(attrname, value)
34
+
35
+ ################################################################
36
+
37
+ # Note: The Structure metaclass checks for the *presence* (not the
38
+ # value!) of a _swapped_bytes_ attribute to determine the bit order in
39
+ # structures containing bit fields.
40
+
41
+ if sys.byteorder == "little":
42
+ _OTHER_ENDIAN = "__ctype_be__"
43
+
44
+ LittleEndianStructure = Structure
45
+
46
+ class BigEndianStructure(Structure, metaclass=_swapped_meta):
47
+ """Structure with big endian byte order"""
48
+ __slots__ = ()
49
+ _swappedbytes_ = None
50
+
51
+ elif sys.byteorder == "big":
52
+ _OTHER_ENDIAN = "__ctype_le__"
53
+
54
+ BigEndianStructure = Structure
55
+ class LittleEndianStructure(Structure, metaclass=_swapped_meta):
56
+ """Structure with little endian byte order"""
57
+ __slots__ = ()
58
+ _swappedbytes_ = None
59
+
60
+ else:
61
+ raise RuntimeError("Invalid byteorder")
my_container_sandbox/workspace/anaconda3/lib/python3.8/ctypes/util.py ADDED
@@ -0,0 +1,397 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import shutil
3
+ import subprocess
4
+ import sys
5
+
6
+ # find_library(name) returns the pathname of a library, or None.
7
+ if os.name == "nt":
8
+
9
+ def _get_build_version():
10
+ """Return the version of MSVC that was used to build Python.
11
+
12
+ For Python 2.3 and up, the version number is included in
13
+ sys.version. For earlier versions, assume the compiler is MSVC 6.
14
+ """
15
+ # This function was copied from Lib/distutils/msvccompiler.py
16
+ prefix = "MSC v."
17
+ i = sys.version.find(prefix)
18
+ if i == -1:
19
+ return 6
20
+ i = i + len(prefix)
21
+ s, rest = sys.version[i:].split(" ", 1)
22
+ majorVersion = int(s[:-2]) - 6
23
+ if majorVersion >= 13:
24
+ majorVersion += 1
25
+ minorVersion = int(s[2:3]) / 10.0
26
+ # I don't think paths are affected by minor version in version 6
27
+ if majorVersion == 6:
28
+ minorVersion = 0
29
+ if majorVersion >= 6:
30
+ return majorVersion + minorVersion
31
+ # else we don't know what version of the compiler this is
32
+ return None
33
+
34
+ def find_msvcrt():
35
+ """Return the name of the VC runtime dll"""
36
+ version = _get_build_version()
37
+ if version is None:
38
+ # better be safe than sorry
39
+ return None
40
+ if version <= 6:
41
+ clibname = 'msvcrt'
42
+ elif version <= 13:
43
+ clibname = 'msvcr%d' % (version * 10)
44
+ else:
45
+ # CRT is no longer directly loadable. See issue23606 for the
46
+ # discussion about alternative approaches.
47
+ return None
48
+
49
+ # If python was built with in debug mode
50
+ import importlib.machinery
51
+ if '_d.pyd' in importlib.machinery.EXTENSION_SUFFIXES:
52
+ clibname += 'd'
53
+ return clibname+'.dll'
54
+
55
+ def find_library(name):
56
+ if name in ('c', 'm'):
57
+ return find_msvcrt()
58
+ # See MSDN for the REAL search order.
59
+ for directory in os.environ['PATH'].split(os.pathsep):
60
+ fname = os.path.join(directory, name)
61
+ if os.path.isfile(fname):
62
+ return fname
63
+ if fname.lower().endswith(".dll"):
64
+ continue
65
+ fname = fname + ".dll"
66
+ if os.path.isfile(fname):
67
+ return fname
68
+ return None
69
+
70
+ elif os.name == "posix" and sys.platform == "darwin":
71
+ from ctypes.macholib.dyld import dyld_find as _dyld_find
72
+ def find_library(name):
73
+ possible = ['@executable_path/../lib/lib%s.dylib' % name,
74
+ 'lib%s.dylib' % name,
75
+ '%s.dylib' % name,
76
+ '%s.framework/%s' % (name, name)]
77
+ for name in possible:
78
+ try:
79
+ return _dyld_find(name)
80
+ except ValueError:
81
+ continue
82
+ return None
83
+
84
+ elif sys.platform.startswith("aix"):
85
+ # AIX has two styles of storing shared libraries
86
+ # GNU auto_tools refer to these as svr4 and aix
87
+ # svr4 (System V Release 4) is a regular file, often with .so as suffix
88
+ # AIX style uses an archive (suffix .a) with members (e.g., shr.o, libssl.so)
89
+ # see issue#26439 and _aix.py for more details
90
+
91
+ from ctypes._aix import find_library
92
+
93
+ elif os.name == "posix":
94
+ # Andreas Degert's find functions, using gcc, /sbin/ldconfig, objdump
95
+ import re, tempfile
96
+
97
+ def _is_elf(filename):
98
+ "Return True if the given file is an ELF file"
99
+ elf_header = b'\x7fELF'
100
+ with open(filename, 'br') as thefile:
101
+ return thefile.read(4) == elf_header
102
+
103
+ def _findLib_gcc(name):
104
+ # Run GCC's linker with the -t (aka --trace) option and examine the
105
+ # library name it prints out. The GCC command will fail because we
106
+ # haven't supplied a proper program with main(), but that does not
107
+ # matter.
108
+ expr = os.fsencode(r'[^\(\)\s]*lib%s\.[^\(\)\s]*' % re.escape(name))
109
+
110
+ c_compiler = shutil.which('gcc')
111
+ if not c_compiler:
112
+ c_compiler = shutil.which('cc')
113
+ if not c_compiler:
114
+ # No C compiler available, give up
115
+ return None
116
+
117
+ temp = tempfile.NamedTemporaryFile()
118
+ try:
119
+ args = [c_compiler, '-Wl,-t', '-o', temp.name, '-l' + name]
120
+
121
+ env = dict(os.environ)
122
+ env['LC_ALL'] = 'C'
123
+ env['LANG'] = 'C'
124
+ try:
125
+ proc = subprocess.Popen(args,
126
+ stdout=subprocess.PIPE,
127
+ stderr=subprocess.STDOUT,
128
+ env=env)
129
+ except OSError: # E.g. bad executable
130
+ return None
131
+ with proc:
132
+ trace = proc.stdout.read()
133
+ finally:
134
+ try:
135
+ temp.close()
136
+ except FileNotFoundError:
137
+ # Raised if the file was already removed, which is the normal
138
+ # behaviour of GCC if linking fails
139
+ pass
140
+ res = re.findall(expr, trace)
141
+ if not res:
142
+ return None
143
+
144
+ for file in res:
145
+ # Check if the given file is an elf file: gcc can report
146
+ # some files that are linker scripts and not actual
147
+ # shared objects. See bpo-41976 for more details
148
+ if not _is_elf(file):
149
+ continue
150
+ return os.fsdecode(file)
151
+
152
+
153
+ if sys.platform == "sunos5":
154
+ # use /usr/ccs/bin/dump on solaris
155
+ def _get_soname(f):
156
+ if not f:
157
+ return None
158
+
159
+ try:
160
+ proc = subprocess.Popen(("/usr/ccs/bin/dump", "-Lpv", f),
161
+ stdout=subprocess.PIPE,
162
+ stderr=subprocess.DEVNULL)
163
+ except OSError: # E.g. command not found
164
+ return None
165
+ with proc:
166
+ data = proc.stdout.read()
167
+ res = re.search(br'\[.*\]\sSONAME\s+([^\s]+)', data)
168
+ if not res:
169
+ return None
170
+ return os.fsdecode(res.group(1))
171
+ else:
172
+ def _get_soname(f):
173
+ # assuming GNU binutils / ELF
174
+ if not f:
175
+ return None
176
+ objdump = shutil.which('objdump')
177
+ if not objdump:
178
+ # objdump is not available, give up
179
+ return None
180
+
181
+ try:
182
+ proc = subprocess.Popen((objdump, '-p', '-j', '.dynamic', f),
183
+ stdout=subprocess.PIPE,
184
+ stderr=subprocess.DEVNULL)
185
+ except OSError: # E.g. bad executable
186
+ return None
187
+ with proc:
188
+ dump = proc.stdout.read()
189
+ res = re.search(br'\sSONAME\s+([^\s]+)', dump)
190
+ if not res:
191
+ return None
192
+ return os.fsdecode(res.group(1))
193
+
194
+ if sys.platform.startswith(("freebsd", "openbsd", "dragonfly")):
195
+
196
+ def _num_version(libname):
197
+ # "libxyz.so.MAJOR.MINOR" => [ MAJOR, MINOR ]
198
+ parts = libname.split(b".")
199
+ nums = []
200
+ try:
201
+ while parts:
202
+ nums.insert(0, int(parts.pop()))
203
+ except ValueError:
204
+ pass
205
+ return nums or [sys.maxsize]
206
+
207
+ def find_library(name):
208
+ ename = re.escape(name)
209
+ expr = r':-l%s\.\S+ => \S*/(lib%s\.\S+)' % (ename, ename)
210
+ expr = os.fsencode(expr)
211
+
212
+ try:
213
+ proc = subprocess.Popen(('/sbin/ldconfig', '-r'),
214
+ stdout=subprocess.PIPE,
215
+ stderr=subprocess.DEVNULL)
216
+ except OSError: # E.g. command not found
217
+ data = b''
218
+ else:
219
+ with proc:
220
+ data = proc.stdout.read()
221
+
222
+ res = re.findall(expr, data)
223
+ if not res:
224
+ return _get_soname(_findLib_gcc(name))
225
+ res.sort(key=_num_version)
226
+ return os.fsdecode(res[-1])
227
+
228
+ elif sys.platform == "sunos5":
229
+
230
+ def _findLib_crle(name, is64):
231
+ if not os.path.exists('/usr/bin/crle'):
232
+ return None
233
+
234
+ env = dict(os.environ)
235
+ env['LC_ALL'] = 'C'
236
+
237
+ if is64:
238
+ args = ('/usr/bin/crle', '-64')
239
+ else:
240
+ args = ('/usr/bin/crle',)
241
+
242
+ paths = None
243
+ try:
244
+ proc = subprocess.Popen(args,
245
+ stdout=subprocess.PIPE,
246
+ stderr=subprocess.DEVNULL,
247
+ env=env)
248
+ except OSError: # E.g. bad executable
249
+ return None
250
+ with proc:
251
+ for line in proc.stdout:
252
+ line = line.strip()
253
+ if line.startswith(b'Default Library Path (ELF):'):
254
+ paths = os.fsdecode(line).split()[4]
255
+
256
+ if not paths:
257
+ return None
258
+
259
+ for dir in paths.split(":"):
260
+ libfile = os.path.join(dir, "lib%s.so" % name)
261
+ if os.path.exists(libfile):
262
+ return libfile
263
+
264
+ return None
265
+
266
+ def find_library(name, is64 = False):
267
+ return _get_soname(_findLib_crle(name, is64) or _findLib_gcc(name))
268
+
269
+ else:
270
+
271
+ def _findSoname_ldconfig(name):
272
+ import struct
273
+ if struct.calcsize('l') == 4:
274
+ machine = os.uname().machine + '-32'
275
+ else:
276
+ machine = os.uname().machine + '-64'
277
+ mach_map = {
278
+ 'x86_64-64': 'libc6,x86-64',
279
+ 'ppc64-64': 'libc6,64bit',
280
+ 'sparc64-64': 'libc6,64bit',
281
+ 's390x-64': 'libc6,64bit',
282
+ 'ia64-64': 'libc6,IA-64',
283
+ }
284
+ abi_type = mach_map.get(machine, 'libc6')
285
+
286
+ # XXX assuming GLIBC's ldconfig (with option -p)
287
+ regex = r'\s+(lib%s\.[^\s]+)\s+\(%s'
288
+ regex = os.fsencode(regex % (re.escape(name), abi_type))
289
+ try:
290
+ with subprocess.Popen(['/sbin/ldconfig', '-p'],
291
+ stdin=subprocess.DEVNULL,
292
+ stderr=subprocess.DEVNULL,
293
+ stdout=subprocess.PIPE,
294
+ env={'LC_ALL': 'C', 'LANG': 'C'}) as p:
295
+ res = re.search(regex, p.stdout.read())
296
+ if res:
297
+ return os.fsdecode(res.group(1))
298
+ except OSError:
299
+ pass
300
+
301
+ def _findLib_ld(name):
302
+ # See issue #9998 for why this is needed
303
+ expr = r'[^\(\)\s]*lib%s\.[^\(\)\s]*' % re.escape(name)
304
+ cmd = ['ld', '-t']
305
+ libpath = os.environ.get('LD_LIBRARY_PATH')
306
+ if libpath:
307
+ for d in libpath.split(':'):
308
+ cmd.extend(['-L', d])
309
+ cmd.extend(['-o', os.devnull, '-l%s' % name])
310
+ result = None
311
+ try:
312
+ p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
313
+ stderr=subprocess.PIPE,
314
+ universal_newlines=True)
315
+ out, _ = p.communicate()
316
+ res = re.findall(expr, os.fsdecode(out))
317
+ for file in res:
318
+ # Check if the given file is an elf file: gcc can report
319
+ # some files that are linker scripts and not actual
320
+ # shared objects. See bpo-41976 for more details
321
+ if not _is_elf(file):
322
+ continue
323
+ return os.fsdecode(file)
324
+ except Exception:
325
+ pass # result will be None
326
+ return result
327
+
328
+ def _findLib_prefix(name):
329
+ if not name:
330
+ return None
331
+ for fullname in (name, "lib%s.so" % (name)):
332
+ path = os.path.join(sys.prefix, 'lib', fullname)
333
+ if os.path.exists(path):
334
+ return path
335
+ return None
336
+
337
+ def find_library(name):
338
+ # See issue #9998
339
+ # Yes calling _findLib_prefix twice is deliberate, because _get_soname ditches
340
+ # the full path.
341
+ # When objdump is unavailable this returns None
342
+ so_name = _get_soname(_findLib_prefix(name)) or name
343
+ if so_name != name:
344
+ return _findLib_prefix(so_name) or \
345
+ _findLib_prefix(name) or \
346
+ _findSoname_ldconfig(name) or \
347
+ _get_soname(_findLib_gcc(name) or _findLib_ld(name))
348
+ else:
349
+ return _findLib_prefix(name) or \
350
+ _findSoname_ldconfig(name) or \
351
+ _get_soname(_findLib_gcc(name) or _findLib_ld(name))
352
+
353
+ ################################################################
354
+ # test code
355
+
356
+ def test():
357
+ from ctypes import cdll
358
+ if os.name == "nt":
359
+ print(cdll.msvcrt)
360
+ print(cdll.load("msvcrt"))
361
+ print(find_library("msvcrt"))
362
+
363
+ if os.name == "posix":
364
+ # find and load_version
365
+ print(find_library("m"))
366
+ print(find_library("c"))
367
+ print(find_library("bz2"))
368
+
369
+ # load
370
+ if sys.platform == "darwin":
371
+ print(cdll.LoadLibrary("libm.dylib"))
372
+ print(cdll.LoadLibrary("libcrypto.dylib"))
373
+ print(cdll.LoadLibrary("libSystem.dylib"))
374
+ print(cdll.LoadLibrary("System.framework/System"))
375
+ # issue-26439 - fix broken test call for AIX
376
+ elif sys.platform.startswith("aix"):
377
+ from ctypes import CDLL
378
+ if sys.maxsize < 2**32:
379
+ print(f"Using CDLL(name, os.RTLD_MEMBER): {CDLL('libc.a(shr.o)', os.RTLD_MEMBER)}")
380
+ print(f"Using cdll.LoadLibrary(): {cdll.LoadLibrary('libc.a(shr.o)')}")
381
+ # librpm.so is only available as 32-bit shared library
382
+ print(find_library("rpm"))
383
+ print(cdll.LoadLibrary("librpm.so"))
384
+ else:
385
+ print(f"Using CDLL(name, os.RTLD_MEMBER): {CDLL('libc.a(shr_64.o)', os.RTLD_MEMBER)}")
386
+ print(f"Using cdll.LoadLibrary(): {cdll.LoadLibrary('libc.a(shr_64.o)')}")
387
+ print(f"crypt\t:: {find_library('crypt')}")
388
+ print(f"crypt\t:: {cdll.LoadLibrary(find_library('crypt'))}")
389
+ print(f"crypto\t:: {find_library('crypto')}")
390
+ print(f"crypto\t:: {cdll.LoadLibrary(find_library('crypto'))}")
391
+ else:
392
+ print(cdll.LoadLibrary("libm.so"))
393
+ print(cdll.LoadLibrary("libcrypt.so"))
394
+ print(find_library("crypt"))
395
+
396
+ if __name__ == "__main__":
397
+ test()
my_container_sandbox/workspace/anaconda3/lib/python3.8/ctypes/wintypes.py ADDED
@@ -0,0 +1,202 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # The most useful windows datatypes
2
+ import ctypes
3
+
4
+ BYTE = ctypes.c_byte
5
+ WORD = ctypes.c_ushort
6
+ DWORD = ctypes.c_ulong
7
+
8
+ #UCHAR = ctypes.c_uchar
9
+ CHAR = ctypes.c_char
10
+ WCHAR = ctypes.c_wchar
11
+ UINT = ctypes.c_uint
12
+ INT = ctypes.c_int
13
+
14
+ DOUBLE = ctypes.c_double
15
+ FLOAT = ctypes.c_float
16
+
17
+ BOOLEAN = BYTE
18
+ BOOL = ctypes.c_long
19
+
20
+ class VARIANT_BOOL(ctypes._SimpleCData):
21
+ _type_ = "v"
22
+ def __repr__(self):
23
+ return "%s(%r)" % (self.__class__.__name__, self.value)
24
+
25
+ ULONG = ctypes.c_ulong
26
+ LONG = ctypes.c_long
27
+
28
+ USHORT = ctypes.c_ushort
29
+ SHORT = ctypes.c_short
30
+
31
+ # in the windows header files, these are structures.
32
+ _LARGE_INTEGER = LARGE_INTEGER = ctypes.c_longlong
33
+ _ULARGE_INTEGER = ULARGE_INTEGER = ctypes.c_ulonglong
34
+
35
+ LPCOLESTR = LPOLESTR = OLESTR = ctypes.c_wchar_p
36
+ LPCWSTR = LPWSTR = ctypes.c_wchar_p
37
+ LPCSTR = LPSTR = ctypes.c_char_p
38
+ LPCVOID = LPVOID = ctypes.c_void_p
39
+
40
+ # WPARAM is defined as UINT_PTR (unsigned type)
41
+ # LPARAM is defined as LONG_PTR (signed type)
42
+ if ctypes.sizeof(ctypes.c_long) == ctypes.sizeof(ctypes.c_void_p):
43
+ WPARAM = ctypes.c_ulong
44
+ LPARAM = ctypes.c_long
45
+ elif ctypes.sizeof(ctypes.c_longlong) == ctypes.sizeof(ctypes.c_void_p):
46
+ WPARAM = ctypes.c_ulonglong
47
+ LPARAM = ctypes.c_longlong
48
+
49
+ ATOM = WORD
50
+ LANGID = WORD
51
+
52
+ COLORREF = DWORD
53
+ LGRPID = DWORD
54
+ LCTYPE = DWORD
55
+
56
+ LCID = DWORD
57
+
58
+ ################################################################
59
+ # HANDLE types
60
+ HANDLE = ctypes.c_void_p # in the header files: void *
61
+
62
+ HACCEL = HANDLE
63
+ HBITMAP = HANDLE
64
+ HBRUSH = HANDLE
65
+ HCOLORSPACE = HANDLE
66
+ HDC = HANDLE
67
+ HDESK = HANDLE
68
+ HDWP = HANDLE
69
+ HENHMETAFILE = HANDLE
70
+ HFONT = HANDLE
71
+ HGDIOBJ = HANDLE
72
+ HGLOBAL = HANDLE
73
+ HHOOK = HANDLE
74
+ HICON = HANDLE
75
+ HINSTANCE = HANDLE
76
+ HKEY = HANDLE
77
+ HKL = HANDLE
78
+ HLOCAL = HANDLE
79
+ HMENU = HANDLE
80
+ HMETAFILE = HANDLE
81
+ HMODULE = HANDLE
82
+ HMONITOR = HANDLE
83
+ HPALETTE = HANDLE
84
+ HPEN = HANDLE
85
+ HRGN = HANDLE
86
+ HRSRC = HANDLE
87
+ HSTR = HANDLE
88
+ HTASK = HANDLE
89
+ HWINSTA = HANDLE
90
+ HWND = HANDLE
91
+ SC_HANDLE = HANDLE
92
+ SERVICE_STATUS_HANDLE = HANDLE
93
+
94
+ ################################################################
95
+ # Some important structure definitions
96
+
97
+ class RECT(ctypes.Structure):
98
+ _fields_ = [("left", LONG),
99
+ ("top", LONG),
100
+ ("right", LONG),
101
+ ("bottom", LONG)]
102
+ tagRECT = _RECTL = RECTL = RECT
103
+
104
+ class _SMALL_RECT(ctypes.Structure):
105
+ _fields_ = [('Left', SHORT),
106
+ ('Top', SHORT),
107
+ ('Right', SHORT),
108
+ ('Bottom', SHORT)]
109
+ SMALL_RECT = _SMALL_RECT
110
+
111
+ class _COORD(ctypes.Structure):
112
+ _fields_ = [('X', SHORT),
113
+ ('Y', SHORT)]
114
+
115
+ class POINT(ctypes.Structure):
116
+ _fields_ = [("x", LONG),
117
+ ("y", LONG)]
118
+ tagPOINT = _POINTL = POINTL = POINT
119
+
120
+ class SIZE(ctypes.Structure):
121
+ _fields_ = [("cx", LONG),
122
+ ("cy", LONG)]
123
+ tagSIZE = SIZEL = SIZE
124
+
125
+ def RGB(red, green, blue):
126
+ return red + (green << 8) + (blue << 16)
127
+
128
+ class FILETIME(ctypes.Structure):
129
+ _fields_ = [("dwLowDateTime", DWORD),
130
+ ("dwHighDateTime", DWORD)]
131
+ _FILETIME = FILETIME
132
+
133
+ class MSG(ctypes.Structure):
134
+ _fields_ = [("hWnd", HWND),
135
+ ("message", UINT),
136
+ ("wParam", WPARAM),
137
+ ("lParam", LPARAM),
138
+ ("time", DWORD),
139
+ ("pt", POINT)]
140
+ tagMSG = MSG
141
+ MAX_PATH = 260
142
+
143
+ class WIN32_FIND_DATAA(ctypes.Structure):
144
+ _fields_ = [("dwFileAttributes", DWORD),
145
+ ("ftCreationTime", FILETIME),
146
+ ("ftLastAccessTime", FILETIME),
147
+ ("ftLastWriteTime", FILETIME),
148
+ ("nFileSizeHigh", DWORD),
149
+ ("nFileSizeLow", DWORD),
150
+ ("dwReserved0", DWORD),
151
+ ("dwReserved1", DWORD),
152
+ ("cFileName", CHAR * MAX_PATH),
153
+ ("cAlternateFileName", CHAR * 14)]
154
+
155
+ class WIN32_FIND_DATAW(ctypes.Structure):
156
+ _fields_ = [("dwFileAttributes", DWORD),
157
+ ("ftCreationTime", FILETIME),
158
+ ("ftLastAccessTime", FILETIME),
159
+ ("ftLastWriteTime", FILETIME),
160
+ ("nFileSizeHigh", DWORD),
161
+ ("nFileSizeLow", DWORD),
162
+ ("dwReserved0", DWORD),
163
+ ("dwReserved1", DWORD),
164
+ ("cFileName", WCHAR * MAX_PATH),
165
+ ("cAlternateFileName", WCHAR * 14)]
166
+
167
+ ################################################################
168
+ # Pointer types
169
+
170
+ LPBOOL = PBOOL = ctypes.POINTER(BOOL)
171
+ PBOOLEAN = ctypes.POINTER(BOOLEAN)
172
+ LPBYTE = PBYTE = ctypes.POINTER(BYTE)
173
+ PCHAR = ctypes.POINTER(CHAR)
174
+ LPCOLORREF = ctypes.POINTER(COLORREF)
175
+ LPDWORD = PDWORD = ctypes.POINTER(DWORD)
176
+ LPFILETIME = PFILETIME = ctypes.POINTER(FILETIME)
177
+ PFLOAT = ctypes.POINTER(FLOAT)
178
+ LPHANDLE = PHANDLE = ctypes.POINTER(HANDLE)
179
+ PHKEY = ctypes.POINTER(HKEY)
180
+ LPHKL = ctypes.POINTER(HKL)
181
+ LPINT = PINT = ctypes.POINTER(INT)
182
+ PLARGE_INTEGER = ctypes.POINTER(LARGE_INTEGER)
183
+ PLCID = ctypes.POINTER(LCID)
184
+ LPLONG = PLONG = ctypes.POINTER(LONG)
185
+ LPMSG = PMSG = ctypes.POINTER(MSG)
186
+ LPPOINT = PPOINT = ctypes.POINTER(POINT)
187
+ PPOINTL = ctypes.POINTER(POINTL)
188
+ LPRECT = PRECT = ctypes.POINTER(RECT)
189
+ LPRECTL = PRECTL = ctypes.POINTER(RECTL)
190
+ LPSC_HANDLE = ctypes.POINTER(SC_HANDLE)
191
+ PSHORT = ctypes.POINTER(SHORT)
192
+ LPSIZE = PSIZE = ctypes.POINTER(SIZE)
193
+ LPSIZEL = PSIZEL = ctypes.POINTER(SIZEL)
194
+ PSMALL_RECT = ctypes.POINTER(SMALL_RECT)
195
+ LPUINT = PUINT = ctypes.POINTER(UINT)
196
+ PULARGE_INTEGER = ctypes.POINTER(ULARGE_INTEGER)
197
+ PULONG = ctypes.POINTER(ULONG)
198
+ PUSHORT = ctypes.POINTER(USHORT)
199
+ PWCHAR = ctypes.POINTER(WCHAR)
200
+ LPWIN32_FIND_DATAA = PWIN32_FIND_DATAA = ctypes.POINTER(WIN32_FIND_DATAA)
201
+ LPWIN32_FIND_DATAW = PWIN32_FIND_DATAW = ctypes.POINTER(WIN32_FIND_DATAW)
202
+ LPWORD = PWORD = ctypes.POINTER(WORD)
my_container_sandbox/workspace/anaconda3/lib/python3.8/http/__init__.py ADDED
@@ -0,0 +1,142 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from enum import IntEnum
2
+
3
+ __all__ = ['HTTPStatus']
4
+
5
+ class HTTPStatus(IntEnum):
6
+ """HTTP status codes and reason phrases
7
+
8
+ Status codes from the following RFCs are all observed:
9
+
10
+ * RFC 7231: Hypertext Transfer Protocol (HTTP/1.1), obsoletes 2616
11
+ * RFC 6585: Additional HTTP Status Codes
12
+ * RFC 3229: Delta encoding in HTTP
13
+ * RFC 4918: HTTP Extensions for WebDAV, obsoletes 2518
14
+ * RFC 5842: Binding Extensions to WebDAV
15
+ * RFC 7238: Permanent Redirect
16
+ * RFC 2295: Transparent Content Negotiation in HTTP
17
+ * RFC 2774: An HTTP Extension Framework
18
+ * RFC 7725: An HTTP Status Code to Report Legal Obstacles
19
+ * RFC 7540: Hypertext Transfer Protocol Version 2 (HTTP/2)
20
+ """
21
+ def __new__(cls, value, phrase, description=''):
22
+ obj = int.__new__(cls, value)
23
+ obj._value_ = value
24
+
25
+ obj.phrase = phrase
26
+ obj.description = description
27
+ return obj
28
+
29
+ # informational
30
+ CONTINUE = 100, 'Continue', 'Request received, please continue'
31
+ SWITCHING_PROTOCOLS = (101, 'Switching Protocols',
32
+ 'Switching to new protocol; obey Upgrade header')
33
+ PROCESSING = 102, 'Processing'
34
+
35
+ # success
36
+ OK = 200, 'OK', 'Request fulfilled, document follows'
37
+ CREATED = 201, 'Created', 'Document created, URL follows'
38
+ ACCEPTED = (202, 'Accepted',
39
+ 'Request accepted, processing continues off-line')
40
+ NON_AUTHORITATIVE_INFORMATION = (203,
41
+ 'Non-Authoritative Information', 'Request fulfilled from cache')
42
+ NO_CONTENT = 204, 'No Content', 'Request fulfilled, nothing follows'
43
+ RESET_CONTENT = 205, 'Reset Content', 'Clear input form for further input'
44
+ PARTIAL_CONTENT = 206, 'Partial Content', 'Partial content follows'
45
+ MULTI_STATUS = 207, 'Multi-Status'
46
+ ALREADY_REPORTED = 208, 'Already Reported'
47
+ IM_USED = 226, 'IM Used'
48
+
49
+ # redirection
50
+ MULTIPLE_CHOICES = (300, 'Multiple Choices',
51
+ 'Object has several resources -- see URI list')
52
+ MOVED_PERMANENTLY = (301, 'Moved Permanently',
53
+ 'Object moved permanently -- see URI list')
54
+ FOUND = 302, 'Found', 'Object moved temporarily -- see URI list'
55
+ SEE_OTHER = 303, 'See Other', 'Object moved -- see Method and URL list'
56
+ NOT_MODIFIED = (304, 'Not Modified',
57
+ 'Document has not changed since given time')
58
+ USE_PROXY = (305, 'Use Proxy',
59
+ 'You must use proxy specified in Location to access this resource')
60
+ TEMPORARY_REDIRECT = (307, 'Temporary Redirect',
61
+ 'Object moved temporarily -- see URI list')
62
+ PERMANENT_REDIRECT = (308, 'Permanent Redirect',
63
+ 'Object moved permanently -- see URI list')
64
+
65
+ # client error
66
+ BAD_REQUEST = (400, 'Bad Request',
67
+ 'Bad request syntax or unsupported method')
68
+ UNAUTHORIZED = (401, 'Unauthorized',
69
+ 'No permission -- see authorization schemes')
70
+ PAYMENT_REQUIRED = (402, 'Payment Required',
71
+ 'No payment -- see charging schemes')
72
+ FORBIDDEN = (403, 'Forbidden',
73
+ 'Request forbidden -- authorization will not help')
74
+ NOT_FOUND = (404, 'Not Found',
75
+ 'Nothing matches the given URI')
76
+ METHOD_NOT_ALLOWED = (405, 'Method Not Allowed',
77
+ 'Specified method is invalid for this resource')
78
+ NOT_ACCEPTABLE = (406, 'Not Acceptable',
79
+ 'URI not available in preferred format')
80
+ PROXY_AUTHENTICATION_REQUIRED = (407,
81
+ 'Proxy Authentication Required',
82
+ 'You must authenticate with this proxy before proceeding')
83
+ REQUEST_TIMEOUT = (408, 'Request Timeout',
84
+ 'Request timed out; try again later')
85
+ CONFLICT = 409, 'Conflict', 'Request conflict'
86
+ GONE = (410, 'Gone',
87
+ 'URI no longer exists and has been permanently removed')
88
+ LENGTH_REQUIRED = (411, 'Length Required',
89
+ 'Client must specify Content-Length')
90
+ PRECONDITION_FAILED = (412, 'Precondition Failed',
91
+ 'Precondition in headers is false')
92
+ REQUEST_ENTITY_TOO_LARGE = (413, 'Request Entity Too Large',
93
+ 'Entity is too large')
94
+ REQUEST_URI_TOO_LONG = (414, 'Request-URI Too Long',
95
+ 'URI is too long')
96
+ UNSUPPORTED_MEDIA_TYPE = (415, 'Unsupported Media Type',
97
+ 'Entity body in unsupported format')
98
+ REQUESTED_RANGE_NOT_SATISFIABLE = (416,
99
+ 'Requested Range Not Satisfiable',
100
+ 'Cannot satisfy request range')
101
+ EXPECTATION_FAILED = (417, 'Expectation Failed',
102
+ 'Expect condition could not be satisfied')
103
+ MISDIRECTED_REQUEST = (421, 'Misdirected Request',
104
+ 'Server is not able to produce a response')
105
+ UNPROCESSABLE_ENTITY = 422, 'Unprocessable Entity'
106
+ LOCKED = 423, 'Locked'
107
+ FAILED_DEPENDENCY = 424, 'Failed Dependency'
108
+ UPGRADE_REQUIRED = 426, 'Upgrade Required'
109
+ PRECONDITION_REQUIRED = (428, 'Precondition Required',
110
+ 'The origin server requires the request to be conditional')
111
+ TOO_MANY_REQUESTS = (429, 'Too Many Requests',
112
+ 'The user has sent too many requests in '
113
+ 'a given amount of time ("rate limiting")')
114
+ REQUEST_HEADER_FIELDS_TOO_LARGE = (431,
115
+ 'Request Header Fields Too Large',
116
+ 'The server is unwilling to process the request because its header '
117
+ 'fields are too large')
118
+ UNAVAILABLE_FOR_LEGAL_REASONS = (451,
119
+ 'Unavailable For Legal Reasons',
120
+ 'The server is denying access to the '
121
+ 'resource as a consequence of a legal demand')
122
+
123
+ # server errors
124
+ INTERNAL_SERVER_ERROR = (500, 'Internal Server Error',
125
+ 'Server got itself in trouble')
126
+ NOT_IMPLEMENTED = (501, 'Not Implemented',
127
+ 'Server does not support this operation')
128
+ BAD_GATEWAY = (502, 'Bad Gateway',
129
+ 'Invalid responses from another server/proxy')
130
+ SERVICE_UNAVAILABLE = (503, 'Service Unavailable',
131
+ 'The server cannot process the request due to a high load')
132
+ GATEWAY_TIMEOUT = (504, 'Gateway Timeout',
133
+ 'The gateway server did not receive a timely response')
134
+ HTTP_VERSION_NOT_SUPPORTED = (505, 'HTTP Version Not Supported',
135
+ 'Cannot fulfill request')
136
+ VARIANT_ALSO_NEGOTIATES = 506, 'Variant Also Negotiates'
137
+ INSUFFICIENT_STORAGE = 507, 'Insufficient Storage'
138
+ LOOP_DETECTED = 508, 'Loop Detected'
139
+ NOT_EXTENDED = 510, 'Not Extended'
140
+ NETWORK_AUTHENTICATION_REQUIRED = (511,
141
+ 'Network Authentication Required',
142
+ 'The client needs to authenticate to gain network access')
my_container_sandbox/workspace/anaconda3/lib/python3.8/http/client.py ADDED
@@ -0,0 +1,1496 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ r"""HTTP/1.1 client library
2
+
3
+ <intro stuff goes here>
4
+ <other stuff, too>
5
+
6
+ HTTPConnection goes through a number of "states", which define when a client
7
+ may legally make another request or fetch the response for a particular
8
+ request. This diagram details these state transitions:
9
+
10
+ (null)
11
+ |
12
+ | HTTPConnection()
13
+ v
14
+ Idle
15
+ |
16
+ | putrequest()
17
+ v
18
+ Request-started
19
+ |
20
+ | ( putheader() )* endheaders()
21
+ v
22
+ Request-sent
23
+ |\_____________________________
24
+ | | getresponse() raises
25
+ | response = getresponse() | ConnectionError
26
+ v v
27
+ Unread-response Idle
28
+ [Response-headers-read]
29
+ |\____________________
30
+ | |
31
+ | response.read() | putrequest()
32
+ v v
33
+ Idle Req-started-unread-response
34
+ ______/|
35
+ / |
36
+ response.read() | | ( putheader() )* endheaders()
37
+ v v
38
+ Request-started Req-sent-unread-response
39
+ |
40
+ | response.read()
41
+ v
42
+ Request-sent
43
+
44
+ This diagram presents the following rules:
45
+ -- a second request may not be started until {response-headers-read}
46
+ -- a response [object] cannot be retrieved until {request-sent}
47
+ -- there is no differentiation between an unread response body and a
48
+ partially read response body
49
+
50
+ Note: this enforcement is applied by the HTTPConnection class. The
51
+ HTTPResponse class does not enforce this state machine, which
52
+ implies sophisticated clients may accelerate the request/response
53
+ pipeline. Caution should be taken, though: accelerating the states
54
+ beyond the above pattern may imply knowledge of the server's
55
+ connection-close behavior for certain requests. For example, it
56
+ is impossible to tell whether the server will close the connection
57
+ UNTIL the response headers have been read; this means that further
58
+ requests cannot be placed into the pipeline until it is known that
59
+ the server will NOT be closing the connection.
60
+
61
+ Logical State __state __response
62
+ ------------- ------- ----------
63
+ Idle _CS_IDLE None
64
+ Request-started _CS_REQ_STARTED None
65
+ Request-sent _CS_REQ_SENT None
66
+ Unread-response _CS_IDLE <response_class>
67
+ Req-started-unread-response _CS_REQ_STARTED <response_class>
68
+ Req-sent-unread-response _CS_REQ_SENT <response_class>
69
+ """
70
+
71
+ import email.parser
72
+ import email.message
73
+ import http
74
+ import io
75
+ import re
76
+ import socket
77
+ import collections.abc
78
+ from urllib.parse import urlsplit
79
+
80
+ # HTTPMessage, parse_headers(), and the HTTP status code constants are
81
+ # intentionally omitted for simplicity
82
+ __all__ = ["HTTPResponse", "HTTPConnection",
83
+ "HTTPException", "NotConnected", "UnknownProtocol",
84
+ "UnknownTransferEncoding", "UnimplementedFileMode",
85
+ "IncompleteRead", "InvalidURL", "ImproperConnectionState",
86
+ "CannotSendRequest", "CannotSendHeader", "ResponseNotReady",
87
+ "BadStatusLine", "LineTooLong", "RemoteDisconnected", "error",
88
+ "responses"]
89
+
90
+ HTTP_PORT = 80
91
+ HTTPS_PORT = 443
92
+
93
+ _UNKNOWN = 'UNKNOWN'
94
+
95
+ # connection states
96
+ _CS_IDLE = 'Idle'
97
+ _CS_REQ_STARTED = 'Request-started'
98
+ _CS_REQ_SENT = 'Request-sent'
99
+
100
+
101
+ # hack to maintain backwards compatibility
102
+ globals().update(http.HTTPStatus.__members__)
103
+
104
+ # another hack to maintain backwards compatibility
105
+ # Mapping status codes to official W3C names
106
+ responses = {v: v.phrase for v in http.HTTPStatus.__members__.values()}
107
+
108
+ # maximal line length when calling readline().
109
+ _MAXLINE = 65536
110
+ _MAXHEADERS = 100
111
+
112
+ # Header name/value ABNF (http://tools.ietf.org/html/rfc7230#section-3.2)
113
+ #
114
+ # VCHAR = %x21-7E
115
+ # obs-text = %x80-FF
116
+ # header-field = field-name ":" OWS field-value OWS
117
+ # field-name = token
118
+ # field-value = *( field-content / obs-fold )
119
+ # field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]
120
+ # field-vchar = VCHAR / obs-text
121
+ #
122
+ # obs-fold = CRLF 1*( SP / HTAB )
123
+ # ; obsolete line folding
124
+ # ; see Section 3.2.4
125
+
126
+ # token = 1*tchar
127
+ #
128
+ # tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*"
129
+ # / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~"
130
+ # / DIGIT / ALPHA
131
+ # ; any VCHAR, except delimiters
132
+ #
133
+ # VCHAR defined in http://tools.ietf.org/html/rfc5234#appendix-B.1
134
+
135
+ # the patterns for both name and value are more lenient than RFC
136
+ # definitions to allow for backwards compatibility
137
+ _is_legal_header_name = re.compile(rb'[^:\s][^:\r\n]*').fullmatch
138
+ _is_illegal_header_value = re.compile(rb'\n(?![ \t])|\r(?![ \t\n])').search
139
+
140
+ # These characters are not allowed within HTTP URL paths.
141
+ # See https://tools.ietf.org/html/rfc3986#section-3.3 and the
142
+ # https://tools.ietf.org/html/rfc3986#appendix-A pchar definition.
143
+ # Prevents CVE-2019-9740. Includes control characters such as \r\n.
144
+ # We don't restrict chars above \x7f as putrequest() limits us to ASCII.
145
+ _contains_disallowed_url_pchar_re = re.compile('[\x00-\x20\x7f]')
146
+ # Arguably only these _should_ allowed:
147
+ # _is_allowed_url_pchars_re = re.compile(r"^[/!$&'()*+,;=:@%a-zA-Z0-9._~-]+$")
148
+ # We are more lenient for assumed real world compatibility purposes.
149
+
150
+ # These characters are not allowed within HTTP method names
151
+ # to prevent http header injection.
152
+ _contains_disallowed_method_pchar_re = re.compile('[\x00-\x1f]')
153
+
154
+ # We always set the Content-Length header for these methods because some
155
+ # servers will otherwise respond with a 411
156
+ _METHODS_EXPECTING_BODY = {'PATCH', 'POST', 'PUT'}
157
+
158
+
159
+ def _encode(data, name='data'):
160
+ """Call data.encode("latin-1") but show a better error message."""
161
+ try:
162
+ return data.encode("latin-1")
163
+ except UnicodeEncodeError as err:
164
+ raise UnicodeEncodeError(
165
+ err.encoding,
166
+ err.object,
167
+ err.start,
168
+ err.end,
169
+ "%s (%.20r) is not valid Latin-1. Use %s.encode('utf-8') "
170
+ "if you want to send it encoded in UTF-8." %
171
+ (name.title(), data[err.start:err.end], name)) from None
172
+
173
+
174
+ class HTTPMessage(email.message.Message):
175
+ # XXX The only usage of this method is in
176
+ # http.server.CGIHTTPRequestHandler. Maybe move the code there so
177
+ # that it doesn't need to be part of the public API. The API has
178
+ # never been defined so this could cause backwards compatibility
179
+ # issues.
180
+
181
+ def getallmatchingheaders(self, name):
182
+ """Find all header lines matching a given header name.
183
+
184
+ Look through the list of headers and find all lines matching a given
185
+ header name (and their continuation lines). A list of the lines is
186
+ returned, without interpretation. If the header does not occur, an
187
+ empty list is returned. If the header occurs multiple times, all
188
+ occurrences are returned. Case is not important in the header name.
189
+
190
+ """
191
+ name = name.lower() + ':'
192
+ n = len(name)
193
+ lst = []
194
+ hit = 0
195
+ for line in self.keys():
196
+ if line[:n].lower() == name:
197
+ hit = 1
198
+ elif not line[:1].isspace():
199
+ hit = 0
200
+ if hit:
201
+ lst.append(line)
202
+ return lst
203
+
204
+ def _read_headers(fp):
205
+ """Reads potential header lines into a list from a file pointer.
206
+
207
+ Length of line is limited by _MAXLINE, and number of
208
+ headers is limited by _MAXHEADERS.
209
+ """
210
+ headers = []
211
+ while True:
212
+ line = fp.readline(_MAXLINE + 1)
213
+ if len(line) > _MAXLINE:
214
+ raise LineTooLong("header line")
215
+ headers.append(line)
216
+ if len(headers) > _MAXHEADERS:
217
+ raise HTTPException("got more than %d headers" % _MAXHEADERS)
218
+ if line in (b'\r\n', b'\n', b''):
219
+ break
220
+ return headers
221
+
222
+ def parse_headers(fp, _class=HTTPMessage):
223
+ """Parses only RFC2822 headers from a file pointer.
224
+
225
+ email Parser wants to see strings rather than bytes.
226
+ But a TextIOWrapper around self.rfile would buffer too many bytes
227
+ from the stream, bytes which we later need to read as bytes.
228
+ So we read the correct bytes here, as bytes, for email Parser
229
+ to parse.
230
+
231
+ """
232
+ headers = _read_headers(fp)
233
+ hstring = b''.join(headers).decode('iso-8859-1')
234
+ return email.parser.Parser(_class=_class).parsestr(hstring)
235
+
236
+
237
+ class HTTPResponse(io.BufferedIOBase):
238
+
239
+ # See RFC 2616 sec 19.6 and RFC 1945 sec 6 for details.
240
+
241
+ # The bytes from the socket object are iso-8859-1 strings.
242
+ # See RFC 2616 sec 2.2 which notes an exception for MIME-encoded
243
+ # text following RFC 2047. The basic status line parsing only
244
+ # accepts iso-8859-1.
245
+
246
+ def __init__(self, sock, debuglevel=0, method=None, url=None):
247
+ # If the response includes a content-length header, we need to
248
+ # make sure that the client doesn't read more than the
249
+ # specified number of bytes. If it does, it will block until
250
+ # the server times out and closes the connection. This will
251
+ # happen if a self.fp.read() is done (without a size) whether
252
+ # self.fp is buffered or not. So, no self.fp.read() by
253
+ # clients unless they know what they are doing.
254
+ self.fp = sock.makefile("rb")
255
+ self.debuglevel = debuglevel
256
+ self._method = method
257
+
258
+ # The HTTPResponse object is returned via urllib. The clients
259
+ # of http and urllib expect different attributes for the
260
+ # headers. headers is used here and supports urllib. msg is
261
+ # provided as a backwards compatibility layer for http
262
+ # clients.
263
+
264
+ self.headers = self.msg = None
265
+
266
+ # from the Status-Line of the response
267
+ self.version = _UNKNOWN # HTTP-Version
268
+ self.status = _UNKNOWN # Status-Code
269
+ self.reason = _UNKNOWN # Reason-Phrase
270
+
271
+ self.chunked = _UNKNOWN # is "chunked" being used?
272
+ self.chunk_left = _UNKNOWN # bytes left to read in current chunk
273
+ self.length = _UNKNOWN # number of bytes left in response
274
+ self.will_close = _UNKNOWN # conn will close at end of response
275
+
276
+ def _read_status(self):
277
+ line = str(self.fp.readline(_MAXLINE + 1), "iso-8859-1")
278
+ if len(line) > _MAXLINE:
279
+ raise LineTooLong("status line")
280
+ if self.debuglevel > 0:
281
+ print("reply:", repr(line))
282
+ if not line:
283
+ # Presumably, the server closed the connection before
284
+ # sending a valid response.
285
+ raise RemoteDisconnected("Remote end closed connection without"
286
+ " response")
287
+ try:
288
+ version, status, reason = line.split(None, 2)
289
+ except ValueError:
290
+ try:
291
+ version, status = line.split(None, 1)
292
+ reason = ""
293
+ except ValueError:
294
+ # empty version will cause next test to fail.
295
+ version = ""
296
+ if not version.startswith("HTTP/"):
297
+ self._close_conn()
298
+ raise BadStatusLine(line)
299
+
300
+ # The status code is a three-digit number
301
+ try:
302
+ status = int(status)
303
+ if status < 100 or status > 999:
304
+ raise BadStatusLine(line)
305
+ except ValueError:
306
+ raise BadStatusLine(line)
307
+ return version, status, reason
308
+
309
+ def begin(self):
310
+ if self.headers is not None:
311
+ # we've already started reading the response
312
+ return
313
+
314
+ # read until we get a non-100 response
315
+ while True:
316
+ version, status, reason = self._read_status()
317
+ if status != CONTINUE:
318
+ break
319
+ # skip the header from the 100 response
320
+ skipped_headers = _read_headers(self.fp)
321
+ if self.debuglevel > 0:
322
+ print("headers:", skipped_headers)
323
+ del skipped_headers
324
+
325
+ self.code = self.status = status
326
+ self.reason = reason.strip()
327
+ if version in ("HTTP/1.0", "HTTP/0.9"):
328
+ # Some servers might still return "0.9", treat it as 1.0 anyway
329
+ self.version = 10
330
+ elif version.startswith("HTTP/1."):
331
+ self.version = 11 # use HTTP/1.1 code for HTTP/1.x where x>=1
332
+ else:
333
+ raise UnknownProtocol(version)
334
+
335
+ self.headers = self.msg = parse_headers(self.fp)
336
+
337
+ if self.debuglevel > 0:
338
+ for hdr, val in self.headers.items():
339
+ print("header:", hdr + ":", val)
340
+
341
+ # are we using the chunked-style of transfer encoding?
342
+ tr_enc = self.headers.get("transfer-encoding")
343
+ if tr_enc and tr_enc.lower() == "chunked":
344
+ self.chunked = True
345
+ self.chunk_left = None
346
+ else:
347
+ self.chunked = False
348
+
349
+ # will the connection close at the end of the response?
350
+ self.will_close = self._check_close()
351
+
352
+ # do we have a Content-Length?
353
+ # NOTE: RFC 2616, S4.4, #3 says we ignore this if tr_enc is "chunked"
354
+ self.length = None
355
+ length = self.headers.get("content-length")
356
+ if length and not self.chunked:
357
+ try:
358
+ self.length = int(length)
359
+ except ValueError:
360
+ self.length = None
361
+ else:
362
+ if self.length < 0: # ignore nonsensical negative lengths
363
+ self.length = None
364
+ else:
365
+ self.length = None
366
+
367
+ # does the body have a fixed length? (of zero)
368
+ if (status == NO_CONTENT or status == NOT_MODIFIED or
369
+ 100 <= status < 200 or # 1xx codes
370
+ self._method == "HEAD"):
371
+ self.length = 0
372
+
373
+ # if the connection remains open, and we aren't using chunked, and
374
+ # a content-length was not provided, then assume that the connection
375
+ # WILL close.
376
+ if (not self.will_close and
377
+ not self.chunked and
378
+ self.length is None):
379
+ self.will_close = True
380
+
381
+ def _check_close(self):
382
+ conn = self.headers.get("connection")
383
+ if self.version == 11:
384
+ # An HTTP/1.1 proxy is assumed to stay open unless
385
+ # explicitly closed.
386
+ if conn and "close" in conn.lower():
387
+ return True
388
+ return False
389
+
390
+ # Some HTTP/1.0 implementations have support for persistent
391
+ # connections, using rules different than HTTP/1.1.
392
+
393
+ # For older HTTP, Keep-Alive indicates persistent connection.
394
+ if self.headers.get("keep-alive"):
395
+ return False
396
+
397
+ # At least Akamai returns a "Connection: Keep-Alive" header,
398
+ # which was supposed to be sent by the client.
399
+ if conn and "keep-alive" in conn.lower():
400
+ return False
401
+
402
+ # Proxy-Connection is a netscape hack.
403
+ pconn = self.headers.get("proxy-connection")
404
+ if pconn and "keep-alive" in pconn.lower():
405
+ return False
406
+
407
+ # otherwise, assume it will close
408
+ return True
409
+
410
+ def _close_conn(self):
411
+ fp = self.fp
412
+ self.fp = None
413
+ fp.close()
414
+
415
+ def close(self):
416
+ try:
417
+ super().close() # set "closed" flag
418
+ finally:
419
+ if self.fp:
420
+ self._close_conn()
421
+
422
+ # These implementations are for the benefit of io.BufferedReader.
423
+
424
+ # XXX This class should probably be revised to act more like
425
+ # the "raw stream" that BufferedReader expects.
426
+
427
+ def flush(self):
428
+ super().flush()
429
+ if self.fp:
430
+ self.fp.flush()
431
+
432
+ def readable(self):
433
+ """Always returns True"""
434
+ return True
435
+
436
+ # End of "raw stream" methods
437
+
438
+ def isclosed(self):
439
+ """True if the connection is closed."""
440
+ # NOTE: it is possible that we will not ever call self.close(). This
441
+ # case occurs when will_close is TRUE, length is None, and we
442
+ # read up to the last byte, but NOT past it.
443
+ #
444
+ # IMPLIES: if will_close is FALSE, then self.close() will ALWAYS be
445
+ # called, meaning self.isclosed() is meaningful.
446
+ return self.fp is None
447
+
448
+ def read(self, amt=None):
449
+ if self.fp is None:
450
+ return b""
451
+
452
+ if self._method == "HEAD":
453
+ self._close_conn()
454
+ return b""
455
+
456
+ if amt is not None:
457
+ # Amount is given, implement using readinto
458
+ b = bytearray(amt)
459
+ n = self.readinto(b)
460
+ return memoryview(b)[:n].tobytes()
461
+ else:
462
+ # Amount is not given (unbounded read) so we must check self.length
463
+ # and self.chunked
464
+
465
+ if self.chunked:
466
+ return self._readall_chunked()
467
+
468
+ if self.length is None:
469
+ s = self.fp.read()
470
+ else:
471
+ try:
472
+ s = self._safe_read(self.length)
473
+ except IncompleteRead:
474
+ self._close_conn()
475
+ raise
476
+ self.length = 0
477
+ self._close_conn() # we read everything
478
+ return s
479
+
480
+ def readinto(self, b):
481
+ """Read up to len(b) bytes into bytearray b and return the number
482
+ of bytes read.
483
+ """
484
+
485
+ if self.fp is None:
486
+ return 0
487
+
488
+ if self._method == "HEAD":
489
+ self._close_conn()
490
+ return 0
491
+
492
+ if self.chunked:
493
+ return self._readinto_chunked(b)
494
+
495
+ if self.length is not None:
496
+ if len(b) > self.length:
497
+ # clip the read to the "end of response"
498
+ b = memoryview(b)[0:self.length]
499
+
500
+ # we do not use _safe_read() here because this may be a .will_close
501
+ # connection, and the user is reading more bytes than will be provided
502
+ # (for example, reading in 1k chunks)
503
+ n = self.fp.readinto(b)
504
+ if not n and b:
505
+ # Ideally, we would raise IncompleteRead if the content-length
506
+ # wasn't satisfied, but it might break compatibility.
507
+ self._close_conn()
508
+ elif self.length is not None:
509
+ self.length -= n
510
+ if not self.length:
511
+ self._close_conn()
512
+ return n
513
+
514
+ def _read_next_chunk_size(self):
515
+ # Read the next chunk size from the file
516
+ line = self.fp.readline(_MAXLINE + 1)
517
+ if len(line) > _MAXLINE:
518
+ raise LineTooLong("chunk size")
519
+ i = line.find(b";")
520
+ if i >= 0:
521
+ line = line[:i] # strip chunk-extensions
522
+ try:
523
+ return int(line, 16)
524
+ except ValueError:
525
+ # close the connection as protocol synchronisation is
526
+ # probably lost
527
+ self._close_conn()
528
+ raise
529
+
530
+ def _read_and_discard_trailer(self):
531
+ # read and discard trailer up to the CRLF terminator
532
+ ### note: we shouldn't have any trailers!
533
+ while True:
534
+ line = self.fp.readline(_MAXLINE + 1)
535
+ if len(line) > _MAXLINE:
536
+ raise LineTooLong("trailer line")
537
+ if not line:
538
+ # a vanishingly small number of sites EOF without
539
+ # sending the trailer
540
+ break
541
+ if line in (b'\r\n', b'\n', b''):
542
+ break
543
+
544
+ def _get_chunk_left(self):
545
+ # return self.chunk_left, reading a new chunk if necessary.
546
+ # chunk_left == 0: at the end of the current chunk, need to close it
547
+ # chunk_left == None: No current chunk, should read next.
548
+ # This function returns non-zero or None if the last chunk has
549
+ # been read.
550
+ chunk_left = self.chunk_left
551
+ if not chunk_left: # Can be 0 or None
552
+ if chunk_left is not None:
553
+ # We are at the end of chunk, discard chunk end
554
+ self._safe_read(2) # toss the CRLF at the end of the chunk
555
+ try:
556
+ chunk_left = self._read_next_chunk_size()
557
+ except ValueError:
558
+ raise IncompleteRead(b'')
559
+ if chunk_left == 0:
560
+ # last chunk: 1*("0") [ chunk-extension ] CRLF
561
+ self._read_and_discard_trailer()
562
+ # we read everything; close the "file"
563
+ self._close_conn()
564
+ chunk_left = None
565
+ self.chunk_left = chunk_left
566
+ return chunk_left
567
+
568
+ def _readall_chunked(self):
569
+ assert self.chunked != _UNKNOWN
570
+ value = []
571
+ try:
572
+ while True:
573
+ chunk_left = self._get_chunk_left()
574
+ if chunk_left is None:
575
+ break
576
+ value.append(self._safe_read(chunk_left))
577
+ self.chunk_left = 0
578
+ return b''.join(value)
579
+ except IncompleteRead:
580
+ raise IncompleteRead(b''.join(value))
581
+
582
+ def _readinto_chunked(self, b):
583
+ assert self.chunked != _UNKNOWN
584
+ total_bytes = 0
585
+ mvb = memoryview(b)
586
+ try:
587
+ while True:
588
+ chunk_left = self._get_chunk_left()
589
+ if chunk_left is None:
590
+ return total_bytes
591
+
592
+ if len(mvb) <= chunk_left:
593
+ n = self._safe_readinto(mvb)
594
+ self.chunk_left = chunk_left - n
595
+ return total_bytes + n
596
+
597
+ temp_mvb = mvb[:chunk_left]
598
+ n = self._safe_readinto(temp_mvb)
599
+ mvb = mvb[n:]
600
+ total_bytes += n
601
+ self.chunk_left = 0
602
+
603
+ except IncompleteRead:
604
+ raise IncompleteRead(bytes(b[0:total_bytes]))
605
+
606
+ def _safe_read(self, amt):
607
+ """Read the number of bytes requested.
608
+
609
+ This function should be used when <amt> bytes "should" be present for
610
+ reading. If the bytes are truly not available (due to EOF), then the
611
+ IncompleteRead exception can be used to detect the problem.
612
+ """
613
+ data = self.fp.read(amt)
614
+ if len(data) < amt:
615
+ raise IncompleteRead(data, amt-len(data))
616
+ return data
617
+
618
+ def _safe_readinto(self, b):
619
+ """Same as _safe_read, but for reading into a buffer."""
620
+ amt = len(b)
621
+ n = self.fp.readinto(b)
622
+ if n < amt:
623
+ raise IncompleteRead(bytes(b[:n]), amt-n)
624
+ return n
625
+
626
+ def read1(self, n=-1):
627
+ """Read with at most one underlying system call. If at least one
628
+ byte is buffered, return that instead.
629
+ """
630
+ if self.fp is None or self._method == "HEAD":
631
+ return b""
632
+ if self.chunked:
633
+ return self._read1_chunked(n)
634
+ if self.length is not None and (n < 0 or n > self.length):
635
+ n = self.length
636
+ result = self.fp.read1(n)
637
+ if not result and n:
638
+ self._close_conn()
639
+ elif self.length is not None:
640
+ self.length -= len(result)
641
+ return result
642
+
643
+ def peek(self, n=-1):
644
+ # Having this enables IOBase.readline() to read more than one
645
+ # byte at a time
646
+ if self.fp is None or self._method == "HEAD":
647
+ return b""
648
+ if self.chunked:
649
+ return self._peek_chunked(n)
650
+ return self.fp.peek(n)
651
+
652
+ def readline(self, limit=-1):
653
+ if self.fp is None or self._method == "HEAD":
654
+ return b""
655
+ if self.chunked:
656
+ # Fallback to IOBase readline which uses peek() and read()
657
+ return super().readline(limit)
658
+ if self.length is not None and (limit < 0 or limit > self.length):
659
+ limit = self.length
660
+ result = self.fp.readline(limit)
661
+ if not result and limit:
662
+ self._close_conn()
663
+ elif self.length is not None:
664
+ self.length -= len(result)
665
+ return result
666
+
667
+ def _read1_chunked(self, n):
668
+ # Strictly speaking, _get_chunk_left() may cause more than one read,
669
+ # but that is ok, since that is to satisfy the chunked protocol.
670
+ chunk_left = self._get_chunk_left()
671
+ if chunk_left is None or n == 0:
672
+ return b''
673
+ if not (0 <= n <= chunk_left):
674
+ n = chunk_left # if n is negative or larger than chunk_left
675
+ read = self.fp.read1(n)
676
+ self.chunk_left -= len(read)
677
+ if not read:
678
+ raise IncompleteRead(b"")
679
+ return read
680
+
681
+ def _peek_chunked(self, n):
682
+ # Strictly speaking, _get_chunk_left() may cause more than one read,
683
+ # but that is ok, since that is to satisfy the chunked protocol.
684
+ try:
685
+ chunk_left = self._get_chunk_left()
686
+ except IncompleteRead:
687
+ return b'' # peek doesn't worry about protocol
688
+ if chunk_left is None:
689
+ return b'' # eof
690
+ # peek is allowed to return more than requested. Just request the
691
+ # entire chunk, and truncate what we get.
692
+ return self.fp.peek(chunk_left)[:chunk_left]
693
+
694
+ def fileno(self):
695
+ return self.fp.fileno()
696
+
697
+ def getheader(self, name, default=None):
698
+ '''Returns the value of the header matching *name*.
699
+
700
+ If there are multiple matching headers, the values are
701
+ combined into a single string separated by commas and spaces.
702
+
703
+ If no matching header is found, returns *default* or None if
704
+ the *default* is not specified.
705
+
706
+ If the headers are unknown, raises http.client.ResponseNotReady.
707
+
708
+ '''
709
+ if self.headers is None:
710
+ raise ResponseNotReady()
711
+ headers = self.headers.get_all(name) or default
712
+ if isinstance(headers, str) or not hasattr(headers, '__iter__'):
713
+ return headers
714
+ else:
715
+ return ', '.join(headers)
716
+
717
+ def getheaders(self):
718
+ """Return list of (header, value) tuples."""
719
+ if self.headers is None:
720
+ raise ResponseNotReady()
721
+ return list(self.headers.items())
722
+
723
+ # We override IOBase.__iter__ so that it doesn't check for closed-ness
724
+
725
+ def __iter__(self):
726
+ return self
727
+
728
+ # For compatibility with old-style urllib responses.
729
+
730
+ def info(self):
731
+ '''Returns an instance of the class mimetools.Message containing
732
+ meta-information associated with the URL.
733
+
734
+ When the method is HTTP, these headers are those returned by
735
+ the server at the head of the retrieved HTML page (including
736
+ Content-Length and Content-Type).
737
+
738
+ When the method is FTP, a Content-Length header will be
739
+ present if (as is now usual) the server passed back a file
740
+ length in response to the FTP retrieval request. A
741
+ Content-Type header will be present if the MIME type can be
742
+ guessed.
743
+
744
+ When the method is local-file, returned headers will include
745
+ a Date representing the file's last-modified time, a
746
+ Content-Length giving file size, and a Content-Type
747
+ containing a guess at the file's type. See also the
748
+ description of the mimetools module.
749
+
750
+ '''
751
+ return self.headers
752
+
753
+ def geturl(self):
754
+ '''Return the real URL of the page.
755
+
756
+ In some cases, the HTTP server redirects a client to another
757
+ URL. The urlopen() function handles this transparently, but in
758
+ some cases the caller needs to know which URL the client was
759
+ redirected to. The geturl() method can be used to get at this
760
+ redirected URL.
761
+
762
+ '''
763
+ return self.url
764
+
765
+ def getcode(self):
766
+ '''Return the HTTP status code that was sent with the response,
767
+ or None if the URL is not an HTTP URL.
768
+
769
+ '''
770
+ return self.status
771
+
772
+ class HTTPConnection:
773
+
774
+ _http_vsn = 11
775
+ _http_vsn_str = 'HTTP/1.1'
776
+
777
+ response_class = HTTPResponse
778
+ default_port = HTTP_PORT
779
+ auto_open = 1
780
+ debuglevel = 0
781
+
782
+ @staticmethod
783
+ def _is_textIO(stream):
784
+ """Test whether a file-like object is a text or a binary stream.
785
+ """
786
+ return isinstance(stream, io.TextIOBase)
787
+
788
+ @staticmethod
789
+ def _get_content_length(body, method):
790
+ """Get the content-length based on the body.
791
+
792
+ If the body is None, we set Content-Length: 0 for methods that expect
793
+ a body (RFC 7230, Section 3.3.2). We also set the Content-Length for
794
+ any method if the body is a str or bytes-like object and not a file.
795
+ """
796
+ if body is None:
797
+ # do an explicit check for not None here to distinguish
798
+ # between unset and set but empty
799
+ if method.upper() in _METHODS_EXPECTING_BODY:
800
+ return 0
801
+ else:
802
+ return None
803
+
804
+ if hasattr(body, 'read'):
805
+ # file-like object.
806
+ return None
807
+
808
+ try:
809
+ # does it implement the buffer protocol (bytes, bytearray, array)?
810
+ mv = memoryview(body)
811
+ return mv.nbytes
812
+ except TypeError:
813
+ pass
814
+
815
+ if isinstance(body, str):
816
+ return len(body)
817
+
818
+ return None
819
+
820
+ def __init__(self, host, port=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT,
821
+ source_address=None, blocksize=8192):
822
+ self.timeout = timeout
823
+ self.source_address = source_address
824
+ self.blocksize = blocksize
825
+ self.sock = None
826
+ self._buffer = []
827
+ self.__response = None
828
+ self.__state = _CS_IDLE
829
+ self._method = None
830
+ self._tunnel_host = None
831
+ self._tunnel_port = None
832
+ self._tunnel_headers = {}
833
+
834
+ (self.host, self.port) = self._get_hostport(host, port)
835
+
836
+ self._validate_host(self.host)
837
+
838
+ # This is stored as an instance variable to allow unit
839
+ # tests to replace it with a suitable mockup
840
+ self._create_connection = socket.create_connection
841
+
842
+ def set_tunnel(self, host, port=None, headers=None):
843
+ """Set up host and port for HTTP CONNECT tunnelling.
844
+
845
+ In a connection that uses HTTP CONNECT tunneling, the host passed to the
846
+ constructor is used as a proxy server that relays all communication to
847
+ the endpoint passed to `set_tunnel`. This done by sending an HTTP
848
+ CONNECT request to the proxy server when the connection is established.
849
+
850
+ This method must be called before the HTTP connection has been
851
+ established.
852
+
853
+ The headers argument should be a mapping of extra HTTP headers to send
854
+ with the CONNECT request.
855
+ """
856
+
857
+ if self.sock:
858
+ raise RuntimeError("Can't set up tunnel for established connection")
859
+
860
+ self._tunnel_host, self._tunnel_port = self._get_hostport(host, port)
861
+ if headers:
862
+ self._tunnel_headers = headers
863
+ else:
864
+ self._tunnel_headers.clear()
865
+
866
+ def _get_hostport(self, host, port):
867
+ if port is None:
868
+ i = host.rfind(':')
869
+ j = host.rfind(']') # ipv6 addresses have [...]
870
+ if i > j:
871
+ try:
872
+ port = int(host[i+1:])
873
+ except ValueError:
874
+ if host[i+1:] == "": # http://foo.com:/ == http://foo.com/
875
+ port = self.default_port
876
+ else:
877
+ raise InvalidURL("nonnumeric port: '%s'" % host[i+1:])
878
+ host = host[:i]
879
+ else:
880
+ port = self.default_port
881
+ if host and host[0] == '[' and host[-1] == ']':
882
+ host = host[1:-1]
883
+
884
+ return (host, port)
885
+
886
+ def set_debuglevel(self, level):
887
+ self.debuglevel = level
888
+
889
+ def _tunnel(self):
890
+ connect_str = "CONNECT %s:%d HTTP/1.0\r\n" % (self._tunnel_host,
891
+ self._tunnel_port)
892
+ connect_bytes = connect_str.encode("ascii")
893
+ self.send(connect_bytes)
894
+ for header, value in self._tunnel_headers.items():
895
+ header_str = "%s: %s\r\n" % (header, value)
896
+ header_bytes = header_str.encode("latin-1")
897
+ self.send(header_bytes)
898
+ self.send(b'\r\n')
899
+
900
+ response = self.response_class(self.sock, method=self._method)
901
+ (version, code, message) = response._read_status()
902
+
903
+ if code != http.HTTPStatus.OK:
904
+ self.close()
905
+ raise OSError("Tunnel connection failed: %d %s" % (code,
906
+ message.strip()))
907
+ while True:
908
+ line = response.fp.readline(_MAXLINE + 1)
909
+ if len(line) > _MAXLINE:
910
+ raise LineTooLong("header line")
911
+ if not line:
912
+ # for sites which EOF without sending a trailer
913
+ break
914
+ if line in (b'\r\n', b'\n', b''):
915
+ break
916
+
917
+ if self.debuglevel > 0:
918
+ print('header:', line.decode())
919
+
920
+ def connect(self):
921
+ """Connect to the host and port specified in __init__."""
922
+ self.sock = self._create_connection(
923
+ (self.host,self.port), self.timeout, self.source_address)
924
+ self.sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
925
+
926
+ if self._tunnel_host:
927
+ self._tunnel()
928
+
929
+ def close(self):
930
+ """Close the connection to the HTTP server."""
931
+ self.__state = _CS_IDLE
932
+ try:
933
+ sock = self.sock
934
+ if sock:
935
+ self.sock = None
936
+ sock.close() # close it manually... there may be other refs
937
+ finally:
938
+ response = self.__response
939
+ if response:
940
+ self.__response = None
941
+ response.close()
942
+
943
+ def send(self, data):
944
+ """Send `data' to the server.
945
+ ``data`` can be a string object, a bytes object, an array object, a
946
+ file-like object that supports a .read() method, or an iterable object.
947
+ """
948
+
949
+ if self.sock is None:
950
+ if self.auto_open:
951
+ self.connect()
952
+ else:
953
+ raise NotConnected()
954
+
955
+ if self.debuglevel > 0:
956
+ print("send:", repr(data))
957
+ if hasattr(data, "read") :
958
+ if self.debuglevel > 0:
959
+ print("sendIng a read()able")
960
+ encode = self._is_textIO(data)
961
+ if encode and self.debuglevel > 0:
962
+ print("encoding file using iso-8859-1")
963
+ while 1:
964
+ datablock = data.read(self.blocksize)
965
+ if not datablock:
966
+ break
967
+ if encode:
968
+ datablock = datablock.encode("iso-8859-1")
969
+ self.sock.sendall(datablock)
970
+ return
971
+ try:
972
+ self.sock.sendall(data)
973
+ except TypeError:
974
+ if isinstance(data, collections.abc.Iterable):
975
+ for d in data:
976
+ self.sock.sendall(d)
977
+ else:
978
+ raise TypeError("data should be a bytes-like object "
979
+ "or an iterable, got %r" % type(data))
980
+
981
+ def _output(self, s):
982
+ """Add a line of output to the current request buffer.
983
+
984
+ Assumes that the line does *not* end with \\r\\n.
985
+ """
986
+ self._buffer.append(s)
987
+
988
+ def _read_readable(self, readable):
989
+ if self.debuglevel > 0:
990
+ print("sendIng a read()able")
991
+ encode = self._is_textIO(readable)
992
+ if encode and self.debuglevel > 0:
993
+ print("encoding file using iso-8859-1")
994
+ while True:
995
+ datablock = readable.read(self.blocksize)
996
+ if not datablock:
997
+ break
998
+ if encode:
999
+ datablock = datablock.encode("iso-8859-1")
1000
+ yield datablock
1001
+
1002
+ def _send_output(self, message_body=None, encode_chunked=False):
1003
+ """Send the currently buffered request and clear the buffer.
1004
+
1005
+ Appends an extra \\r\\n to the buffer.
1006
+ A message_body may be specified, to be appended to the request.
1007
+ """
1008
+ self._buffer.extend((b"", b""))
1009
+ msg = b"\r\n".join(self._buffer)
1010
+ del self._buffer[:]
1011
+ self.send(msg)
1012
+
1013
+ if message_body is not None:
1014
+
1015
+ # create a consistent interface to message_body
1016
+ if hasattr(message_body, 'read'):
1017
+ # Let file-like take precedence over byte-like. This
1018
+ # is needed to allow the current position of mmap'ed
1019
+ # files to be taken into account.
1020
+ chunks = self._read_readable(message_body)
1021
+ else:
1022
+ try:
1023
+ # this is solely to check to see if message_body
1024
+ # implements the buffer API. it /would/ be easier
1025
+ # to capture if PyObject_CheckBuffer was exposed
1026
+ # to Python.
1027
+ memoryview(message_body)
1028
+ except TypeError:
1029
+ try:
1030
+ chunks = iter(message_body)
1031
+ except TypeError:
1032
+ raise TypeError("message_body should be a bytes-like "
1033
+ "object or an iterable, got %r"
1034
+ % type(message_body))
1035
+ else:
1036
+ # the object implements the buffer interface and
1037
+ # can be passed directly into socket methods
1038
+ chunks = (message_body,)
1039
+
1040
+ for chunk in chunks:
1041
+ if not chunk:
1042
+ if self.debuglevel > 0:
1043
+ print('Zero length chunk ignored')
1044
+ continue
1045
+
1046
+ if encode_chunked and self._http_vsn == 11:
1047
+ # chunked encoding
1048
+ chunk = f'{len(chunk):X}\r\n'.encode('ascii') + chunk \
1049
+ + b'\r\n'
1050
+ self.send(chunk)
1051
+
1052
+ if encode_chunked and self._http_vsn == 11:
1053
+ # end chunked transfer
1054
+ self.send(b'0\r\n\r\n')
1055
+
1056
+ def putrequest(self, method, url, skip_host=False,
1057
+ skip_accept_encoding=False):
1058
+ """Send a request to the server.
1059
+
1060
+ `method' specifies an HTTP request method, e.g. 'GET'.
1061
+ `url' specifies the object being requested, e.g. '/index.html'.
1062
+ `skip_host' if True does not add automatically a 'Host:' header
1063
+ `skip_accept_encoding' if True does not add automatically an
1064
+ 'Accept-Encoding:' header
1065
+ """
1066
+
1067
+ # if a prior response has been completed, then forget about it.
1068
+ if self.__response and self.__response.isclosed():
1069
+ self.__response = None
1070
+
1071
+
1072
+ # in certain cases, we cannot issue another request on this connection.
1073
+ # this occurs when:
1074
+ # 1) we are in the process of sending a request. (_CS_REQ_STARTED)
1075
+ # 2) a response to a previous request has signalled that it is going
1076
+ # to close the connection upon completion.
1077
+ # 3) the headers for the previous response have not been read, thus
1078
+ # we cannot determine whether point (2) is true. (_CS_REQ_SENT)
1079
+ #
1080
+ # if there is no prior response, then we can request at will.
1081
+ #
1082
+ # if point (2) is true, then we will have passed the socket to the
1083
+ # response (effectively meaning, "there is no prior response"), and
1084
+ # will open a new one when a new request is made.
1085
+ #
1086
+ # Note: if a prior response exists, then we *can* start a new request.
1087
+ # We are not allowed to begin fetching the response to this new
1088
+ # request, however, until that prior response is complete.
1089
+ #
1090
+ if self.__state == _CS_IDLE:
1091
+ self.__state = _CS_REQ_STARTED
1092
+ else:
1093
+ raise CannotSendRequest(self.__state)
1094
+
1095
+ self._validate_method(method)
1096
+
1097
+ # Save the method for use later in the response phase
1098
+ self._method = method
1099
+
1100
+ url = url or '/'
1101
+ self._validate_path(url)
1102
+
1103
+ request = '%s %s %s' % (method, url, self._http_vsn_str)
1104
+
1105
+ self._output(self._encode_request(request))
1106
+
1107
+ if self._http_vsn == 11:
1108
+ # Issue some standard headers for better HTTP/1.1 compliance
1109
+
1110
+ if not skip_host:
1111
+ # this header is issued *only* for HTTP/1.1
1112
+ # connections. more specifically, this means it is
1113
+ # only issued when the client uses the new
1114
+ # HTTPConnection() class. backwards-compat clients
1115
+ # will be using HTTP/1.0 and those clients may be
1116
+ # issuing this header themselves. we should NOT issue
1117
+ # it twice; some web servers (such as Apache) barf
1118
+ # when they see two Host: headers
1119
+
1120
+ # If we need a non-standard port,include it in the
1121
+ # header. If the request is going through a proxy,
1122
+ # but the host of the actual URL, not the host of the
1123
+ # proxy.
1124
+
1125
+ netloc = ''
1126
+ if url.startswith('http'):
1127
+ nil, netloc, nil, nil, nil = urlsplit(url)
1128
+
1129
+ if netloc:
1130
+ try:
1131
+ netloc_enc = netloc.encode("ascii")
1132
+ except UnicodeEncodeError:
1133
+ netloc_enc = netloc.encode("idna")
1134
+ self.putheader('Host', netloc_enc)
1135
+ else:
1136
+ if self._tunnel_host:
1137
+ host = self._tunnel_host
1138
+ port = self._tunnel_port
1139
+ else:
1140
+ host = self.host
1141
+ port = self.port
1142
+
1143
+ try:
1144
+ host_enc = host.encode("ascii")
1145
+ except UnicodeEncodeError:
1146
+ host_enc = host.encode("idna")
1147
+
1148
+ # As per RFC 273, IPv6 address should be wrapped with []
1149
+ # when used as Host header
1150
+
1151
+ if host.find(':') >= 0:
1152
+ host_enc = b'[' + host_enc + b']'
1153
+
1154
+ if port == self.default_port:
1155
+ self.putheader('Host', host_enc)
1156
+ else:
1157
+ host_enc = host_enc.decode("ascii")
1158
+ self.putheader('Host', "%s:%s" % (host_enc, port))
1159
+
1160
+ # note: we are assuming that clients will not attempt to set these
1161
+ # headers since *this* library must deal with the
1162
+ # consequences. this also means that when the supporting
1163
+ # libraries are updated to recognize other forms, then this
1164
+ # code should be changed (removed or updated).
1165
+
1166
+ # we only want a Content-Encoding of "identity" since we don't
1167
+ # support encodings such as x-gzip or x-deflate.
1168
+ if not skip_accept_encoding:
1169
+ self.putheader('Accept-Encoding', 'identity')
1170
+
1171
+ # we can accept "chunked" Transfer-Encodings, but no others
1172
+ # NOTE: no TE header implies *only* "chunked"
1173
+ #self.putheader('TE', 'chunked')
1174
+
1175
+ # if TE is supplied in the header, then it must appear in a
1176
+ # Connection header.
1177
+ #self.putheader('Connection', 'TE')
1178
+
1179
+ else:
1180
+ # For HTTP/1.0, the server will assume "not chunked"
1181
+ pass
1182
+
1183
+ def _encode_request(self, request):
1184
+ # ASCII also helps prevent CVE-2019-9740.
1185
+ return request.encode('ascii')
1186
+
1187
+ def _validate_method(self, method):
1188
+ """Validate a method name for putrequest."""
1189
+ # prevent http header injection
1190
+ match = _contains_disallowed_method_pchar_re.search(method)
1191
+ if match:
1192
+ raise ValueError(
1193
+ f"method can't contain control characters. {method!r} "
1194
+ f"(found at least {match.group()!r})")
1195
+
1196
+ def _validate_path(self, url):
1197
+ """Validate a url for putrequest."""
1198
+ # Prevent CVE-2019-9740.
1199
+ match = _contains_disallowed_url_pchar_re.search(url)
1200
+ if match:
1201
+ raise InvalidURL(f"URL can't contain control characters. {url!r} "
1202
+ f"(found at least {match.group()!r})")
1203
+
1204
+ def _validate_host(self, host):
1205
+ """Validate a host so it doesn't contain control characters."""
1206
+ # Prevent CVE-2019-18348.
1207
+ match = _contains_disallowed_url_pchar_re.search(host)
1208
+ if match:
1209
+ raise InvalidURL(f"URL can't contain control characters. {host!r} "
1210
+ f"(found at least {match.group()!r})")
1211
+
1212
+ def putheader(self, header, *values):
1213
+ """Send a request header line to the server.
1214
+
1215
+ For example: h.putheader('Accept', 'text/html')
1216
+ """
1217
+ if self.__state != _CS_REQ_STARTED:
1218
+ raise CannotSendHeader()
1219
+
1220
+ if hasattr(header, 'encode'):
1221
+ header = header.encode('ascii')
1222
+
1223
+ if not _is_legal_header_name(header):
1224
+ raise ValueError('Invalid header name %r' % (header,))
1225
+
1226
+ values = list(values)
1227
+ for i, one_value in enumerate(values):
1228
+ if hasattr(one_value, 'encode'):
1229
+ values[i] = one_value.encode('latin-1')
1230
+ elif isinstance(one_value, int):
1231
+ values[i] = str(one_value).encode('ascii')
1232
+
1233
+ if _is_illegal_header_value(values[i]):
1234
+ raise ValueError('Invalid header value %r' % (values[i],))
1235
+
1236
+ value = b'\r\n\t'.join(values)
1237
+ header = header + b': ' + value
1238
+ self._output(header)
1239
+
1240
+ def endheaders(self, message_body=None, *, encode_chunked=False):
1241
+ """Indicate that the last header line has been sent to the server.
1242
+
1243
+ This method sends the request to the server. The optional message_body
1244
+ argument can be used to pass a message body associated with the
1245
+ request.
1246
+ """
1247
+ if self.__state == _CS_REQ_STARTED:
1248
+ self.__state = _CS_REQ_SENT
1249
+ else:
1250
+ raise CannotSendHeader()
1251
+ self._send_output(message_body, encode_chunked=encode_chunked)
1252
+
1253
+ def request(self, method, url, body=None, headers={}, *,
1254
+ encode_chunked=False):
1255
+ """Send a complete request to the server."""
1256
+ self._send_request(method, url, body, headers, encode_chunked)
1257
+
1258
+ def _send_request(self, method, url, body, headers, encode_chunked):
1259
+ # Honor explicitly requested Host: and Accept-Encoding: headers.
1260
+ header_names = frozenset(k.lower() for k in headers)
1261
+ skips = {}
1262
+ if 'host' in header_names:
1263
+ skips['skip_host'] = 1
1264
+ if 'accept-encoding' in header_names:
1265
+ skips['skip_accept_encoding'] = 1
1266
+
1267
+ self.putrequest(method, url, **skips)
1268
+
1269
+ # chunked encoding will happen if HTTP/1.1 is used and either
1270
+ # the caller passes encode_chunked=True or the following
1271
+ # conditions hold:
1272
+ # 1. content-length has not been explicitly set
1273
+ # 2. the body is a file or iterable, but not a str or bytes-like
1274
+ # 3. Transfer-Encoding has NOT been explicitly set by the caller
1275
+
1276
+ if 'content-length' not in header_names:
1277
+ # only chunk body if not explicitly set for backwards
1278
+ # compatibility, assuming the client code is already handling the
1279
+ # chunking
1280
+ if 'transfer-encoding' not in header_names:
1281
+ # if content-length cannot be automatically determined, fall
1282
+ # back to chunked encoding
1283
+ encode_chunked = False
1284
+ content_length = self._get_content_length(body, method)
1285
+ if content_length is None:
1286
+ if body is not None:
1287
+ if self.debuglevel > 0:
1288
+ print('Unable to determine size of %r' % body)
1289
+ encode_chunked = True
1290
+ self.putheader('Transfer-Encoding', 'chunked')
1291
+ else:
1292
+ self.putheader('Content-Length', str(content_length))
1293
+ else:
1294
+ encode_chunked = False
1295
+
1296
+ for hdr, value in headers.items():
1297
+ self.putheader(hdr, value)
1298
+ if isinstance(body, str):
1299
+ # RFC 2616 Section 3.7.1 says that text default has a
1300
+ # default charset of iso-8859-1.
1301
+ body = _encode(body, 'body')
1302
+ self.endheaders(body, encode_chunked=encode_chunked)
1303
+
1304
+ def getresponse(self):
1305
+ """Get the response from the server.
1306
+
1307
+ If the HTTPConnection is in the correct state, returns an
1308
+ instance of HTTPResponse or of whatever object is returned by
1309
+ the response_class variable.
1310
+
1311
+ If a request has not been sent or if a previous response has
1312
+ not be handled, ResponseNotReady is raised. If the HTTP
1313
+ response indicates that the connection should be closed, then
1314
+ it will be closed before the response is returned. When the
1315
+ connection is closed, the underlying socket is closed.
1316
+ """
1317
+
1318
+ # if a prior response has been completed, then forget about it.
1319
+ if self.__response and self.__response.isclosed():
1320
+ self.__response = None
1321
+
1322
+ # if a prior response exists, then it must be completed (otherwise, we
1323
+ # cannot read this response's header to determine the connection-close
1324
+ # behavior)
1325
+ #
1326
+ # note: if a prior response existed, but was connection-close, then the
1327
+ # socket and response were made independent of this HTTPConnection
1328
+ # object since a new request requires that we open a whole new
1329
+ # connection
1330
+ #
1331
+ # this means the prior response had one of two states:
1332
+ # 1) will_close: this connection was reset and the prior socket and
1333
+ # response operate independently
1334
+ # 2) persistent: the response was retained and we await its
1335
+ # isclosed() status to become true.
1336
+ #
1337
+ if self.__state != _CS_REQ_SENT or self.__response:
1338
+ raise ResponseNotReady(self.__state)
1339
+
1340
+ if self.debuglevel > 0:
1341
+ response = self.response_class(self.sock, self.debuglevel,
1342
+ method=self._method)
1343
+ else:
1344
+ response = self.response_class(self.sock, method=self._method)
1345
+
1346
+ try:
1347
+ try:
1348
+ response.begin()
1349
+ except ConnectionError:
1350
+ self.close()
1351
+ raise
1352
+ assert response.will_close != _UNKNOWN
1353
+ self.__state = _CS_IDLE
1354
+
1355
+ if response.will_close:
1356
+ # this effectively passes the connection to the response
1357
+ self.close()
1358
+ else:
1359
+ # remember this, so we can tell when it is complete
1360
+ self.__response = response
1361
+
1362
+ return response
1363
+ except:
1364
+ response.close()
1365
+ raise
1366
+
1367
+ try:
1368
+ import ssl
1369
+ except ImportError:
1370
+ pass
1371
+ else:
1372
+ class HTTPSConnection(HTTPConnection):
1373
+ "This class allows communication via SSL."
1374
+
1375
+ default_port = HTTPS_PORT
1376
+
1377
+ # XXX Should key_file and cert_file be deprecated in favour of context?
1378
+
1379
+ def __init__(self, host, port=None, key_file=None, cert_file=None,
1380
+ timeout=socket._GLOBAL_DEFAULT_TIMEOUT,
1381
+ source_address=None, *, context=None,
1382
+ check_hostname=None, blocksize=8192):
1383
+ super(HTTPSConnection, self).__init__(host, port, timeout,
1384
+ source_address,
1385
+ blocksize=blocksize)
1386
+ if (key_file is not None or cert_file is not None or
1387
+ check_hostname is not None):
1388
+ import warnings
1389
+ warnings.warn("key_file, cert_file and check_hostname are "
1390
+ "deprecated, use a custom context instead.",
1391
+ DeprecationWarning, 2)
1392
+ self.key_file = key_file
1393
+ self.cert_file = cert_file
1394
+ if context is None:
1395
+ context = ssl._create_default_https_context()
1396
+ # enable PHA for TLS 1.3 connections if available
1397
+ if context.post_handshake_auth is not None:
1398
+ context.post_handshake_auth = True
1399
+ will_verify = context.verify_mode != ssl.CERT_NONE
1400
+ if check_hostname is None:
1401
+ check_hostname = context.check_hostname
1402
+ if check_hostname and not will_verify:
1403
+ raise ValueError("check_hostname needs a SSL context with "
1404
+ "either CERT_OPTIONAL or CERT_REQUIRED")
1405
+ if key_file or cert_file:
1406
+ context.load_cert_chain(cert_file, key_file)
1407
+ # cert and key file means the user wants to authenticate.
1408
+ # enable TLS 1.3 PHA implicitly even for custom contexts.
1409
+ if context.post_handshake_auth is not None:
1410
+ context.post_handshake_auth = True
1411
+ self._context = context
1412
+ if check_hostname is not None:
1413
+ self._context.check_hostname = check_hostname
1414
+
1415
+ def connect(self):
1416
+ "Connect to a host on a given (SSL) port."
1417
+
1418
+ super().connect()
1419
+
1420
+ if self._tunnel_host:
1421
+ server_hostname = self._tunnel_host
1422
+ else:
1423
+ server_hostname = self.host
1424
+
1425
+ self.sock = self._context.wrap_socket(self.sock,
1426
+ server_hostname=server_hostname)
1427
+
1428
+ __all__.append("HTTPSConnection")
1429
+
1430
+ class HTTPException(Exception):
1431
+ # Subclasses that define an __init__ must call Exception.__init__
1432
+ # or define self.args. Otherwise, str() will fail.
1433
+ pass
1434
+
1435
+ class NotConnected(HTTPException):
1436
+ pass
1437
+
1438
+ class InvalidURL(HTTPException):
1439
+ pass
1440
+
1441
+ class UnknownProtocol(HTTPException):
1442
+ def __init__(self, version):
1443
+ self.args = version,
1444
+ self.version = version
1445
+
1446
+ class UnknownTransferEncoding(HTTPException):
1447
+ pass
1448
+
1449
+ class UnimplementedFileMode(HTTPException):
1450
+ pass
1451
+
1452
+ class IncompleteRead(HTTPException):
1453
+ def __init__(self, partial, expected=None):
1454
+ self.args = partial,
1455
+ self.partial = partial
1456
+ self.expected = expected
1457
+ def __repr__(self):
1458
+ if self.expected is not None:
1459
+ e = ', %i more expected' % self.expected
1460
+ else:
1461
+ e = ''
1462
+ return '%s(%i bytes read%s)' % (self.__class__.__name__,
1463
+ len(self.partial), e)
1464
+ __str__ = object.__str__
1465
+
1466
+ class ImproperConnectionState(HTTPException):
1467
+ pass
1468
+
1469
+ class CannotSendRequest(ImproperConnectionState):
1470
+ pass
1471
+
1472
+ class CannotSendHeader(ImproperConnectionState):
1473
+ pass
1474
+
1475
+ class ResponseNotReady(ImproperConnectionState):
1476
+ pass
1477
+
1478
+ class BadStatusLine(HTTPException):
1479
+ def __init__(self, line):
1480
+ if not line:
1481
+ line = repr(line)
1482
+ self.args = line,
1483
+ self.line = line
1484
+
1485
+ class LineTooLong(HTTPException):
1486
+ def __init__(self, line_type):
1487
+ HTTPException.__init__(self, "got more than %d bytes when reading %s"
1488
+ % (_MAXLINE, line_type))
1489
+
1490
+ class RemoteDisconnected(ConnectionResetError, BadStatusLine):
1491
+ def __init__(self, *pos, **kw):
1492
+ BadStatusLine.__init__(self, "")
1493
+ ConnectionResetError.__init__(self, *pos, **kw)
1494
+
1495
+ # for backwards compatibility
1496
+ error = HTTPException
my_container_sandbox/workspace/anaconda3/lib/python3.8/http/cookiejar.py ADDED
@@ -0,0 +1,2113 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ r"""HTTP cookie handling for web clients.
2
+
3
+ This module has (now fairly distant) origins in Gisle Aas' Perl module
4
+ HTTP::Cookies, from the libwww-perl library.
5
+
6
+ Docstrings, comments and debug strings in this code refer to the
7
+ attributes of the HTTP cookie system as cookie-attributes, to distinguish
8
+ them clearly from Python attributes.
9
+
10
+ Class diagram (note that BSDDBCookieJar and the MSIE* classes are not
11
+ distributed with the Python standard library, but are available from
12
+ http://wwwsearch.sf.net/):
13
+
14
+ CookieJar____
15
+ / \ \
16
+ FileCookieJar \ \
17
+ / | \ \ \
18
+ MozillaCookieJar | LWPCookieJar \ \
19
+ | | \
20
+ | ---MSIEBase | \
21
+ | / | | \
22
+ | / MSIEDBCookieJar BSDDBCookieJar
23
+ |/
24
+ MSIECookieJar
25
+
26
+ """
27
+
28
+ __all__ = ['Cookie', 'CookieJar', 'CookiePolicy', 'DefaultCookiePolicy',
29
+ 'FileCookieJar', 'LWPCookieJar', 'LoadError', 'MozillaCookieJar']
30
+
31
+ import os
32
+ import copy
33
+ import datetime
34
+ import re
35
+ import time
36
+ import urllib.parse, urllib.request
37
+ import threading as _threading
38
+ import http.client # only for the default HTTP port
39
+ from calendar import timegm
40
+
41
+ debug = False # set to True to enable debugging via the logging module
42
+ logger = None
43
+
44
+ def _debug(*args):
45
+ if not debug:
46
+ return
47
+ global logger
48
+ if not logger:
49
+ import logging
50
+ logger = logging.getLogger("http.cookiejar")
51
+ return logger.debug(*args)
52
+
53
+
54
+ DEFAULT_HTTP_PORT = str(http.client.HTTP_PORT)
55
+ MISSING_FILENAME_TEXT = ("a filename was not supplied (nor was the CookieJar "
56
+ "instance initialised with one)")
57
+
58
+ def _warn_unhandled_exception():
59
+ # There are a few catch-all except: statements in this module, for
60
+ # catching input that's bad in unexpected ways. Warn if any
61
+ # exceptions are caught there.
62
+ import io, warnings, traceback
63
+ f = io.StringIO()
64
+ traceback.print_exc(None, f)
65
+ msg = f.getvalue()
66
+ warnings.warn("http.cookiejar bug!\n%s" % msg, stacklevel=2)
67
+
68
+
69
+ # Date/time conversion
70
+ # -----------------------------------------------------------------------------
71
+
72
+ EPOCH_YEAR = 1970
73
+ def _timegm(tt):
74
+ year, month, mday, hour, min, sec = tt[:6]
75
+ if ((year >= EPOCH_YEAR) and (1 <= month <= 12) and (1 <= mday <= 31) and
76
+ (0 <= hour <= 24) and (0 <= min <= 59) and (0 <= sec <= 61)):
77
+ return timegm(tt)
78
+ else:
79
+ return None
80
+
81
+ DAYS = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
82
+ MONTHS = ["Jan", "Feb", "Mar", "Apr", "May", "Jun",
83
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
84
+ MONTHS_LOWER = []
85
+ for month in MONTHS: MONTHS_LOWER.append(month.lower())
86
+
87
+ def time2isoz(t=None):
88
+ """Return a string representing time in seconds since epoch, t.
89
+
90
+ If the function is called without an argument, it will use the current
91
+ time.
92
+
93
+ The format of the returned string is like "YYYY-MM-DD hh:mm:ssZ",
94
+ representing Universal Time (UTC, aka GMT). An example of this format is:
95
+
96
+ 1994-11-24 08:49:37Z
97
+
98
+ """
99
+ if t is None:
100
+ dt = datetime.datetime.utcnow()
101
+ else:
102
+ dt = datetime.datetime.utcfromtimestamp(t)
103
+ return "%04d-%02d-%02d %02d:%02d:%02dZ" % (
104
+ dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second)
105
+
106
+ def time2netscape(t=None):
107
+ """Return a string representing time in seconds since epoch, t.
108
+
109
+ If the function is called without an argument, it will use the current
110
+ time.
111
+
112
+ The format of the returned string is like this:
113
+
114
+ Wed, DD-Mon-YYYY HH:MM:SS GMT
115
+
116
+ """
117
+ if t is None:
118
+ dt = datetime.datetime.utcnow()
119
+ else:
120
+ dt = datetime.datetime.utcfromtimestamp(t)
121
+ return "%s, %02d-%s-%04d %02d:%02d:%02d GMT" % (
122
+ DAYS[dt.weekday()], dt.day, MONTHS[dt.month-1],
123
+ dt.year, dt.hour, dt.minute, dt.second)
124
+
125
+
126
+ UTC_ZONES = {"GMT": None, "UTC": None, "UT": None, "Z": None}
127
+
128
+ TIMEZONE_RE = re.compile(r"^([-+])?(\d\d?):?(\d\d)?$", re.ASCII)
129
+ def offset_from_tz_string(tz):
130
+ offset = None
131
+ if tz in UTC_ZONES:
132
+ offset = 0
133
+ else:
134
+ m = TIMEZONE_RE.search(tz)
135
+ if m:
136
+ offset = 3600 * int(m.group(2))
137
+ if m.group(3):
138
+ offset = offset + 60 * int(m.group(3))
139
+ if m.group(1) == '-':
140
+ offset = -offset
141
+ return offset
142
+
143
+ def _str2time(day, mon, yr, hr, min, sec, tz):
144
+ yr = int(yr)
145
+ if yr > datetime.MAXYEAR:
146
+ return None
147
+
148
+ # translate month name to number
149
+ # month numbers start with 1 (January)
150
+ try:
151
+ mon = MONTHS_LOWER.index(mon.lower())+1
152
+ except ValueError:
153
+ # maybe it's already a number
154
+ try:
155
+ imon = int(mon)
156
+ except ValueError:
157
+ return None
158
+ if 1 <= imon <= 12:
159
+ mon = imon
160
+ else:
161
+ return None
162
+
163
+ # make sure clock elements are defined
164
+ if hr is None: hr = 0
165
+ if min is None: min = 0
166
+ if sec is None: sec = 0
167
+
168
+ day = int(day)
169
+ hr = int(hr)
170
+ min = int(min)
171
+ sec = int(sec)
172
+
173
+ if yr < 1000:
174
+ # find "obvious" year
175
+ cur_yr = time.localtime(time.time())[0]
176
+ m = cur_yr % 100
177
+ tmp = yr
178
+ yr = yr + cur_yr - m
179
+ m = m - tmp
180
+ if abs(m) > 50:
181
+ if m > 0: yr = yr + 100
182
+ else: yr = yr - 100
183
+
184
+ # convert UTC time tuple to seconds since epoch (not timezone-adjusted)
185
+ t = _timegm((yr, mon, day, hr, min, sec, tz))
186
+
187
+ if t is not None:
188
+ # adjust time using timezone string, to get absolute time since epoch
189
+ if tz is None:
190
+ tz = "UTC"
191
+ tz = tz.upper()
192
+ offset = offset_from_tz_string(tz)
193
+ if offset is None:
194
+ return None
195
+ t = t - offset
196
+
197
+ return t
198
+
199
+ STRICT_DATE_RE = re.compile(
200
+ r"^[SMTWF][a-z][a-z], (\d\d) ([JFMASOND][a-z][a-z]) "
201
+ r"(\d\d\d\d) (\d\d):(\d\d):(\d\d) GMT$", re.ASCII)
202
+ WEEKDAY_RE = re.compile(
203
+ r"^(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)[a-z]*,?\s*", re.I | re.ASCII)
204
+ LOOSE_HTTP_DATE_RE = re.compile(
205
+ r"""^
206
+ (\d\d?) # day
207
+ (?:\s+|[-\/])
208
+ (\w+) # month
209
+ (?:\s+|[-\/])
210
+ (\d+) # year
211
+ (?:
212
+ (?:\s+|:) # separator before clock
213
+ (\d\d?):(\d\d) # hour:min
214
+ (?::(\d\d))? # optional seconds
215
+ )? # optional clock
216
+ \s*
217
+ (?:
218
+ ([-+]?\d{2,4}|(?![APap][Mm]\b)[A-Za-z]+) # timezone
219
+ \s*
220
+ )?
221
+ (?:
222
+ \(\w+\) # ASCII representation of timezone in parens.
223
+ \s*
224
+ )?$""", re.X | re.ASCII)
225
+ def http2time(text):
226
+ """Returns time in seconds since epoch of time represented by a string.
227
+
228
+ Return value is an integer.
229
+
230
+ None is returned if the format of str is unrecognized, the time is outside
231
+ the representable range, or the timezone string is not recognized. If the
232
+ string contains no timezone, UTC is assumed.
233
+
234
+ The timezone in the string may be numerical (like "-0800" or "+0100") or a
235
+ string timezone (like "UTC", "GMT", "BST" or "EST"). Currently, only the
236
+ timezone strings equivalent to UTC (zero offset) are known to the function.
237
+
238
+ The function loosely parses the following formats:
239
+
240
+ Wed, 09 Feb 1994 22:23:32 GMT -- HTTP format
241
+ Tuesday, 08-Feb-94 14:15:29 GMT -- old rfc850 HTTP format
242
+ Tuesday, 08-Feb-1994 14:15:29 GMT -- broken rfc850 HTTP format
243
+ 09 Feb 1994 22:23:32 GMT -- HTTP format (no weekday)
244
+ 08-Feb-94 14:15:29 GMT -- rfc850 format (no weekday)
245
+ 08-Feb-1994 14:15:29 GMT -- broken rfc850 format (no weekday)
246
+
247
+ The parser ignores leading and trailing whitespace. The time may be
248
+ absent.
249
+
250
+ If the year is given with only 2 digits, the function will select the
251
+ century that makes the year closest to the current date.
252
+
253
+ """
254
+ # fast exit for strictly conforming string
255
+ m = STRICT_DATE_RE.search(text)
256
+ if m:
257
+ g = m.groups()
258
+ mon = MONTHS_LOWER.index(g[1].lower()) + 1
259
+ tt = (int(g[2]), mon, int(g[0]),
260
+ int(g[3]), int(g[4]), float(g[5]))
261
+ return _timegm(tt)
262
+
263
+ # No, we need some messy parsing...
264
+
265
+ # clean up
266
+ text = text.lstrip()
267
+ text = WEEKDAY_RE.sub("", text, 1) # Useless weekday
268
+
269
+ # tz is time zone specifier string
270
+ day, mon, yr, hr, min, sec, tz = [None]*7
271
+
272
+ # loose regexp parse
273
+ m = LOOSE_HTTP_DATE_RE.search(text)
274
+ if m is not None:
275
+ day, mon, yr, hr, min, sec, tz = m.groups()
276
+ else:
277
+ return None # bad format
278
+
279
+ return _str2time(day, mon, yr, hr, min, sec, tz)
280
+
281
+ ISO_DATE_RE = re.compile(
282
+ r"""^
283
+ (\d{4}) # year
284
+ [-\/]?
285
+ (\d\d?) # numerical month
286
+ [-\/]?
287
+ (\d\d?) # day
288
+ (?:
289
+ (?:\s+|[-:Tt]) # separator before clock
290
+ (\d\d?):?(\d\d) # hour:min
291
+ (?::?(\d\d(?:\.\d*)?))? # optional seconds (and fractional)
292
+ )? # optional clock
293
+ \s*
294
+ (?:
295
+ ([-+]?\d\d?:?(:?\d\d)?
296
+ |Z|z) # timezone (Z is "zero meridian", i.e. GMT)
297
+ \s*
298
+ )?$""", re.X | re. ASCII)
299
+ def iso2time(text):
300
+ """
301
+ As for http2time, but parses the ISO 8601 formats:
302
+
303
+ 1994-02-03 14:15:29 -0100 -- ISO 8601 format
304
+ 1994-02-03 14:15:29 -- zone is optional
305
+ 1994-02-03 -- only date
306
+ 1994-02-03T14:15:29 -- Use T as separator
307
+ 19940203T141529Z -- ISO 8601 compact format
308
+ 19940203 -- only date
309
+
310
+ """
311
+ # clean up
312
+ text = text.lstrip()
313
+
314
+ # tz is time zone specifier string
315
+ day, mon, yr, hr, min, sec, tz = [None]*7
316
+
317
+ # loose regexp parse
318
+ m = ISO_DATE_RE.search(text)
319
+ if m is not None:
320
+ # XXX there's an extra bit of the timezone I'm ignoring here: is
321
+ # this the right thing to do?
322
+ yr, mon, day, hr, min, sec, tz, _ = m.groups()
323
+ else:
324
+ return None # bad format
325
+
326
+ return _str2time(day, mon, yr, hr, min, sec, tz)
327
+
328
+
329
+ # Header parsing
330
+ # -----------------------------------------------------------------------------
331
+
332
+ def unmatched(match):
333
+ """Return unmatched part of re.Match object."""
334
+ start, end = match.span(0)
335
+ return match.string[:start]+match.string[end:]
336
+
337
+ HEADER_TOKEN_RE = re.compile(r"^\s*([^=\s;,]+)")
338
+ HEADER_QUOTED_VALUE_RE = re.compile(r"^\s*=\s*\"([^\"\\]*(?:\\.[^\"\\]*)*)\"")
339
+ HEADER_VALUE_RE = re.compile(r"^\s*=\s*([^\s;,]*)")
340
+ HEADER_ESCAPE_RE = re.compile(r"\\(.)")
341
+ def split_header_words(header_values):
342
+ r"""Parse header values into a list of lists containing key,value pairs.
343
+
344
+ The function knows how to deal with ",", ";" and "=" as well as quoted
345
+ values after "=". A list of space separated tokens are parsed as if they
346
+ were separated by ";".
347
+
348
+ If the header_values passed as argument contains multiple values, then they
349
+ are treated as if they were a single value separated by comma ",".
350
+
351
+ This means that this function is useful for parsing header fields that
352
+ follow this syntax (BNF as from the HTTP/1.1 specification, but we relax
353
+ the requirement for tokens).
354
+
355
+ headers = #header
356
+ header = (token | parameter) *( [";"] (token | parameter))
357
+
358
+ token = 1*<any CHAR except CTLs or separators>
359
+ separators = "(" | ")" | "<" | ">" | "@"
360
+ | "," | ";" | ":" | "\" | <">
361
+ | "/" | "[" | "]" | "?" | "="
362
+ | "{" | "}" | SP | HT
363
+
364
+ quoted-string = ( <"> *(qdtext | quoted-pair ) <"> )
365
+ qdtext = <any TEXT except <">>
366
+ quoted-pair = "\" CHAR
367
+
368
+ parameter = attribute "=" value
369
+ attribute = token
370
+ value = token | quoted-string
371
+
372
+ Each header is represented by a list of key/value pairs. The value for a
373
+ simple token (not part of a parameter) is None. Syntactically incorrect
374
+ headers will not necessarily be parsed as you would want.
375
+
376
+ This is easier to describe with some examples:
377
+
378
+ >>> split_header_words(['foo="bar"; port="80,81"; discard, bar=baz'])
379
+ [[('foo', 'bar'), ('port', '80,81'), ('discard', None)], [('bar', 'baz')]]
380
+ >>> split_header_words(['text/html; charset="iso-8859-1"'])
381
+ [[('text/html', None), ('charset', 'iso-8859-1')]]
382
+ >>> split_header_words([r'Basic realm="\"foo\bar\""'])
383
+ [[('Basic', None), ('realm', '"foobar"')]]
384
+
385
+ """
386
+ assert not isinstance(header_values, str)
387
+ result = []
388
+ for text in header_values:
389
+ orig_text = text
390
+ pairs = []
391
+ while text:
392
+ m = HEADER_TOKEN_RE.search(text)
393
+ if m:
394
+ text = unmatched(m)
395
+ name = m.group(1)
396
+ m = HEADER_QUOTED_VALUE_RE.search(text)
397
+ if m: # quoted value
398
+ text = unmatched(m)
399
+ value = m.group(1)
400
+ value = HEADER_ESCAPE_RE.sub(r"\1", value)
401
+ else:
402
+ m = HEADER_VALUE_RE.search(text)
403
+ if m: # unquoted value
404
+ text = unmatched(m)
405
+ value = m.group(1)
406
+ value = value.rstrip()
407
+ else:
408
+ # no value, a lone token
409
+ value = None
410
+ pairs.append((name, value))
411
+ elif text.lstrip().startswith(","):
412
+ # concatenated headers, as per RFC 2616 section 4.2
413
+ text = text.lstrip()[1:]
414
+ if pairs: result.append(pairs)
415
+ pairs = []
416
+ else:
417
+ # skip junk
418
+ non_junk, nr_junk_chars = re.subn(r"^[=\s;]*", "", text)
419
+ assert nr_junk_chars > 0, (
420
+ "split_header_words bug: '%s', '%s', %s" %
421
+ (orig_text, text, pairs))
422
+ text = non_junk
423
+ if pairs: result.append(pairs)
424
+ return result
425
+
426
+ HEADER_JOIN_ESCAPE_RE = re.compile(r"([\"\\])")
427
+ def join_header_words(lists):
428
+ """Do the inverse (almost) of the conversion done by split_header_words.
429
+
430
+ Takes a list of lists of (key, value) pairs and produces a single header
431
+ value. Attribute values are quoted if needed.
432
+
433
+ >>> join_header_words([[("text/plain", None), ("charset", "iso-8859-1")]])
434
+ 'text/plain; charset="iso-8859-1"'
435
+ >>> join_header_words([[("text/plain", None)], [("charset", "iso-8859-1")]])
436
+ 'text/plain, charset="iso-8859-1"'
437
+
438
+ """
439
+ headers = []
440
+ for pairs in lists:
441
+ attr = []
442
+ for k, v in pairs:
443
+ if v is not None:
444
+ if not re.search(r"^\w+$", v):
445
+ v = HEADER_JOIN_ESCAPE_RE.sub(r"\\\1", v) # escape " and \
446
+ v = '"%s"' % v
447
+ k = "%s=%s" % (k, v)
448
+ attr.append(k)
449
+ if attr: headers.append("; ".join(attr))
450
+ return ", ".join(headers)
451
+
452
+ def strip_quotes(text):
453
+ if text.startswith('"'):
454
+ text = text[1:]
455
+ if text.endswith('"'):
456
+ text = text[:-1]
457
+ return text
458
+
459
+ def parse_ns_headers(ns_headers):
460
+ """Ad-hoc parser for Netscape protocol cookie-attributes.
461
+
462
+ The old Netscape cookie format for Set-Cookie can for instance contain
463
+ an unquoted "," in the expires field, so we have to use this ad-hoc
464
+ parser instead of split_header_words.
465
+
466
+ XXX This may not make the best possible effort to parse all the crap
467
+ that Netscape Cookie headers contain. Ronald Tschalar's HTTPClient
468
+ parser is probably better, so could do worse than following that if
469
+ this ever gives any trouble.
470
+
471
+ Currently, this is also used for parsing RFC 2109 cookies.
472
+
473
+ """
474
+ known_attrs = ("expires", "domain", "path", "secure",
475
+ # RFC 2109 attrs (may turn up in Netscape cookies, too)
476
+ "version", "port", "max-age")
477
+
478
+ result = []
479
+ for ns_header in ns_headers:
480
+ pairs = []
481
+ version_set = False
482
+
483
+ # XXX: The following does not strictly adhere to RFCs in that empty
484
+ # names and values are legal (the former will only appear once and will
485
+ # be overwritten if multiple occurrences are present). This is
486
+ # mostly to deal with backwards compatibility.
487
+ for ii, param in enumerate(ns_header.split(';')):
488
+ param = param.strip()
489
+
490
+ key, sep, val = param.partition('=')
491
+ key = key.strip()
492
+
493
+ if not key:
494
+ if ii == 0:
495
+ break
496
+ else:
497
+ continue
498
+
499
+ # allow for a distinction between present and empty and missing
500
+ # altogether
501
+ val = val.strip() if sep else None
502
+
503
+ if ii != 0:
504
+ lc = key.lower()
505
+ if lc in known_attrs:
506
+ key = lc
507
+
508
+ if key == "version":
509
+ # This is an RFC 2109 cookie.
510
+ if val is not None:
511
+ val = strip_quotes(val)
512
+ version_set = True
513
+ elif key == "expires":
514
+ # convert expires date to seconds since epoch
515
+ if val is not None:
516
+ val = http2time(strip_quotes(val)) # None if invalid
517
+ pairs.append((key, val))
518
+
519
+ if pairs:
520
+ if not version_set:
521
+ pairs.append(("version", "0"))
522
+ result.append(pairs)
523
+
524
+ return result
525
+
526
+
527
+ IPV4_RE = re.compile(r"\.\d+$", re.ASCII)
528
+ def is_HDN(text):
529
+ """Return True if text is a host domain name."""
530
+ # XXX
531
+ # This may well be wrong. Which RFC is HDN defined in, if any (for
532
+ # the purposes of RFC 2965)?
533
+ # For the current implementation, what about IPv6? Remember to look
534
+ # at other uses of IPV4_RE also, if change this.
535
+ if IPV4_RE.search(text):
536
+ return False
537
+ if text == "":
538
+ return False
539
+ if text[0] == "." or text[-1] == ".":
540
+ return False
541
+ return True
542
+
543
+ def domain_match(A, B):
544
+ """Return True if domain A domain-matches domain B, according to RFC 2965.
545
+
546
+ A and B may be host domain names or IP addresses.
547
+
548
+ RFC 2965, section 1:
549
+
550
+ Host names can be specified either as an IP address or a HDN string.
551
+ Sometimes we compare one host name with another. (Such comparisons SHALL
552
+ be case-insensitive.) Host A's name domain-matches host B's if
553
+
554
+ * their host name strings string-compare equal; or
555
+
556
+ * A is a HDN string and has the form NB, where N is a non-empty
557
+ name string, B has the form .B', and B' is a HDN string. (So,
558
+ x.y.com domain-matches .Y.com but not Y.com.)
559
+
560
+ Note that domain-match is not a commutative operation: a.b.c.com
561
+ domain-matches .c.com, but not the reverse.
562
+
563
+ """
564
+ # Note that, if A or B are IP addresses, the only relevant part of the
565
+ # definition of the domain-match algorithm is the direct string-compare.
566
+ A = A.lower()
567
+ B = B.lower()
568
+ if A == B:
569
+ return True
570
+ if not is_HDN(A):
571
+ return False
572
+ i = A.rfind(B)
573
+ if i == -1 or i == 0:
574
+ # A does not have form NB, or N is the empty string
575
+ return False
576
+ if not B.startswith("."):
577
+ return False
578
+ if not is_HDN(B[1:]):
579
+ return False
580
+ return True
581
+
582
+ def liberal_is_HDN(text):
583
+ """Return True if text is a sort-of-like a host domain name.
584
+
585
+ For accepting/blocking domains.
586
+
587
+ """
588
+ if IPV4_RE.search(text):
589
+ return False
590
+ return True
591
+
592
+ def user_domain_match(A, B):
593
+ """For blocking/accepting domains.
594
+
595
+ A and B may be host domain names or IP addresses.
596
+
597
+ """
598
+ A = A.lower()
599
+ B = B.lower()
600
+ if not (liberal_is_HDN(A) and liberal_is_HDN(B)):
601
+ if A == B:
602
+ # equal IP addresses
603
+ return True
604
+ return False
605
+ initial_dot = B.startswith(".")
606
+ if initial_dot and A.endswith(B):
607
+ return True
608
+ if not initial_dot and A == B:
609
+ return True
610
+ return False
611
+
612
+ cut_port_re = re.compile(r":\d+$", re.ASCII)
613
+ def request_host(request):
614
+ """Return request-host, as defined by RFC 2965.
615
+
616
+ Variation from RFC: returned value is lowercased, for convenient
617
+ comparison.
618
+
619
+ """
620
+ url = request.get_full_url()
621
+ host = urllib.parse.urlparse(url)[1]
622
+ if host == "":
623
+ host = request.get_header("Host", "")
624
+
625
+ # remove port, if present
626
+ host = cut_port_re.sub("", host, 1)
627
+ return host.lower()
628
+
629
+ def eff_request_host(request):
630
+ """Return a tuple (request-host, effective request-host name).
631
+
632
+ As defined by RFC 2965, except both are lowercased.
633
+
634
+ """
635
+ erhn = req_host = request_host(request)
636
+ if req_host.find(".") == -1 and not IPV4_RE.search(req_host):
637
+ erhn = req_host + ".local"
638
+ return req_host, erhn
639
+
640
+ def request_path(request):
641
+ """Path component of request-URI, as defined by RFC 2965."""
642
+ url = request.get_full_url()
643
+ parts = urllib.parse.urlsplit(url)
644
+ path = escape_path(parts.path)
645
+ if not path.startswith("/"):
646
+ # fix bad RFC 2396 absoluteURI
647
+ path = "/" + path
648
+ return path
649
+
650
+ def request_port(request):
651
+ host = request.host
652
+ i = host.find(':')
653
+ if i >= 0:
654
+ port = host[i+1:]
655
+ try:
656
+ int(port)
657
+ except ValueError:
658
+ _debug("nonnumeric port: '%s'", port)
659
+ return None
660
+ else:
661
+ port = DEFAULT_HTTP_PORT
662
+ return port
663
+
664
+ # Characters in addition to A-Z, a-z, 0-9, '_', '.', and '-' that don't
665
+ # need to be escaped to form a valid HTTP URL (RFCs 2396 and 1738).
666
+ HTTP_PATH_SAFE = "%/;:@&=+$,!~*'()"
667
+ ESCAPED_CHAR_RE = re.compile(r"%([0-9a-fA-F][0-9a-fA-F])")
668
+ def uppercase_escaped_char(match):
669
+ return "%%%s" % match.group(1).upper()
670
+ def escape_path(path):
671
+ """Escape any invalid characters in HTTP URL, and uppercase all escapes."""
672
+ # There's no knowing what character encoding was used to create URLs
673
+ # containing %-escapes, but since we have to pick one to escape invalid
674
+ # path characters, we pick UTF-8, as recommended in the HTML 4.0
675
+ # specification:
676
+ # http://www.w3.org/TR/REC-html40/appendix/notes.html#h-B.2.1
677
+ # And here, kind of: draft-fielding-uri-rfc2396bis-03
678
+ # (And in draft IRI specification: draft-duerst-iri-05)
679
+ # (And here, for new URI schemes: RFC 2718)
680
+ path = urllib.parse.quote(path, HTTP_PATH_SAFE)
681
+ path = ESCAPED_CHAR_RE.sub(uppercase_escaped_char, path)
682
+ return path
683
+
684
+ def reach(h):
685
+ """Return reach of host h, as defined by RFC 2965, section 1.
686
+
687
+ The reach R of a host name H is defined as follows:
688
+
689
+ * If
690
+
691
+ - H is the host domain name of a host; and,
692
+
693
+ - H has the form A.B; and
694
+
695
+ - A has no embedded (that is, interior) dots; and
696
+
697
+ - B has at least one embedded dot, or B is the string "local".
698
+ then the reach of H is .B.
699
+
700
+ * Otherwise, the reach of H is H.
701
+
702
+ >>> reach("www.acme.com")
703
+ '.acme.com'
704
+ >>> reach("acme.com")
705
+ 'acme.com'
706
+ >>> reach("acme.local")
707
+ '.local'
708
+
709
+ """
710
+ i = h.find(".")
711
+ if i >= 0:
712
+ #a = h[:i] # this line is only here to show what a is
713
+ b = h[i+1:]
714
+ i = b.find(".")
715
+ if is_HDN(h) and (i >= 0 or b == "local"):
716
+ return "."+b
717
+ return h
718
+
719
+ def is_third_party(request):
720
+ """
721
+
722
+ RFC 2965, section 3.3.6:
723
+
724
+ An unverifiable transaction is to a third-party host if its request-
725
+ host U does not domain-match the reach R of the request-host O in the
726
+ origin transaction.
727
+
728
+ """
729
+ req_host = request_host(request)
730
+ if not domain_match(req_host, reach(request.origin_req_host)):
731
+ return True
732
+ else:
733
+ return False
734
+
735
+
736
+ class Cookie:
737
+ """HTTP Cookie.
738
+
739
+ This class represents both Netscape and RFC 2965 cookies.
740
+
741
+ This is deliberately a very simple class. It just holds attributes. It's
742
+ possible to construct Cookie instances that don't comply with the cookie
743
+ standards. CookieJar.make_cookies is the factory function for Cookie
744
+ objects -- it deals with cookie parsing, supplying defaults, and
745
+ normalising to the representation used in this class. CookiePolicy is
746
+ responsible for checking them to see whether they should be accepted from
747
+ and returned to the server.
748
+
749
+ Note that the port may be present in the headers, but unspecified ("Port"
750
+ rather than"Port=80", for example); if this is the case, port is None.
751
+
752
+ """
753
+
754
+ def __init__(self, version, name, value,
755
+ port, port_specified,
756
+ domain, domain_specified, domain_initial_dot,
757
+ path, path_specified,
758
+ secure,
759
+ expires,
760
+ discard,
761
+ comment,
762
+ comment_url,
763
+ rest,
764
+ rfc2109=False,
765
+ ):
766
+
767
+ if version is not None: version = int(version)
768
+ if expires is not None: expires = int(float(expires))
769
+ if port is None and port_specified is True:
770
+ raise ValueError("if port is None, port_specified must be false")
771
+
772
+ self.version = version
773
+ self.name = name
774
+ self.value = value
775
+ self.port = port
776
+ self.port_specified = port_specified
777
+ # normalise case, as per RFC 2965 section 3.3.3
778
+ self.domain = domain.lower()
779
+ self.domain_specified = domain_specified
780
+ # Sigh. We need to know whether the domain given in the
781
+ # cookie-attribute had an initial dot, in order to follow RFC 2965
782
+ # (as clarified in draft errata). Needed for the returned $Domain
783
+ # value.
784
+ self.domain_initial_dot = domain_initial_dot
785
+ self.path = path
786
+ self.path_specified = path_specified
787
+ self.secure = secure
788
+ self.expires = expires
789
+ self.discard = discard
790
+ self.comment = comment
791
+ self.comment_url = comment_url
792
+ self.rfc2109 = rfc2109
793
+
794
+ self._rest = copy.copy(rest)
795
+
796
+ def has_nonstandard_attr(self, name):
797
+ return name in self._rest
798
+ def get_nonstandard_attr(self, name, default=None):
799
+ return self._rest.get(name, default)
800
+ def set_nonstandard_attr(self, name, value):
801
+ self._rest[name] = value
802
+
803
+ def is_expired(self, now=None):
804
+ if now is None: now = time.time()
805
+ if (self.expires is not None) and (self.expires <= now):
806
+ return True
807
+ return False
808
+
809
+ def __str__(self):
810
+ if self.port is None: p = ""
811
+ else: p = ":"+self.port
812
+ limit = self.domain + p + self.path
813
+ if self.value is not None:
814
+ namevalue = "%s=%s" % (self.name, self.value)
815
+ else:
816
+ namevalue = self.name
817
+ return "<Cookie %s for %s>" % (namevalue, limit)
818
+
819
+ def __repr__(self):
820
+ args = []
821
+ for name in ("version", "name", "value",
822
+ "port", "port_specified",
823
+ "domain", "domain_specified", "domain_initial_dot",
824
+ "path", "path_specified",
825
+ "secure", "expires", "discard", "comment", "comment_url",
826
+ ):
827
+ attr = getattr(self, name)
828
+ args.append("%s=%s" % (name, repr(attr)))
829
+ args.append("rest=%s" % repr(self._rest))
830
+ args.append("rfc2109=%s" % repr(self.rfc2109))
831
+ return "%s(%s)" % (self.__class__.__name__, ", ".join(args))
832
+
833
+
834
+ class CookiePolicy:
835
+ """Defines which cookies get accepted from and returned to server.
836
+
837
+ May also modify cookies, though this is probably a bad idea.
838
+
839
+ The subclass DefaultCookiePolicy defines the standard rules for Netscape
840
+ and RFC 2965 cookies -- override that if you want a customized policy.
841
+
842
+ """
843
+ def set_ok(self, cookie, request):
844
+ """Return true if (and only if) cookie should be accepted from server.
845
+
846
+ Currently, pre-expired cookies never get this far -- the CookieJar
847
+ class deletes such cookies itself.
848
+
849
+ """
850
+ raise NotImplementedError()
851
+
852
+ def return_ok(self, cookie, request):
853
+ """Return true if (and only if) cookie should be returned to server."""
854
+ raise NotImplementedError()
855
+
856
+ def domain_return_ok(self, domain, request):
857
+ """Return false if cookies should not be returned, given cookie domain.
858
+ """
859
+ return True
860
+
861
+ def path_return_ok(self, path, request):
862
+ """Return false if cookies should not be returned, given cookie path.
863
+ """
864
+ return True
865
+
866
+
867
+ class DefaultCookiePolicy(CookiePolicy):
868
+ """Implements the standard rules for accepting and returning cookies."""
869
+
870
+ DomainStrictNoDots = 1
871
+ DomainStrictNonDomain = 2
872
+ DomainRFC2965Match = 4
873
+
874
+ DomainLiberal = 0
875
+ DomainStrict = DomainStrictNoDots|DomainStrictNonDomain
876
+
877
+ def __init__(self,
878
+ blocked_domains=None, allowed_domains=None,
879
+ netscape=True, rfc2965=False,
880
+ rfc2109_as_netscape=None,
881
+ hide_cookie2=False,
882
+ strict_domain=False,
883
+ strict_rfc2965_unverifiable=True,
884
+ strict_ns_unverifiable=False,
885
+ strict_ns_domain=DomainLiberal,
886
+ strict_ns_set_initial_dollar=False,
887
+ strict_ns_set_path=False,
888
+ secure_protocols=("https", "wss")
889
+ ):
890
+ """Constructor arguments should be passed as keyword arguments only."""
891
+ self.netscape = netscape
892
+ self.rfc2965 = rfc2965
893
+ self.rfc2109_as_netscape = rfc2109_as_netscape
894
+ self.hide_cookie2 = hide_cookie2
895
+ self.strict_domain = strict_domain
896
+ self.strict_rfc2965_unverifiable = strict_rfc2965_unverifiable
897
+ self.strict_ns_unverifiable = strict_ns_unverifiable
898
+ self.strict_ns_domain = strict_ns_domain
899
+ self.strict_ns_set_initial_dollar = strict_ns_set_initial_dollar
900
+ self.strict_ns_set_path = strict_ns_set_path
901
+ self.secure_protocols = secure_protocols
902
+
903
+ if blocked_domains is not None:
904
+ self._blocked_domains = tuple(blocked_domains)
905
+ else:
906
+ self._blocked_domains = ()
907
+
908
+ if allowed_domains is not None:
909
+ allowed_domains = tuple(allowed_domains)
910
+ self._allowed_domains = allowed_domains
911
+
912
+ def blocked_domains(self):
913
+ """Return the sequence of blocked domains (as a tuple)."""
914
+ return self._blocked_domains
915
+ def set_blocked_domains(self, blocked_domains):
916
+ """Set the sequence of blocked domains."""
917
+ self._blocked_domains = tuple(blocked_domains)
918
+
919
+ def is_blocked(self, domain):
920
+ for blocked_domain in self._blocked_domains:
921
+ if user_domain_match(domain, blocked_domain):
922
+ return True
923
+ return False
924
+
925
+ def allowed_domains(self):
926
+ """Return None, or the sequence of allowed domains (as a tuple)."""
927
+ return self._allowed_domains
928
+ def set_allowed_domains(self, allowed_domains):
929
+ """Set the sequence of allowed domains, or None."""
930
+ if allowed_domains is not None:
931
+ allowed_domains = tuple(allowed_domains)
932
+ self._allowed_domains = allowed_domains
933
+
934
+ def is_not_allowed(self, domain):
935
+ if self._allowed_domains is None:
936
+ return False
937
+ for allowed_domain in self._allowed_domains:
938
+ if user_domain_match(domain, allowed_domain):
939
+ return False
940
+ return True
941
+
942
+ def set_ok(self, cookie, request):
943
+ """
944
+ If you override .set_ok(), be sure to call this method. If it returns
945
+ false, so should your subclass (assuming your subclass wants to be more
946
+ strict about which cookies to accept).
947
+
948
+ """
949
+ _debug(" - checking cookie %s=%s", cookie.name, cookie.value)
950
+
951
+ assert cookie.name is not None
952
+
953
+ for n in "version", "verifiability", "name", "path", "domain", "port":
954
+ fn_name = "set_ok_"+n
955
+ fn = getattr(self, fn_name)
956
+ if not fn(cookie, request):
957
+ return False
958
+
959
+ return True
960
+
961
+ def set_ok_version(self, cookie, request):
962
+ if cookie.version is None:
963
+ # Version is always set to 0 by parse_ns_headers if it's a Netscape
964
+ # cookie, so this must be an invalid RFC 2965 cookie.
965
+ _debug(" Set-Cookie2 without version attribute (%s=%s)",
966
+ cookie.name, cookie.value)
967
+ return False
968
+ if cookie.version > 0 and not self.rfc2965:
969
+ _debug(" RFC 2965 cookies are switched off")
970
+ return False
971
+ elif cookie.version == 0 and not self.netscape:
972
+ _debug(" Netscape cookies are switched off")
973
+ return False
974
+ return True
975
+
976
+ def set_ok_verifiability(self, cookie, request):
977
+ if request.unverifiable and is_third_party(request):
978
+ if cookie.version > 0 and self.strict_rfc2965_unverifiable:
979
+ _debug(" third-party RFC 2965 cookie during "
980
+ "unverifiable transaction")
981
+ return False
982
+ elif cookie.version == 0 and self.strict_ns_unverifiable:
983
+ _debug(" third-party Netscape cookie during "
984
+ "unverifiable transaction")
985
+ return False
986
+ return True
987
+
988
+ def set_ok_name(self, cookie, request):
989
+ # Try and stop servers setting V0 cookies designed to hack other
990
+ # servers that know both V0 and V1 protocols.
991
+ if (cookie.version == 0 and self.strict_ns_set_initial_dollar and
992
+ cookie.name.startswith("$")):
993
+ _debug(" illegal name (starts with '$'): '%s'", cookie.name)
994
+ return False
995
+ return True
996
+
997
+ def set_ok_path(self, cookie, request):
998
+ if cookie.path_specified:
999
+ req_path = request_path(request)
1000
+ if ((cookie.version > 0 or
1001
+ (cookie.version == 0 and self.strict_ns_set_path)) and
1002
+ not self.path_return_ok(cookie.path, request)):
1003
+ _debug(" path attribute %s is not a prefix of request "
1004
+ "path %s", cookie.path, req_path)
1005
+ return False
1006
+ return True
1007
+
1008
+ def set_ok_domain(self, cookie, request):
1009
+ if self.is_blocked(cookie.domain):
1010
+ _debug(" domain %s is in user block-list", cookie.domain)
1011
+ return False
1012
+ if self.is_not_allowed(cookie.domain):
1013
+ _debug(" domain %s is not in user allow-list", cookie.domain)
1014
+ return False
1015
+ if cookie.domain_specified:
1016
+ req_host, erhn = eff_request_host(request)
1017
+ domain = cookie.domain
1018
+ if self.strict_domain and (domain.count(".") >= 2):
1019
+ # XXX This should probably be compared with the Konqueror
1020
+ # (kcookiejar.cpp) and Mozilla implementations, but it's a
1021
+ # losing battle.
1022
+ i = domain.rfind(".")
1023
+ j = domain.rfind(".", 0, i)
1024
+ if j == 0: # domain like .foo.bar
1025
+ tld = domain[i+1:]
1026
+ sld = domain[j+1:i]
1027
+ if sld.lower() in ("co", "ac", "com", "edu", "org", "net",
1028
+ "gov", "mil", "int", "aero", "biz", "cat", "coop",
1029
+ "info", "jobs", "mobi", "museum", "name", "pro",
1030
+ "travel", "eu") and len(tld) == 2:
1031
+ # domain like .co.uk
1032
+ _debug(" country-code second level domain %s", domain)
1033
+ return False
1034
+ if domain.startswith("."):
1035
+ undotted_domain = domain[1:]
1036
+ else:
1037
+ undotted_domain = domain
1038
+ embedded_dots = (undotted_domain.find(".") >= 0)
1039
+ if not embedded_dots and domain != ".local":
1040
+ _debug(" non-local domain %s contains no embedded dot",
1041
+ domain)
1042
+ return False
1043
+ if cookie.version == 0:
1044
+ if (not erhn.endswith(domain) and
1045
+ (not erhn.startswith(".") and
1046
+ not ("."+erhn).endswith(domain))):
1047
+ _debug(" effective request-host %s (even with added "
1048
+ "initial dot) does not end with %s",
1049
+ erhn, domain)
1050
+ return False
1051
+ if (cookie.version > 0 or
1052
+ (self.strict_ns_domain & self.DomainRFC2965Match)):
1053
+ if not domain_match(erhn, domain):
1054
+ _debug(" effective request-host %s does not domain-match "
1055
+ "%s", erhn, domain)
1056
+ return False
1057
+ if (cookie.version > 0 or
1058
+ (self.strict_ns_domain & self.DomainStrictNoDots)):
1059
+ host_prefix = req_host[:-len(domain)]
1060
+ if (host_prefix.find(".") >= 0 and
1061
+ not IPV4_RE.search(req_host)):
1062
+ _debug(" host prefix %s for domain %s contains a dot",
1063
+ host_prefix, domain)
1064
+ return False
1065
+ return True
1066
+
1067
+ def set_ok_port(self, cookie, request):
1068
+ if cookie.port_specified:
1069
+ req_port = request_port(request)
1070
+ if req_port is None:
1071
+ req_port = "80"
1072
+ else:
1073
+ req_port = str(req_port)
1074
+ for p in cookie.port.split(","):
1075
+ try:
1076
+ int(p)
1077
+ except ValueError:
1078
+ _debug(" bad port %s (not numeric)", p)
1079
+ return False
1080
+ if p == req_port:
1081
+ break
1082
+ else:
1083
+ _debug(" request port (%s) not found in %s",
1084
+ req_port, cookie.port)
1085
+ return False
1086
+ return True
1087
+
1088
+ def return_ok(self, cookie, request):
1089
+ """
1090
+ If you override .return_ok(), be sure to call this method. If it
1091
+ returns false, so should your subclass (assuming your subclass wants to
1092
+ be more strict about which cookies to return).
1093
+
1094
+ """
1095
+ # Path has already been checked by .path_return_ok(), and domain
1096
+ # blocking done by .domain_return_ok().
1097
+ _debug(" - checking cookie %s=%s", cookie.name, cookie.value)
1098
+
1099
+ for n in "version", "verifiability", "secure", "expires", "port", "domain":
1100
+ fn_name = "return_ok_"+n
1101
+ fn = getattr(self, fn_name)
1102
+ if not fn(cookie, request):
1103
+ return False
1104
+ return True
1105
+
1106
+ def return_ok_version(self, cookie, request):
1107
+ if cookie.version > 0 and not self.rfc2965:
1108
+ _debug(" RFC 2965 cookies are switched off")
1109
+ return False
1110
+ elif cookie.version == 0 and not self.netscape:
1111
+ _debug(" Netscape cookies are switched off")
1112
+ return False
1113
+ return True
1114
+
1115
+ def return_ok_verifiability(self, cookie, request):
1116
+ if request.unverifiable and is_third_party(request):
1117
+ if cookie.version > 0 and self.strict_rfc2965_unverifiable:
1118
+ _debug(" third-party RFC 2965 cookie during unverifiable "
1119
+ "transaction")
1120
+ return False
1121
+ elif cookie.version == 0 and self.strict_ns_unverifiable:
1122
+ _debug(" third-party Netscape cookie during unverifiable "
1123
+ "transaction")
1124
+ return False
1125
+ return True
1126
+
1127
+ def return_ok_secure(self, cookie, request):
1128
+ if cookie.secure and request.type not in self.secure_protocols:
1129
+ _debug(" secure cookie with non-secure request")
1130
+ return False
1131
+ return True
1132
+
1133
+ def return_ok_expires(self, cookie, request):
1134
+ if cookie.is_expired(self._now):
1135
+ _debug(" cookie expired")
1136
+ return False
1137
+ return True
1138
+
1139
+ def return_ok_port(self, cookie, request):
1140
+ if cookie.port:
1141
+ req_port = request_port(request)
1142
+ if req_port is None:
1143
+ req_port = "80"
1144
+ for p in cookie.port.split(","):
1145
+ if p == req_port:
1146
+ break
1147
+ else:
1148
+ _debug(" request port %s does not match cookie port %s",
1149
+ req_port, cookie.port)
1150
+ return False
1151
+ return True
1152
+
1153
+ def return_ok_domain(self, cookie, request):
1154
+ req_host, erhn = eff_request_host(request)
1155
+ domain = cookie.domain
1156
+
1157
+ if domain and not domain.startswith("."):
1158
+ dotdomain = "." + domain
1159
+ else:
1160
+ dotdomain = domain
1161
+
1162
+ # strict check of non-domain cookies: Mozilla does this, MSIE5 doesn't
1163
+ if (cookie.version == 0 and
1164
+ (self.strict_ns_domain & self.DomainStrictNonDomain) and
1165
+ not cookie.domain_specified and domain != erhn):
1166
+ _debug(" cookie with unspecified domain does not string-compare "
1167
+ "equal to request domain")
1168
+ return False
1169
+
1170
+ if cookie.version > 0 and not domain_match(erhn, domain):
1171
+ _debug(" effective request-host name %s does not domain-match "
1172
+ "RFC 2965 cookie domain %s", erhn, domain)
1173
+ return False
1174
+ if cookie.version == 0 and not ("."+erhn).endswith(dotdomain):
1175
+ _debug(" request-host %s does not match Netscape cookie domain "
1176
+ "%s", req_host, domain)
1177
+ return False
1178
+ return True
1179
+
1180
+ def domain_return_ok(self, domain, request):
1181
+ # Liberal check of. This is here as an optimization to avoid
1182
+ # having to load lots of MSIE cookie files unless necessary.
1183
+ req_host, erhn = eff_request_host(request)
1184
+ if not req_host.startswith("."):
1185
+ req_host = "."+req_host
1186
+ if not erhn.startswith("."):
1187
+ erhn = "."+erhn
1188
+ if domain and not domain.startswith("."):
1189
+ dotdomain = "." + domain
1190
+ else:
1191
+ dotdomain = domain
1192
+ if not (req_host.endswith(dotdomain) or erhn.endswith(dotdomain)):
1193
+ #_debug(" request domain %s does not match cookie domain %s",
1194
+ # req_host, domain)
1195
+ return False
1196
+
1197
+ if self.is_blocked(domain):
1198
+ _debug(" domain %s is in user block-list", domain)
1199
+ return False
1200
+ if self.is_not_allowed(domain):
1201
+ _debug(" domain %s is not in user allow-list", domain)
1202
+ return False
1203
+
1204
+ return True
1205
+
1206
+ def path_return_ok(self, path, request):
1207
+ _debug("- checking cookie path=%s", path)
1208
+ req_path = request_path(request)
1209
+ pathlen = len(path)
1210
+ if req_path == path:
1211
+ return True
1212
+ elif (req_path.startswith(path) and
1213
+ (path.endswith("/") or req_path[pathlen:pathlen+1] == "/")):
1214
+ return True
1215
+
1216
+ _debug(" %s does not path-match %s", req_path, path)
1217
+ return False
1218
+
1219
+ def vals_sorted_by_key(adict):
1220
+ keys = sorted(adict.keys())
1221
+ return map(adict.get, keys)
1222
+
1223
+ def deepvalues(mapping):
1224
+ """Iterates over nested mapping, depth-first, in sorted order by key."""
1225
+ values = vals_sorted_by_key(mapping)
1226
+ for obj in values:
1227
+ mapping = False
1228
+ try:
1229
+ obj.items
1230
+ except AttributeError:
1231
+ pass
1232
+ else:
1233
+ mapping = True
1234
+ yield from deepvalues(obj)
1235
+ if not mapping:
1236
+ yield obj
1237
+
1238
+
1239
+ # Used as second parameter to dict.get() method, to distinguish absent
1240
+ # dict key from one with a None value.
1241
+ class Absent: pass
1242
+
1243
+ class CookieJar:
1244
+ """Collection of HTTP cookies.
1245
+
1246
+ You may not need to know about this class: try
1247
+ urllib.request.build_opener(HTTPCookieProcessor).open(url).
1248
+ """
1249
+
1250
+ non_word_re = re.compile(r"\W")
1251
+ quote_re = re.compile(r"([\"\\])")
1252
+ strict_domain_re = re.compile(r"\.?[^.]*")
1253
+ domain_re = re.compile(r"[^.]*")
1254
+ dots_re = re.compile(r"^\.+")
1255
+
1256
+ magic_re = re.compile(r"^\#LWP-Cookies-(\d+\.\d+)", re.ASCII)
1257
+
1258
+ def __init__(self, policy=None):
1259
+ if policy is None:
1260
+ policy = DefaultCookiePolicy()
1261
+ self._policy = policy
1262
+
1263
+ self._cookies_lock = _threading.RLock()
1264
+ self._cookies = {}
1265
+
1266
+ def set_policy(self, policy):
1267
+ self._policy = policy
1268
+
1269
+ def _cookies_for_domain(self, domain, request):
1270
+ cookies = []
1271
+ if not self._policy.domain_return_ok(domain, request):
1272
+ return []
1273
+ _debug("Checking %s for cookies to return", domain)
1274
+ cookies_by_path = self._cookies[domain]
1275
+ for path in cookies_by_path.keys():
1276
+ if not self._policy.path_return_ok(path, request):
1277
+ continue
1278
+ cookies_by_name = cookies_by_path[path]
1279
+ for cookie in cookies_by_name.values():
1280
+ if not self._policy.return_ok(cookie, request):
1281
+ _debug(" not returning cookie")
1282
+ continue
1283
+ _debug(" it's a match")
1284
+ cookies.append(cookie)
1285
+ return cookies
1286
+
1287
+ def _cookies_for_request(self, request):
1288
+ """Return a list of cookies to be returned to server."""
1289
+ cookies = []
1290
+ for domain in self._cookies.keys():
1291
+ cookies.extend(self._cookies_for_domain(domain, request))
1292
+ return cookies
1293
+
1294
+ def _cookie_attrs(self, cookies):
1295
+ """Return a list of cookie-attributes to be returned to server.
1296
+
1297
+ like ['foo="bar"; $Path="/"', ...]
1298
+
1299
+ The $Version attribute is also added when appropriate (currently only
1300
+ once per request).
1301
+
1302
+ """
1303
+ # add cookies in order of most specific (ie. longest) path first
1304
+ cookies.sort(key=lambda a: len(a.path), reverse=True)
1305
+
1306
+ version_set = False
1307
+
1308
+ attrs = []
1309
+ for cookie in cookies:
1310
+ # set version of Cookie header
1311
+ # XXX
1312
+ # What should it be if multiple matching Set-Cookie headers have
1313
+ # different versions themselves?
1314
+ # Answer: there is no answer; was supposed to be settled by
1315
+ # RFC 2965 errata, but that may never appear...
1316
+ version = cookie.version
1317
+ if not version_set:
1318
+ version_set = True
1319
+ if version > 0:
1320
+ attrs.append("$Version=%s" % version)
1321
+
1322
+ # quote cookie value if necessary
1323
+ # (not for Netscape protocol, which already has any quotes
1324
+ # intact, due to the poorly-specified Netscape Cookie: syntax)
1325
+ if ((cookie.value is not None) and
1326
+ self.non_word_re.search(cookie.value) and version > 0):
1327
+ value = self.quote_re.sub(r"\\\1", cookie.value)
1328
+ else:
1329
+ value = cookie.value
1330
+
1331
+ # add cookie-attributes to be returned in Cookie header
1332
+ if cookie.value is None:
1333
+ attrs.append(cookie.name)
1334
+ else:
1335
+ attrs.append("%s=%s" % (cookie.name, value))
1336
+ if version > 0:
1337
+ if cookie.path_specified:
1338
+ attrs.append('$Path="%s"' % cookie.path)
1339
+ if cookie.domain.startswith("."):
1340
+ domain = cookie.domain
1341
+ if (not cookie.domain_initial_dot and
1342
+ domain.startswith(".")):
1343
+ domain = domain[1:]
1344
+ attrs.append('$Domain="%s"' % domain)
1345
+ if cookie.port is not None:
1346
+ p = "$Port"
1347
+ if cookie.port_specified:
1348
+ p = p + ('="%s"' % cookie.port)
1349
+ attrs.append(p)
1350
+
1351
+ return attrs
1352
+
1353
+ def add_cookie_header(self, request):
1354
+ """Add correct Cookie: header to request (urllib.request.Request object).
1355
+
1356
+ The Cookie2 header is also added unless policy.hide_cookie2 is true.
1357
+
1358
+ """
1359
+ _debug("add_cookie_header")
1360
+ self._cookies_lock.acquire()
1361
+ try:
1362
+
1363
+ self._policy._now = self._now = int(time.time())
1364
+
1365
+ cookies = self._cookies_for_request(request)
1366
+
1367
+ attrs = self._cookie_attrs(cookies)
1368
+ if attrs:
1369
+ if not request.has_header("Cookie"):
1370
+ request.add_unredirected_header(
1371
+ "Cookie", "; ".join(attrs))
1372
+
1373
+ # if necessary, advertise that we know RFC 2965
1374
+ if (self._policy.rfc2965 and not self._policy.hide_cookie2 and
1375
+ not request.has_header("Cookie2")):
1376
+ for cookie in cookies:
1377
+ if cookie.version != 1:
1378
+ request.add_unredirected_header("Cookie2", '$Version="1"')
1379
+ break
1380
+
1381
+ finally:
1382
+ self._cookies_lock.release()
1383
+
1384
+ self.clear_expired_cookies()
1385
+
1386
+ def _normalized_cookie_tuples(self, attrs_set):
1387
+ """Return list of tuples containing normalised cookie information.
1388
+
1389
+ attrs_set is the list of lists of key,value pairs extracted from
1390
+ the Set-Cookie or Set-Cookie2 headers.
1391
+
1392
+ Tuples are name, value, standard, rest, where name and value are the
1393
+ cookie name and value, standard is a dictionary containing the standard
1394
+ cookie-attributes (discard, secure, version, expires or max-age,
1395
+ domain, path and port) and rest is a dictionary containing the rest of
1396
+ the cookie-attributes.
1397
+
1398
+ """
1399
+ cookie_tuples = []
1400
+
1401
+ boolean_attrs = "discard", "secure"
1402
+ value_attrs = ("version",
1403
+ "expires", "max-age",
1404
+ "domain", "path", "port",
1405
+ "comment", "commenturl")
1406
+
1407
+ for cookie_attrs in attrs_set:
1408
+ name, value = cookie_attrs[0]
1409
+
1410
+ # Build dictionary of standard cookie-attributes (standard) and
1411
+ # dictionary of other cookie-attributes (rest).
1412
+
1413
+ # Note: expiry time is normalised to seconds since epoch. V0
1414
+ # cookies should have the Expires cookie-attribute, and V1 cookies
1415
+ # should have Max-Age, but since V1 includes RFC 2109 cookies (and
1416
+ # since V0 cookies may be a mish-mash of Netscape and RFC 2109), we
1417
+ # accept either (but prefer Max-Age).
1418
+ max_age_set = False
1419
+
1420
+ bad_cookie = False
1421
+
1422
+ standard = {}
1423
+ rest = {}
1424
+ for k, v in cookie_attrs[1:]:
1425
+ lc = k.lower()
1426
+ # don't lose case distinction for unknown fields
1427
+ if lc in value_attrs or lc in boolean_attrs:
1428
+ k = lc
1429
+ if k in boolean_attrs and v is None:
1430
+ # boolean cookie-attribute is present, but has no value
1431
+ # (like "discard", rather than "port=80")
1432
+ v = True
1433
+ if k in standard:
1434
+ # only first value is significant
1435
+ continue
1436
+ if k == "domain":
1437
+ if v is None:
1438
+ _debug(" missing value for domain attribute")
1439
+ bad_cookie = True
1440
+ break
1441
+ # RFC 2965 section 3.3.3
1442
+ v = v.lower()
1443
+ if k == "expires":
1444
+ if max_age_set:
1445
+ # Prefer max-age to expires (like Mozilla)
1446
+ continue
1447
+ if v is None:
1448
+ _debug(" missing or invalid value for expires "
1449
+ "attribute: treating as session cookie")
1450
+ continue
1451
+ if k == "max-age":
1452
+ max_age_set = True
1453
+ try:
1454
+ v = int(v)
1455
+ except ValueError:
1456
+ _debug(" missing or invalid (non-numeric) value for "
1457
+ "max-age attribute")
1458
+ bad_cookie = True
1459
+ break
1460
+ # convert RFC 2965 Max-Age to seconds since epoch
1461
+ # XXX Strictly you're supposed to follow RFC 2616
1462
+ # age-calculation rules. Remember that zero Max-Age
1463
+ # is a request to discard (old and new) cookie, though.
1464
+ k = "expires"
1465
+ v = self._now + v
1466
+ if (k in value_attrs) or (k in boolean_attrs):
1467
+ if (v is None and
1468
+ k not in ("port", "comment", "commenturl")):
1469
+ _debug(" missing value for %s attribute" % k)
1470
+ bad_cookie = True
1471
+ break
1472
+ standard[k] = v
1473
+ else:
1474
+ rest[k] = v
1475
+
1476
+ if bad_cookie:
1477
+ continue
1478
+
1479
+ cookie_tuples.append((name, value, standard, rest))
1480
+
1481
+ return cookie_tuples
1482
+
1483
+ def _cookie_from_cookie_tuple(self, tup, request):
1484
+ # standard is dict of standard cookie-attributes, rest is dict of the
1485
+ # rest of them
1486
+ name, value, standard, rest = tup
1487
+
1488
+ domain = standard.get("domain", Absent)
1489
+ path = standard.get("path", Absent)
1490
+ port = standard.get("port", Absent)
1491
+ expires = standard.get("expires", Absent)
1492
+
1493
+ # set the easy defaults
1494
+ version = standard.get("version", None)
1495
+ if version is not None:
1496
+ try:
1497
+ version = int(version)
1498
+ except ValueError:
1499
+ return None # invalid version, ignore cookie
1500
+ secure = standard.get("secure", False)
1501
+ # (discard is also set if expires is Absent)
1502
+ discard = standard.get("discard", False)
1503
+ comment = standard.get("comment", None)
1504
+ comment_url = standard.get("commenturl", None)
1505
+
1506
+ # set default path
1507
+ if path is not Absent and path != "":
1508
+ path_specified = True
1509
+ path = escape_path(path)
1510
+ else:
1511
+ path_specified = False
1512
+ path = request_path(request)
1513
+ i = path.rfind("/")
1514
+ if i != -1:
1515
+ if version == 0:
1516
+ # Netscape spec parts company from reality here
1517
+ path = path[:i]
1518
+ else:
1519
+ path = path[:i+1]
1520
+ if len(path) == 0: path = "/"
1521
+
1522
+ # set default domain
1523
+ domain_specified = domain is not Absent
1524
+ # but first we have to remember whether it starts with a dot
1525
+ domain_initial_dot = False
1526
+ if domain_specified:
1527
+ domain_initial_dot = bool(domain.startswith("."))
1528
+ if domain is Absent:
1529
+ req_host, erhn = eff_request_host(request)
1530
+ domain = erhn
1531
+ elif not domain.startswith("."):
1532
+ domain = "."+domain
1533
+
1534
+ # set default port
1535
+ port_specified = False
1536
+ if port is not Absent:
1537
+ if port is None:
1538
+ # Port attr present, but has no value: default to request port.
1539
+ # Cookie should then only be sent back on that port.
1540
+ port = request_port(request)
1541
+ else:
1542
+ port_specified = True
1543
+ port = re.sub(r"\s+", "", port)
1544
+ else:
1545
+ # No port attr present. Cookie can be sent back on any port.
1546
+ port = None
1547
+
1548
+ # set default expires and discard
1549
+ if expires is Absent:
1550
+ expires = None
1551
+ discard = True
1552
+ elif expires <= self._now:
1553
+ # Expiry date in past is request to delete cookie. This can't be
1554
+ # in DefaultCookiePolicy, because can't delete cookies there.
1555
+ try:
1556
+ self.clear(domain, path, name)
1557
+ except KeyError:
1558
+ pass
1559
+ _debug("Expiring cookie, domain='%s', path='%s', name='%s'",
1560
+ domain, path, name)
1561
+ return None
1562
+
1563
+ return Cookie(version,
1564
+ name, value,
1565
+ port, port_specified,
1566
+ domain, domain_specified, domain_initial_dot,
1567
+ path, path_specified,
1568
+ secure,
1569
+ expires,
1570
+ discard,
1571
+ comment,
1572
+ comment_url,
1573
+ rest)
1574
+
1575
+ def _cookies_from_attrs_set(self, attrs_set, request):
1576
+ cookie_tuples = self._normalized_cookie_tuples(attrs_set)
1577
+
1578
+ cookies = []
1579
+ for tup in cookie_tuples:
1580
+ cookie = self._cookie_from_cookie_tuple(tup, request)
1581
+ if cookie: cookies.append(cookie)
1582
+ return cookies
1583
+
1584
+ def _process_rfc2109_cookies(self, cookies):
1585
+ rfc2109_as_ns = getattr(self._policy, 'rfc2109_as_netscape', None)
1586
+ if rfc2109_as_ns is None:
1587
+ rfc2109_as_ns = not self._policy.rfc2965
1588
+ for cookie in cookies:
1589
+ if cookie.version == 1:
1590
+ cookie.rfc2109 = True
1591
+ if rfc2109_as_ns:
1592
+ # treat 2109 cookies as Netscape cookies rather than
1593
+ # as RFC2965 cookies
1594
+ cookie.version = 0
1595
+
1596
+ def make_cookies(self, response, request):
1597
+ """Return sequence of Cookie objects extracted from response object."""
1598
+ # get cookie-attributes for RFC 2965 and Netscape protocols
1599
+ headers = response.info()
1600
+ rfc2965_hdrs = headers.get_all("Set-Cookie2", [])
1601
+ ns_hdrs = headers.get_all("Set-Cookie", [])
1602
+ self._policy._now = self._now = int(time.time())
1603
+
1604
+ rfc2965 = self._policy.rfc2965
1605
+ netscape = self._policy.netscape
1606
+
1607
+ if ((not rfc2965_hdrs and not ns_hdrs) or
1608
+ (not ns_hdrs and not rfc2965) or
1609
+ (not rfc2965_hdrs and not netscape) or
1610
+ (not netscape and not rfc2965)):
1611
+ return [] # no relevant cookie headers: quick exit
1612
+
1613
+ try:
1614
+ cookies = self._cookies_from_attrs_set(
1615
+ split_header_words(rfc2965_hdrs), request)
1616
+ except Exception:
1617
+ _warn_unhandled_exception()
1618
+ cookies = []
1619
+
1620
+ if ns_hdrs and netscape:
1621
+ try:
1622
+ # RFC 2109 and Netscape cookies
1623
+ ns_cookies = self._cookies_from_attrs_set(
1624
+ parse_ns_headers(ns_hdrs), request)
1625
+ except Exception:
1626
+ _warn_unhandled_exception()
1627
+ ns_cookies = []
1628
+ self._process_rfc2109_cookies(ns_cookies)
1629
+
1630
+ # Look for Netscape cookies (from Set-Cookie headers) that match
1631
+ # corresponding RFC 2965 cookies (from Set-Cookie2 headers).
1632
+ # For each match, keep the RFC 2965 cookie and ignore the Netscape
1633
+ # cookie (RFC 2965 section 9.1). Actually, RFC 2109 cookies are
1634
+ # bundled in with the Netscape cookies for this purpose, which is
1635
+ # reasonable behaviour.
1636
+ if rfc2965:
1637
+ lookup = {}
1638
+ for cookie in cookies:
1639
+ lookup[(cookie.domain, cookie.path, cookie.name)] = None
1640
+
1641
+ def no_matching_rfc2965(ns_cookie, lookup=lookup):
1642
+ key = ns_cookie.domain, ns_cookie.path, ns_cookie.name
1643
+ return key not in lookup
1644
+ ns_cookies = filter(no_matching_rfc2965, ns_cookies)
1645
+
1646
+ if ns_cookies:
1647
+ cookies.extend(ns_cookies)
1648
+
1649
+ return cookies
1650
+
1651
+ def set_cookie_if_ok(self, cookie, request):
1652
+ """Set a cookie if policy says it's OK to do so."""
1653
+ self._cookies_lock.acquire()
1654
+ try:
1655
+ self._policy._now = self._now = int(time.time())
1656
+
1657
+ if self._policy.set_ok(cookie, request):
1658
+ self.set_cookie(cookie)
1659
+
1660
+
1661
+ finally:
1662
+ self._cookies_lock.release()
1663
+
1664
+ def set_cookie(self, cookie):
1665
+ """Set a cookie, without checking whether or not it should be set."""
1666
+ c = self._cookies
1667
+ self._cookies_lock.acquire()
1668
+ try:
1669
+ if cookie.domain not in c: c[cookie.domain] = {}
1670
+ c2 = c[cookie.domain]
1671
+ if cookie.path not in c2: c2[cookie.path] = {}
1672
+ c3 = c2[cookie.path]
1673
+ c3[cookie.name] = cookie
1674
+ finally:
1675
+ self._cookies_lock.release()
1676
+
1677
+ def extract_cookies(self, response, request):
1678
+ """Extract cookies from response, where allowable given the request."""
1679
+ _debug("extract_cookies: %s", response.info())
1680
+ self._cookies_lock.acquire()
1681
+ try:
1682
+ for cookie in self.make_cookies(response, request):
1683
+ if self._policy.set_ok(cookie, request):
1684
+ _debug(" setting cookie: %s", cookie)
1685
+ self.set_cookie(cookie)
1686
+ finally:
1687
+ self._cookies_lock.release()
1688
+
1689
+ def clear(self, domain=None, path=None, name=None):
1690
+ """Clear some cookies.
1691
+
1692
+ Invoking this method without arguments will clear all cookies. If
1693
+ given a single argument, only cookies belonging to that domain will be
1694
+ removed. If given two arguments, cookies belonging to the specified
1695
+ path within that domain are removed. If given three arguments, then
1696
+ the cookie with the specified name, path and domain is removed.
1697
+
1698
+ Raises KeyError if no matching cookie exists.
1699
+
1700
+ """
1701
+ if name is not None:
1702
+ if (domain is None) or (path is None):
1703
+ raise ValueError(
1704
+ "domain and path must be given to remove a cookie by name")
1705
+ del self._cookies[domain][path][name]
1706
+ elif path is not None:
1707
+ if domain is None:
1708
+ raise ValueError(
1709
+ "domain must be given to remove cookies by path")
1710
+ del self._cookies[domain][path]
1711
+ elif domain is not None:
1712
+ del self._cookies[domain]
1713
+ else:
1714
+ self._cookies = {}
1715
+
1716
+ def clear_session_cookies(self):
1717
+ """Discard all session cookies.
1718
+
1719
+ Note that the .save() method won't save session cookies anyway, unless
1720
+ you ask otherwise by passing a true ignore_discard argument.
1721
+
1722
+ """
1723
+ self._cookies_lock.acquire()
1724
+ try:
1725
+ for cookie in self:
1726
+ if cookie.discard:
1727
+ self.clear(cookie.domain, cookie.path, cookie.name)
1728
+ finally:
1729
+ self._cookies_lock.release()
1730
+
1731
+ def clear_expired_cookies(self):
1732
+ """Discard all expired cookies.
1733
+
1734
+ You probably don't need to call this method: expired cookies are never
1735
+ sent back to the server (provided you're using DefaultCookiePolicy),
1736
+ this method is called by CookieJar itself every so often, and the
1737
+ .save() method won't save expired cookies anyway (unless you ask
1738
+ otherwise by passing a true ignore_expires argument).
1739
+
1740
+ """
1741
+ self._cookies_lock.acquire()
1742
+ try:
1743
+ now = time.time()
1744
+ for cookie in self:
1745
+ if cookie.is_expired(now):
1746
+ self.clear(cookie.domain, cookie.path, cookie.name)
1747
+ finally:
1748
+ self._cookies_lock.release()
1749
+
1750
+ def __iter__(self):
1751
+ return deepvalues(self._cookies)
1752
+
1753
+ def __len__(self):
1754
+ """Return number of contained cookies."""
1755
+ i = 0
1756
+ for cookie in self: i = i + 1
1757
+ return i
1758
+
1759
+ def __repr__(self):
1760
+ r = []
1761
+ for cookie in self: r.append(repr(cookie))
1762
+ return "<%s[%s]>" % (self.__class__.__name__, ", ".join(r))
1763
+
1764
+ def __str__(self):
1765
+ r = []
1766
+ for cookie in self: r.append(str(cookie))
1767
+ return "<%s[%s]>" % (self.__class__.__name__, ", ".join(r))
1768
+
1769
+
1770
+ # derives from OSError for backwards-compatibility with Python 2.4.0
1771
+ class LoadError(OSError): pass
1772
+
1773
+ class FileCookieJar(CookieJar):
1774
+ """CookieJar that can be loaded from and saved to a file."""
1775
+
1776
+ def __init__(self, filename=None, delayload=False, policy=None):
1777
+ """
1778
+ Cookies are NOT loaded from the named file until either the .load() or
1779
+ .revert() method is called.
1780
+
1781
+ """
1782
+ CookieJar.__init__(self, policy)
1783
+ if filename is not None:
1784
+ filename = os.fspath(filename)
1785
+ self.filename = filename
1786
+ self.delayload = bool(delayload)
1787
+
1788
+ def save(self, filename=None, ignore_discard=False, ignore_expires=False):
1789
+ """Save cookies to a file."""
1790
+ raise NotImplementedError()
1791
+
1792
+ def load(self, filename=None, ignore_discard=False, ignore_expires=False):
1793
+ """Load cookies from a file."""
1794
+ if filename is None:
1795
+ if self.filename is not None: filename = self.filename
1796
+ else: raise ValueError(MISSING_FILENAME_TEXT)
1797
+
1798
+ with open(filename) as f:
1799
+ self._really_load(f, filename, ignore_discard, ignore_expires)
1800
+
1801
+ def revert(self, filename=None,
1802
+ ignore_discard=False, ignore_expires=False):
1803
+ """Clear all cookies and reload cookies from a saved file.
1804
+
1805
+ Raises LoadError (or OSError) if reversion is not successful; the
1806
+ object's state will not be altered if this happens.
1807
+
1808
+ """
1809
+ if filename is None:
1810
+ if self.filename is not None: filename = self.filename
1811
+ else: raise ValueError(MISSING_FILENAME_TEXT)
1812
+
1813
+ self._cookies_lock.acquire()
1814
+ try:
1815
+
1816
+ old_state = copy.deepcopy(self._cookies)
1817
+ self._cookies = {}
1818
+ try:
1819
+ self.load(filename, ignore_discard, ignore_expires)
1820
+ except OSError:
1821
+ self._cookies = old_state
1822
+ raise
1823
+
1824
+ finally:
1825
+ self._cookies_lock.release()
1826
+
1827
+
1828
+ def lwp_cookie_str(cookie):
1829
+ """Return string representation of Cookie in the LWP cookie file format.
1830
+
1831
+ Actually, the format is extended a bit -- see module docstring.
1832
+
1833
+ """
1834
+ h = [(cookie.name, cookie.value),
1835
+ ("path", cookie.path),
1836
+ ("domain", cookie.domain)]
1837
+ if cookie.port is not None: h.append(("port", cookie.port))
1838
+ if cookie.path_specified: h.append(("path_spec", None))
1839
+ if cookie.port_specified: h.append(("port_spec", None))
1840
+ if cookie.domain_initial_dot: h.append(("domain_dot", None))
1841
+ if cookie.secure: h.append(("secure", None))
1842
+ if cookie.expires: h.append(("expires",
1843
+ time2isoz(float(cookie.expires))))
1844
+ if cookie.discard: h.append(("discard", None))
1845
+ if cookie.comment: h.append(("comment", cookie.comment))
1846
+ if cookie.comment_url: h.append(("commenturl", cookie.comment_url))
1847
+
1848
+ keys = sorted(cookie._rest.keys())
1849
+ for k in keys:
1850
+ h.append((k, str(cookie._rest[k])))
1851
+
1852
+ h.append(("version", str(cookie.version)))
1853
+
1854
+ return join_header_words([h])
1855
+
1856
+ class LWPCookieJar(FileCookieJar):
1857
+ """
1858
+ The LWPCookieJar saves a sequence of "Set-Cookie3" lines.
1859
+ "Set-Cookie3" is the format used by the libwww-perl library, not known
1860
+ to be compatible with any browser, but which is easy to read and
1861
+ doesn't lose information about RFC 2965 cookies.
1862
+
1863
+ Additional methods
1864
+
1865
+ as_lwp_str(ignore_discard=True, ignore_expired=True)
1866
+
1867
+ """
1868
+
1869
+ def as_lwp_str(self, ignore_discard=True, ignore_expires=True):
1870
+ """Return cookies as a string of "\\n"-separated "Set-Cookie3" headers.
1871
+
1872
+ ignore_discard and ignore_expires: see docstring for FileCookieJar.save
1873
+
1874
+ """
1875
+ now = time.time()
1876
+ r = []
1877
+ for cookie in self:
1878
+ if not ignore_discard and cookie.discard:
1879
+ continue
1880
+ if not ignore_expires and cookie.is_expired(now):
1881
+ continue
1882
+ r.append("Set-Cookie3: %s" % lwp_cookie_str(cookie))
1883
+ return "\n".join(r+[""])
1884
+
1885
+ def save(self, filename=None, ignore_discard=False, ignore_expires=False):
1886
+ if filename is None:
1887
+ if self.filename is not None: filename = self.filename
1888
+ else: raise ValueError(MISSING_FILENAME_TEXT)
1889
+
1890
+ with open(filename, "w") as f:
1891
+ # There really isn't an LWP Cookies 2.0 format, but this indicates
1892
+ # that there is extra information in here (domain_dot and
1893
+ # port_spec) while still being compatible with libwww-perl, I hope.
1894
+ f.write("#LWP-Cookies-2.0\n")
1895
+ f.write(self.as_lwp_str(ignore_discard, ignore_expires))
1896
+
1897
+ def _really_load(self, f, filename, ignore_discard, ignore_expires):
1898
+ magic = f.readline()
1899
+ if not self.magic_re.search(magic):
1900
+ msg = ("%r does not look like a Set-Cookie3 (LWP) format "
1901
+ "file" % filename)
1902
+ raise LoadError(msg)
1903
+
1904
+ now = time.time()
1905
+
1906
+ header = "Set-Cookie3:"
1907
+ boolean_attrs = ("port_spec", "path_spec", "domain_dot",
1908
+ "secure", "discard")
1909
+ value_attrs = ("version",
1910
+ "port", "path", "domain",
1911
+ "expires",
1912
+ "comment", "commenturl")
1913
+
1914
+ try:
1915
+ while 1:
1916
+ line = f.readline()
1917
+ if line == "": break
1918
+ if not line.startswith(header):
1919
+ continue
1920
+ line = line[len(header):].strip()
1921
+
1922
+ for data in split_header_words([line]):
1923
+ name, value = data[0]
1924
+ standard = {}
1925
+ rest = {}
1926
+ for k in boolean_attrs:
1927
+ standard[k] = False
1928
+ for k, v in data[1:]:
1929
+ if k is not None:
1930
+ lc = k.lower()
1931
+ else:
1932
+ lc = None
1933
+ # don't lose case distinction for unknown fields
1934
+ if (lc in value_attrs) or (lc in boolean_attrs):
1935
+ k = lc
1936
+ if k in boolean_attrs:
1937
+ if v is None: v = True
1938
+ standard[k] = v
1939
+ elif k in value_attrs:
1940
+ standard[k] = v
1941
+ else:
1942
+ rest[k] = v
1943
+
1944
+ h = standard.get
1945
+ expires = h("expires")
1946
+ discard = h("discard")
1947
+ if expires is not None:
1948
+ expires = iso2time(expires)
1949
+ if expires is None:
1950
+ discard = True
1951
+ domain = h("domain")
1952
+ domain_specified = domain.startswith(".")
1953
+ c = Cookie(h("version"), name, value,
1954
+ h("port"), h("port_spec"),
1955
+ domain, domain_specified, h("domain_dot"),
1956
+ h("path"), h("path_spec"),
1957
+ h("secure"),
1958
+ expires,
1959
+ discard,
1960
+ h("comment"),
1961
+ h("commenturl"),
1962
+ rest)
1963
+ if not ignore_discard and c.discard:
1964
+ continue
1965
+ if not ignore_expires and c.is_expired(now):
1966
+ continue
1967
+ self.set_cookie(c)
1968
+ except OSError:
1969
+ raise
1970
+ except Exception:
1971
+ _warn_unhandled_exception()
1972
+ raise LoadError("invalid Set-Cookie3 format file %r: %r" %
1973
+ (filename, line))
1974
+
1975
+
1976
+ class MozillaCookieJar(FileCookieJar):
1977
+ """
1978
+
1979
+ WARNING: you may want to backup your browser's cookies file if you use
1980
+ this class to save cookies. I *think* it works, but there have been
1981
+ bugs in the past!
1982
+
1983
+ This class differs from CookieJar only in the format it uses to save and
1984
+ load cookies to and from a file. This class uses the Mozilla/Netscape
1985
+ `cookies.txt' format. lynx uses this file format, too.
1986
+
1987
+ Don't expect cookies saved while the browser is running to be noticed by
1988
+ the browser (in fact, Mozilla on unix will overwrite your saved cookies if
1989
+ you change them on disk while it's running; on Windows, you probably can't
1990
+ save at all while the browser is running).
1991
+
1992
+ Note that the Mozilla/Netscape format will downgrade RFC2965 cookies to
1993
+ Netscape cookies on saving.
1994
+
1995
+ In particular, the cookie version and port number information is lost,
1996
+ together with information about whether or not Path, Port and Discard were
1997
+ specified by the Set-Cookie2 (or Set-Cookie) header, and whether or not the
1998
+ domain as set in the HTTP header started with a dot (yes, I'm aware some
1999
+ domains in Netscape files start with a dot and some don't -- trust me, you
2000
+ really don't want to know any more about this).
2001
+
2002
+ Note that though Mozilla and Netscape use the same format, they use
2003
+ slightly different headers. The class saves cookies using the Netscape
2004
+ header by default (Mozilla can cope with that).
2005
+
2006
+ """
2007
+ magic_re = re.compile("#( Netscape)? HTTP Cookie File")
2008
+ header = """\
2009
+ # Netscape HTTP Cookie File
2010
+ # http://curl.haxx.se/rfc/cookie_spec.html
2011
+ # This is a generated file! Do not edit.
2012
+
2013
+ """
2014
+
2015
+ def _really_load(self, f, filename, ignore_discard, ignore_expires):
2016
+ now = time.time()
2017
+
2018
+ magic = f.readline()
2019
+ if not self.magic_re.search(magic):
2020
+ raise LoadError(
2021
+ "%r does not look like a Netscape format cookies file" %
2022
+ filename)
2023
+
2024
+ try:
2025
+ while 1:
2026
+ line = f.readline()
2027
+ if line == "": break
2028
+
2029
+ # last field may be absent, so keep any trailing tab
2030
+ if line.endswith("\n"): line = line[:-1]
2031
+
2032
+ # skip comments and blank lines XXX what is $ for?
2033
+ if (line.strip().startswith(("#", "$")) or
2034
+ line.strip() == ""):
2035
+ continue
2036
+
2037
+ domain, domain_specified, path, secure, expires, name, value = \
2038
+ line.split("\t")
2039
+ secure = (secure == "TRUE")
2040
+ domain_specified = (domain_specified == "TRUE")
2041
+ if name == "":
2042
+ # cookies.txt regards 'Set-Cookie: foo' as a cookie
2043
+ # with no name, whereas http.cookiejar regards it as a
2044
+ # cookie with no value.
2045
+ name = value
2046
+ value = None
2047
+
2048
+ initial_dot = domain.startswith(".")
2049
+ assert domain_specified == initial_dot
2050
+
2051
+ discard = False
2052
+ if expires == "":
2053
+ expires = None
2054
+ discard = True
2055
+
2056
+ # assume path_specified is false
2057
+ c = Cookie(0, name, value,
2058
+ None, False,
2059
+ domain, domain_specified, initial_dot,
2060
+ path, False,
2061
+ secure,
2062
+ expires,
2063
+ discard,
2064
+ None,
2065
+ None,
2066
+ {})
2067
+ if not ignore_discard and c.discard:
2068
+ continue
2069
+ if not ignore_expires and c.is_expired(now):
2070
+ continue
2071
+ self.set_cookie(c)
2072
+
2073
+ except OSError:
2074
+ raise
2075
+ except Exception:
2076
+ _warn_unhandled_exception()
2077
+ raise LoadError("invalid Netscape format cookies file %r: %r" %
2078
+ (filename, line))
2079
+
2080
+ def save(self, filename=None, ignore_discard=False, ignore_expires=False):
2081
+ if filename is None:
2082
+ if self.filename is not None: filename = self.filename
2083
+ else: raise ValueError(MISSING_FILENAME_TEXT)
2084
+
2085
+ with open(filename, "w") as f:
2086
+ f.write(self.header)
2087
+ now = time.time()
2088
+ for cookie in self:
2089
+ if not ignore_discard and cookie.discard:
2090
+ continue
2091
+ if not ignore_expires and cookie.is_expired(now):
2092
+ continue
2093
+ if cookie.secure: secure = "TRUE"
2094
+ else: secure = "FALSE"
2095
+ if cookie.domain.startswith("."): initial_dot = "TRUE"
2096
+ else: initial_dot = "FALSE"
2097
+ if cookie.expires is not None:
2098
+ expires = str(cookie.expires)
2099
+ else:
2100
+ expires = ""
2101
+ if cookie.value is None:
2102
+ # cookies.txt regards 'Set-Cookie: foo' as a cookie
2103
+ # with no name, whereas http.cookiejar regards it as a
2104
+ # cookie with no value.
2105
+ name = ""
2106
+ value = cookie.name
2107
+ else:
2108
+ name = cookie.name
2109
+ value = cookie.value
2110
+ f.write(
2111
+ "\t".join([cookie.domain, initial_dot, cookie.path,
2112
+ secure, expires, name, value])+
2113
+ "\n")
my_container_sandbox/workspace/anaconda3/lib/python3.8/http/cookies.py ADDED
@@ -0,0 +1,609 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ####
2
+ # Copyright 2000 by Timothy O'Malley <timo@alum.mit.edu>
3
+ #
4
+ # All Rights Reserved
5
+ #
6
+ # Permission to use, copy, modify, and distribute this software
7
+ # and its documentation for any purpose and without fee is hereby
8
+ # granted, provided that the above copyright notice appear in all
9
+ # copies and that both that copyright notice and this permission
10
+ # notice appear in supporting documentation, and that the name of
11
+ # Timothy O'Malley not be used in advertising or publicity
12
+ # pertaining to distribution of the software without specific, written
13
+ # prior permission.
14
+ #
15
+ # Timothy O'Malley DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
16
+ # SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
17
+ # AND FITNESS, IN NO EVENT SHALL Timothy O'Malley BE LIABLE FOR
18
+ # ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19
+ # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
20
+ # WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
21
+ # ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
22
+ # PERFORMANCE OF THIS SOFTWARE.
23
+ #
24
+ ####
25
+ #
26
+ # Id: Cookie.py,v 2.29 2000/08/23 05:28:49 timo Exp
27
+ # by Timothy O'Malley <timo@alum.mit.edu>
28
+ #
29
+ # Cookie.py is a Python module for the handling of HTTP
30
+ # cookies as a Python dictionary. See RFC 2109 for more
31
+ # information on cookies.
32
+ #
33
+ # The original idea to treat Cookies as a dictionary came from
34
+ # Dave Mitchell (davem@magnet.com) in 1995, when he released the
35
+ # first version of nscookie.py.
36
+ #
37
+ ####
38
+
39
+ r"""
40
+ Here's a sample session to show how to use this module.
41
+ At the moment, this is the only documentation.
42
+
43
+ The Basics
44
+ ----------
45
+
46
+ Importing is easy...
47
+
48
+ >>> from http import cookies
49
+
50
+ Most of the time you start by creating a cookie.
51
+
52
+ >>> C = cookies.SimpleCookie()
53
+
54
+ Once you've created your Cookie, you can add values just as if it were
55
+ a dictionary.
56
+
57
+ >>> C = cookies.SimpleCookie()
58
+ >>> C["fig"] = "newton"
59
+ >>> C["sugar"] = "wafer"
60
+ >>> C.output()
61
+ 'Set-Cookie: fig=newton\r\nSet-Cookie: sugar=wafer'
62
+
63
+ Notice that the printable representation of a Cookie is the
64
+ appropriate format for a Set-Cookie: header. This is the
65
+ default behavior. You can change the header and printed
66
+ attributes by using the .output() function
67
+
68
+ >>> C = cookies.SimpleCookie()
69
+ >>> C["rocky"] = "road"
70
+ >>> C["rocky"]["path"] = "/cookie"
71
+ >>> print(C.output(header="Cookie:"))
72
+ Cookie: rocky=road; Path=/cookie
73
+ >>> print(C.output(attrs=[], header="Cookie:"))
74
+ Cookie: rocky=road
75
+
76
+ The load() method of a Cookie extracts cookies from a string. In a
77
+ CGI script, you would use this method to extract the cookies from the
78
+ HTTP_COOKIE environment variable.
79
+
80
+ >>> C = cookies.SimpleCookie()
81
+ >>> C.load("chips=ahoy; vienna=finger")
82
+ >>> C.output()
83
+ 'Set-Cookie: chips=ahoy\r\nSet-Cookie: vienna=finger'
84
+
85
+ The load() method is darn-tootin smart about identifying cookies
86
+ within a string. Escaped quotation marks, nested semicolons, and other
87
+ such trickeries do not confuse it.
88
+
89
+ >>> C = cookies.SimpleCookie()
90
+ >>> C.load('keebler="E=everybody; L=\\"Loves\\"; fudge=\\012;";')
91
+ >>> print(C)
92
+ Set-Cookie: keebler="E=everybody; L=\"Loves\"; fudge=\012;"
93
+
94
+ Each element of the Cookie also supports all of the RFC 2109
95
+ Cookie attributes. Here's an example which sets the Path
96
+ attribute.
97
+
98
+ >>> C = cookies.SimpleCookie()
99
+ >>> C["oreo"] = "doublestuff"
100
+ >>> C["oreo"]["path"] = "/"
101
+ >>> print(C)
102
+ Set-Cookie: oreo=doublestuff; Path=/
103
+
104
+ Each dictionary element has a 'value' attribute, which gives you
105
+ back the value associated with the key.
106
+
107
+ >>> C = cookies.SimpleCookie()
108
+ >>> C["twix"] = "none for you"
109
+ >>> C["twix"].value
110
+ 'none for you'
111
+
112
+ The SimpleCookie expects that all values should be standard strings.
113
+ Just to be sure, SimpleCookie invokes the str() builtin to convert
114
+ the value to a string, when the values are set dictionary-style.
115
+
116
+ >>> C = cookies.SimpleCookie()
117
+ >>> C["number"] = 7
118
+ >>> C["string"] = "seven"
119
+ >>> C["number"].value
120
+ '7'
121
+ >>> C["string"].value
122
+ 'seven'
123
+ >>> C.output()
124
+ 'Set-Cookie: number=7\r\nSet-Cookie: string=seven'
125
+
126
+ Finis.
127
+ """
128
+
129
+ #
130
+ # Import our required modules
131
+ #
132
+ import re
133
+ import string
134
+
135
+ __all__ = ["CookieError", "BaseCookie", "SimpleCookie"]
136
+
137
+ _nulljoin = ''.join
138
+ _semispacejoin = '; '.join
139
+ _spacejoin = ' '.join
140
+
141
+ #
142
+ # Define an exception visible to External modules
143
+ #
144
+ class CookieError(Exception):
145
+ pass
146
+
147
+
148
+ # These quoting routines conform to the RFC2109 specification, which in
149
+ # turn references the character definitions from RFC2068. They provide
150
+ # a two-way quoting algorithm. Any non-text character is translated
151
+ # into a 4 character sequence: a forward-slash followed by the
152
+ # three-digit octal equivalent of the character. Any '\' or '"' is
153
+ # quoted with a preceding '\' slash.
154
+ # Because of the way browsers really handle cookies (as opposed to what
155
+ # the RFC says) we also encode "," and ";".
156
+ #
157
+ # These are taken from RFC2068 and RFC2109.
158
+ # _LegalChars is the list of chars which don't require "'s
159
+ # _Translator hash-table for fast quoting
160
+ #
161
+ _LegalChars = string.ascii_letters + string.digits + "!#$%&'*+-.^_`|~:"
162
+ _UnescapedChars = _LegalChars + ' ()/<=>?@[]{}'
163
+
164
+ _Translator = {n: '\\%03o' % n
165
+ for n in set(range(256)) - set(map(ord, _UnescapedChars))}
166
+ _Translator.update({
167
+ ord('"'): '\\"',
168
+ ord('\\'): '\\\\',
169
+ })
170
+
171
+ _is_legal_key = re.compile('[%s]+' % re.escape(_LegalChars)).fullmatch
172
+
173
+ def _quote(str):
174
+ r"""Quote a string for use in a cookie header.
175
+
176
+ If the string does not need to be double-quoted, then just return the
177
+ string. Otherwise, surround the string in doublequotes and quote
178
+ (with a \) special characters.
179
+ """
180
+ if str is None or _is_legal_key(str):
181
+ return str
182
+ else:
183
+ return '"' + str.translate(_Translator) + '"'
184
+
185
+
186
+ _OctalPatt = re.compile(r"\\[0-3][0-7][0-7]")
187
+ _QuotePatt = re.compile(r"[\\].")
188
+
189
+ def _unquote(str):
190
+ # If there aren't any doublequotes,
191
+ # then there can't be any special characters. See RFC 2109.
192
+ if str is None or len(str) < 2:
193
+ return str
194
+ if str[0] != '"' or str[-1] != '"':
195
+ return str
196
+
197
+ # We have to assume that we must decode this string.
198
+ # Down to work.
199
+
200
+ # Remove the "s
201
+ str = str[1:-1]
202
+
203
+ # Check for special sequences. Examples:
204
+ # \012 --> \n
205
+ # \" --> "
206
+ #
207
+ i = 0
208
+ n = len(str)
209
+ res = []
210
+ while 0 <= i < n:
211
+ o_match = _OctalPatt.search(str, i)
212
+ q_match = _QuotePatt.search(str, i)
213
+ if not o_match and not q_match: # Neither matched
214
+ res.append(str[i:])
215
+ break
216
+ # else:
217
+ j = k = -1
218
+ if o_match:
219
+ j = o_match.start(0)
220
+ if q_match:
221
+ k = q_match.start(0)
222
+ if q_match and (not o_match or k < j): # QuotePatt matched
223
+ res.append(str[i:k])
224
+ res.append(str[k+1])
225
+ i = k + 2
226
+ else: # OctalPatt matched
227
+ res.append(str[i:j])
228
+ res.append(chr(int(str[j+1:j+4], 8)))
229
+ i = j + 4
230
+ return _nulljoin(res)
231
+
232
+ # The _getdate() routine is used to set the expiration time in the cookie's HTTP
233
+ # header. By default, _getdate() returns the current time in the appropriate
234
+ # "expires" format for a Set-Cookie header. The one optional argument is an
235
+ # offset from now, in seconds. For example, an offset of -3600 means "one hour
236
+ # ago". The offset may be a floating point number.
237
+ #
238
+
239
+ _weekdayname = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
240
+
241
+ _monthname = [None,
242
+ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
243
+ 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
244
+
245
+ def _getdate(future=0, weekdayname=_weekdayname, monthname=_monthname):
246
+ from time import gmtime, time
247
+ now = time()
248
+ year, month, day, hh, mm, ss, wd, y, z = gmtime(now + future)
249
+ return "%s, %02d %3s %4d %02d:%02d:%02d GMT" % \
250
+ (weekdayname[wd], day, monthname[month], year, hh, mm, ss)
251
+
252
+
253
+ class Morsel(dict):
254
+ """A class to hold ONE (key, value) pair.
255
+
256
+ In a cookie, each such pair may have several attributes, so this class is
257
+ used to keep the attributes associated with the appropriate key,value pair.
258
+ This class also includes a coded_value attribute, which is used to hold
259
+ the network representation of the value.
260
+ """
261
+ # RFC 2109 lists these attributes as reserved:
262
+ # path comment domain
263
+ # max-age secure version
264
+ #
265
+ # For historical reasons, these attributes are also reserved:
266
+ # expires
267
+ #
268
+ # This is an extension from Microsoft:
269
+ # httponly
270
+ #
271
+ # This dictionary provides a mapping from the lowercase
272
+ # variant on the left to the appropriate traditional
273
+ # formatting on the right.
274
+ _reserved = {
275
+ "expires" : "expires",
276
+ "path" : "Path",
277
+ "comment" : "Comment",
278
+ "domain" : "Domain",
279
+ "max-age" : "Max-Age",
280
+ "secure" : "Secure",
281
+ "httponly" : "HttpOnly",
282
+ "version" : "Version",
283
+ "samesite" : "SameSite",
284
+ }
285
+
286
+ _flags = {'secure', 'httponly'}
287
+
288
+ def __init__(self):
289
+ # Set defaults
290
+ self._key = self._value = self._coded_value = None
291
+
292
+ # Set default attributes
293
+ for key in self._reserved:
294
+ dict.__setitem__(self, key, "")
295
+
296
+ @property
297
+ def key(self):
298
+ return self._key
299
+
300
+ @property
301
+ def value(self):
302
+ return self._value
303
+
304
+ @property
305
+ def coded_value(self):
306
+ return self._coded_value
307
+
308
+ def __setitem__(self, K, V):
309
+ K = K.lower()
310
+ if not K in self._reserved:
311
+ raise CookieError("Invalid attribute %r" % (K,))
312
+ dict.__setitem__(self, K, V)
313
+
314
+ def setdefault(self, key, val=None):
315
+ key = key.lower()
316
+ if key not in self._reserved:
317
+ raise CookieError("Invalid attribute %r" % (key,))
318
+ return dict.setdefault(self, key, val)
319
+
320
+ def __eq__(self, morsel):
321
+ if not isinstance(morsel, Morsel):
322
+ return NotImplemented
323
+ return (dict.__eq__(self, morsel) and
324
+ self._value == morsel._value and
325
+ self._key == morsel._key and
326
+ self._coded_value == morsel._coded_value)
327
+
328
+ __ne__ = object.__ne__
329
+
330
+ def copy(self):
331
+ morsel = Morsel()
332
+ dict.update(morsel, self)
333
+ morsel.__dict__.update(self.__dict__)
334
+ return morsel
335
+
336
+ def update(self, values):
337
+ data = {}
338
+ for key, val in dict(values).items():
339
+ key = key.lower()
340
+ if key not in self._reserved:
341
+ raise CookieError("Invalid attribute %r" % (key,))
342
+ data[key] = val
343
+ dict.update(self, data)
344
+
345
+ def isReservedKey(self, K):
346
+ return K.lower() in self._reserved
347
+
348
+ def set(self, key, val, coded_val):
349
+ if key.lower() in self._reserved:
350
+ raise CookieError('Attempt to set a reserved key %r' % (key,))
351
+ if not _is_legal_key(key):
352
+ raise CookieError('Illegal key %r' % (key,))
353
+
354
+ # It's a good key, so save it.
355
+ self._key = key
356
+ self._value = val
357
+ self._coded_value = coded_val
358
+
359
+ def __getstate__(self):
360
+ return {
361
+ 'key': self._key,
362
+ 'value': self._value,
363
+ 'coded_value': self._coded_value,
364
+ }
365
+
366
+ def __setstate__(self, state):
367
+ self._key = state['key']
368
+ self._value = state['value']
369
+ self._coded_value = state['coded_value']
370
+
371
+ def output(self, attrs=None, header="Set-Cookie:"):
372
+ return "%s %s" % (header, self.OutputString(attrs))
373
+
374
+ __str__ = output
375
+
376
+ def __repr__(self):
377
+ return '<%s: %s>' % (self.__class__.__name__, self.OutputString())
378
+
379
+ def js_output(self, attrs=None):
380
+ # Print javascript
381
+ return """
382
+ <script type="text/javascript">
383
+ <!-- begin hiding
384
+ document.cookie = \"%s\";
385
+ // end hiding -->
386
+ </script>
387
+ """ % (self.OutputString(attrs).replace('"', r'\"'))
388
+
389
+ def OutputString(self, attrs=None):
390
+ # Build up our result
391
+ #
392
+ result = []
393
+ append = result.append
394
+
395
+ # First, the key=value pair
396
+ append("%s=%s" % (self.key, self.coded_value))
397
+
398
+ # Now add any defined attributes
399
+ if attrs is None:
400
+ attrs = self._reserved
401
+ items = sorted(self.items())
402
+ for key, value in items:
403
+ if value == "":
404
+ continue
405
+ if key not in attrs:
406
+ continue
407
+ if key == "expires" and isinstance(value, int):
408
+ append("%s=%s" % (self._reserved[key], _getdate(value)))
409
+ elif key == "max-age" and isinstance(value, int):
410
+ append("%s=%d" % (self._reserved[key], value))
411
+ elif key == "comment" and isinstance(value, str):
412
+ append("%s=%s" % (self._reserved[key], _quote(value)))
413
+ elif key in self._flags:
414
+ if value:
415
+ append(str(self._reserved[key]))
416
+ else:
417
+ append("%s=%s" % (self._reserved[key], value))
418
+
419
+ # Return the result
420
+ return _semispacejoin(result)
421
+
422
+
423
+ #
424
+ # Pattern for finding cookie
425
+ #
426
+ # This used to be strict parsing based on the RFC2109 and RFC2068
427
+ # specifications. I have since discovered that MSIE 3.0x doesn't
428
+ # follow the character rules outlined in those specs. As a
429
+ # result, the parsing rules here are less strict.
430
+ #
431
+
432
+ _LegalKeyChars = r"\w\d!#%&'~_`><@,:/\$\*\+\-\.\^\|\)\(\?\}\{\="
433
+ _LegalValueChars = _LegalKeyChars + r'\[\]'
434
+ _CookiePattern = re.compile(r"""
435
+ \s* # Optional whitespace at start of cookie
436
+ (?P<key> # Start of group 'key'
437
+ [""" + _LegalKeyChars + r"""]+? # Any word of at least one letter
438
+ ) # End of group 'key'
439
+ ( # Optional group: there may not be a value.
440
+ \s*=\s* # Equal Sign
441
+ (?P<val> # Start of group 'val'
442
+ "(?:[^\\"]|\\.)*" # Any doublequoted string
443
+ | # or
444
+ \w{3},\s[\w\d\s-]{9,11}\s[\d:]{8}\sGMT # Special case for "expires" attr
445
+ | # or
446
+ [""" + _LegalValueChars + r"""]* # Any word or empty string
447
+ ) # End of group 'val'
448
+ )? # End of optional value group
449
+ \s* # Any number of spaces.
450
+ (\s+|;|$) # Ending either at space, semicolon, or EOS.
451
+ """, re.ASCII | re.VERBOSE) # re.ASCII may be removed if safe.
452
+
453
+
454
+ # At long last, here is the cookie class. Using this class is almost just like
455
+ # using a dictionary. See this module's docstring for example usage.
456
+ #
457
+ class BaseCookie(dict):
458
+ """A container class for a set of Morsels."""
459
+
460
+ def value_decode(self, val):
461
+ """real_value, coded_value = value_decode(STRING)
462
+ Called prior to setting a cookie's value from the network
463
+ representation. The VALUE is the value read from HTTP
464
+ header.
465
+ Override this function to modify the behavior of cookies.
466
+ """
467
+ return val, val
468
+
469
+ def value_encode(self, val):
470
+ """real_value, coded_value = value_encode(VALUE)
471
+ Called prior to setting a cookie's value from the dictionary
472
+ representation. The VALUE is the value being assigned.
473
+ Override this function to modify the behavior of cookies.
474
+ """
475
+ strval = str(val)
476
+ return strval, strval
477
+
478
+ def __init__(self, input=None):
479
+ if input:
480
+ self.load(input)
481
+
482
+ def __set(self, key, real_value, coded_value):
483
+ """Private method for setting a cookie's value"""
484
+ M = self.get(key, Morsel())
485
+ M.set(key, real_value, coded_value)
486
+ dict.__setitem__(self, key, M)
487
+
488
+ def __setitem__(self, key, value):
489
+ """Dictionary style assignment."""
490
+ if isinstance(value, Morsel):
491
+ # allow assignment of constructed Morsels (e.g. for pickling)
492
+ dict.__setitem__(self, key, value)
493
+ else:
494
+ rval, cval = self.value_encode(value)
495
+ self.__set(key, rval, cval)
496
+
497
+ def output(self, attrs=None, header="Set-Cookie:", sep="\015\012"):
498
+ """Return a string suitable for HTTP."""
499
+ result = []
500
+ items = sorted(self.items())
501
+ for key, value in items:
502
+ result.append(value.output(attrs, header))
503
+ return sep.join(result)
504
+
505
+ __str__ = output
506
+
507
+ def __repr__(self):
508
+ l = []
509
+ items = sorted(self.items())
510
+ for key, value in items:
511
+ l.append('%s=%s' % (key, repr(value.value)))
512
+ return '<%s: %s>' % (self.__class__.__name__, _spacejoin(l))
513
+
514
+ def js_output(self, attrs=None):
515
+ """Return a string suitable for JavaScript."""
516
+ result = []
517
+ items = sorted(self.items())
518
+ for key, value in items:
519
+ result.append(value.js_output(attrs))
520
+ return _nulljoin(result)
521
+
522
+ def load(self, rawdata):
523
+ """Load cookies from a string (presumably HTTP_COOKIE) or
524
+ from a dictionary. Loading cookies from a dictionary 'd'
525
+ is equivalent to calling:
526
+ map(Cookie.__setitem__, d.keys(), d.values())
527
+ """
528
+ if isinstance(rawdata, str):
529
+ self.__parse_string(rawdata)
530
+ else:
531
+ # self.update() wouldn't call our custom __setitem__
532
+ for key, value in rawdata.items():
533
+ self[key] = value
534
+ return
535
+
536
+ def __parse_string(self, str, patt=_CookiePattern):
537
+ i = 0 # Our starting point
538
+ n = len(str) # Length of string
539
+ parsed_items = [] # Parsed (type, key, value) triples
540
+ morsel_seen = False # A key=value pair was previously encountered
541
+
542
+ TYPE_ATTRIBUTE = 1
543
+ TYPE_KEYVALUE = 2
544
+
545
+ # We first parse the whole cookie string and reject it if it's
546
+ # syntactically invalid (this helps avoid some classes of injection
547
+ # attacks).
548
+ while 0 <= i < n:
549
+ # Start looking for a cookie
550
+ match = patt.match(str, i)
551
+ if not match:
552
+ # No more cookies
553
+ break
554
+
555
+ key, value = match.group("key"), match.group("val")
556
+ i = match.end(0)
557
+
558
+ if key[0] == "$":
559
+ if not morsel_seen:
560
+ # We ignore attributes which pertain to the cookie
561
+ # mechanism as a whole, such as "$Version".
562
+ # See RFC 2965. (Does anyone care?)
563
+ continue
564
+ parsed_items.append((TYPE_ATTRIBUTE, key[1:], value))
565
+ elif key.lower() in Morsel._reserved:
566
+ if not morsel_seen:
567
+ # Invalid cookie string
568
+ return
569
+ if value is None:
570
+ if key.lower() in Morsel._flags:
571
+ parsed_items.append((TYPE_ATTRIBUTE, key, True))
572
+ else:
573
+ # Invalid cookie string
574
+ return
575
+ else:
576
+ parsed_items.append((TYPE_ATTRIBUTE, key, _unquote(value)))
577
+ elif value is not None:
578
+ parsed_items.append((TYPE_KEYVALUE, key, self.value_decode(value)))
579
+ morsel_seen = True
580
+ else:
581
+ # Invalid cookie string
582
+ return
583
+
584
+ # The cookie string is valid, apply it.
585
+ M = None # current morsel
586
+ for tp, key, value in parsed_items:
587
+ if tp == TYPE_ATTRIBUTE:
588
+ assert M is not None
589
+ M[key] = value
590
+ else:
591
+ assert tp == TYPE_KEYVALUE
592
+ rval, cval = value
593
+ self.__set(key, rval, cval)
594
+ M = self[key]
595
+
596
+
597
+ class SimpleCookie(BaseCookie):
598
+ """
599
+ SimpleCookie supports strings as cookie values. When setting
600
+ the value using the dictionary assignment notation, SimpleCookie
601
+ calls the builtin str() to convert the value to a string. Values
602
+ received from HTTP are kept as strings.
603
+ """
604
+ def value_decode(self, val):
605
+ return _unquote(val), val
606
+
607
+ def value_encode(self, val):
608
+ strval = str(val)
609
+ return strval, _quote(strval)
my_container_sandbox/workspace/anaconda3/lib/python3.8/http/server.py ADDED
@@ -0,0 +1,1316 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """HTTP server classes.
2
+
3
+ Note: BaseHTTPRequestHandler doesn't implement any HTTP request; see
4
+ SimpleHTTPRequestHandler for simple implementations of GET, HEAD and POST,
5
+ and CGIHTTPRequestHandler for CGI scripts.
6
+
7
+ It does, however, optionally implement HTTP/1.1 persistent connections,
8
+ as of version 0.3.
9
+
10
+ Notes on CGIHTTPRequestHandler
11
+ ------------------------------
12
+
13
+ This class implements GET and POST requests to cgi-bin scripts.
14
+
15
+ If the os.fork() function is not present (e.g. on Windows),
16
+ subprocess.Popen() is used as a fallback, with slightly altered semantics.
17
+
18
+ In all cases, the implementation is intentionally naive -- all
19
+ requests are executed synchronously.
20
+
21
+ SECURITY WARNING: DON'T USE THIS CODE UNLESS YOU ARE INSIDE A FIREWALL
22
+ -- it may execute arbitrary Python code or external programs.
23
+
24
+ Note that status code 200 is sent prior to execution of a CGI script, so
25
+ scripts cannot send other status codes such as 302 (redirect).
26
+
27
+ XXX To do:
28
+
29
+ - log requests even later (to capture byte count)
30
+ - log user-agent header and other interesting goodies
31
+ - send error log to separate file
32
+ """
33
+
34
+
35
+ # See also:
36
+ #
37
+ # HTTP Working Group T. Berners-Lee
38
+ # INTERNET-DRAFT R. T. Fielding
39
+ # <draft-ietf-http-v10-spec-00.txt> H. Frystyk Nielsen
40
+ # Expires September 8, 1995 March 8, 1995
41
+ #
42
+ # URL: http://www.ics.uci.edu/pub/ietf/http/draft-ietf-http-v10-spec-00.txt
43
+ #
44
+ # and
45
+ #
46
+ # Network Working Group R. Fielding
47
+ # Request for Comments: 2616 et al
48
+ # Obsoletes: 2068 June 1999
49
+ # Category: Standards Track
50
+ #
51
+ # URL: http://www.faqs.org/rfcs/rfc2616.html
52
+
53
+ # Log files
54
+ # ---------
55
+ #
56
+ # Here's a quote from the NCSA httpd docs about log file format.
57
+ #
58
+ # | The logfile format is as follows. Each line consists of:
59
+ # |
60
+ # | host rfc931 authuser [DD/Mon/YYYY:hh:mm:ss] "request" ddd bbbb
61
+ # |
62
+ # | host: Either the DNS name or the IP number of the remote client
63
+ # | rfc931: Any information returned by identd for this person,
64
+ # | - otherwise.
65
+ # | authuser: If user sent a userid for authentication, the user name,
66
+ # | - otherwise.
67
+ # | DD: Day
68
+ # | Mon: Month (calendar name)
69
+ # | YYYY: Year
70
+ # | hh: hour (24-hour format, the machine's timezone)
71
+ # | mm: minutes
72
+ # | ss: seconds
73
+ # | request: The first line of the HTTP request as sent by the client.
74
+ # | ddd: the status code returned by the server, - if not available.
75
+ # | bbbb: the total number of bytes sent,
76
+ # | *not including the HTTP/1.0 header*, - if not available
77
+ # |
78
+ # | You can determine the name of the file accessed through request.
79
+ #
80
+ # (Actually, the latter is only true if you know the server configuration
81
+ # at the time the request was made!)
82
+
83
+ __version__ = "0.6"
84
+
85
+ __all__ = [
86
+ "HTTPServer", "ThreadingHTTPServer", "BaseHTTPRequestHandler",
87
+ "SimpleHTTPRequestHandler", "CGIHTTPRequestHandler",
88
+ ]
89
+
90
+ import copy
91
+ import datetime
92
+ import email.utils
93
+ import html
94
+ import http.client
95
+ import io
96
+ import itertools
97
+ import mimetypes
98
+ import os
99
+ import posixpath
100
+ import select
101
+ import shutil
102
+ import socket # For gethostbyaddr()
103
+ import socketserver
104
+ import sys
105
+ import time
106
+ import urllib.parse
107
+ import contextlib
108
+ from functools import partial
109
+
110
+ from http import HTTPStatus
111
+
112
+
113
+ # Default error message template
114
+ DEFAULT_ERROR_MESSAGE = """\
115
+ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
116
+ "http://www.w3.org/TR/html4/strict.dtd">
117
+ <html>
118
+ <head>
119
+ <meta http-equiv="Content-Type" content="text/html;charset=utf-8">
120
+ <title>Error response</title>
121
+ </head>
122
+ <body>
123
+ <h1>Error response</h1>
124
+ <p>Error code: %(code)d</p>
125
+ <p>Message: %(message)s.</p>
126
+ <p>Error code explanation: %(code)s - %(explain)s.</p>
127
+ </body>
128
+ </html>
129
+ """
130
+
131
+ DEFAULT_ERROR_CONTENT_TYPE = "text/html;charset=utf-8"
132
+
133
+ class HTTPServer(socketserver.TCPServer):
134
+
135
+ allow_reuse_address = 1 # Seems to make sense in testing environment
136
+
137
+ def server_bind(self):
138
+ """Override server_bind to store the server name."""
139
+ socketserver.TCPServer.server_bind(self)
140
+ host, port = self.server_address[:2]
141
+ self.server_name = socket.getfqdn(host)
142
+ self.server_port = port
143
+
144
+
145
+ class ThreadingHTTPServer(socketserver.ThreadingMixIn, HTTPServer):
146
+ daemon_threads = True
147
+
148
+
149
+ class BaseHTTPRequestHandler(socketserver.StreamRequestHandler):
150
+
151
+ """HTTP request handler base class.
152
+
153
+ The following explanation of HTTP serves to guide you through the
154
+ code as well as to expose any misunderstandings I may have about
155
+ HTTP (so you don't need to read the code to figure out I'm wrong
156
+ :-).
157
+
158
+ HTTP (HyperText Transfer Protocol) is an extensible protocol on
159
+ top of a reliable stream transport (e.g. TCP/IP). The protocol
160
+ recognizes three parts to a request:
161
+
162
+ 1. One line identifying the request type and path
163
+ 2. An optional set of RFC-822-style headers
164
+ 3. An optional data part
165
+
166
+ The headers and data are separated by a blank line.
167
+
168
+ The first line of the request has the form
169
+
170
+ <command> <path> <version>
171
+
172
+ where <command> is a (case-sensitive) keyword such as GET or POST,
173
+ <path> is a string containing path information for the request,
174
+ and <version> should be the string "HTTP/1.0" or "HTTP/1.1".
175
+ <path> is encoded using the URL encoding scheme (using %xx to signify
176
+ the ASCII character with hex code xx).
177
+
178
+ The specification specifies that lines are separated by CRLF but
179
+ for compatibility with the widest range of clients recommends
180
+ servers also handle LF. Similarly, whitespace in the request line
181
+ is treated sensibly (allowing multiple spaces between components
182
+ and allowing trailing whitespace).
183
+
184
+ Similarly, for output, lines ought to be separated by CRLF pairs
185
+ but most clients grok LF characters just fine.
186
+
187
+ If the first line of the request has the form
188
+
189
+ <command> <path>
190
+
191
+ (i.e. <version> is left out) then this is assumed to be an HTTP
192
+ 0.9 request; this form has no optional headers and data part and
193
+ the reply consists of just the data.
194
+
195
+ The reply form of the HTTP 1.x protocol again has three parts:
196
+
197
+ 1. One line giving the response code
198
+ 2. An optional set of RFC-822-style headers
199
+ 3. The data
200
+
201
+ Again, the headers and data are separated by a blank line.
202
+
203
+ The response code line has the form
204
+
205
+ <version> <responsecode> <responsestring>
206
+
207
+ where <version> is the protocol version ("HTTP/1.0" or "HTTP/1.1"),
208
+ <responsecode> is a 3-digit response code indicating success or
209
+ failure of the request, and <responsestring> is an optional
210
+ human-readable string explaining what the response code means.
211
+
212
+ This server parses the request and the headers, and then calls a
213
+ function specific to the request type (<command>). Specifically,
214
+ a request SPAM will be handled by a method do_SPAM(). If no
215
+ such method exists the server sends an error response to the
216
+ client. If it exists, it is called with no arguments:
217
+
218
+ do_SPAM()
219
+
220
+ Note that the request name is case sensitive (i.e. SPAM and spam
221
+ are different requests).
222
+
223
+ The various request details are stored in instance variables:
224
+
225
+ - client_address is the client IP address in the form (host,
226
+ port);
227
+
228
+ - command, path and version are the broken-down request line;
229
+
230
+ - headers is an instance of email.message.Message (or a derived
231
+ class) containing the header information;
232
+
233
+ - rfile is a file object open for reading positioned at the
234
+ start of the optional input data part;
235
+
236
+ - wfile is a file object open for writing.
237
+
238
+ IT IS IMPORTANT TO ADHERE TO THE PROTOCOL FOR WRITING!
239
+
240
+ The first thing to be written must be the response line. Then
241
+ follow 0 or more header lines, then a blank line, and then the
242
+ actual data (if any). The meaning of the header lines depends on
243
+ the command executed by the server; in most cases, when data is
244
+ returned, there should be at least one header line of the form
245
+
246
+ Content-type: <type>/<subtype>
247
+
248
+ where <type> and <subtype> should be registered MIME types,
249
+ e.g. "text/html" or "text/plain".
250
+
251
+ """
252
+
253
+ # The Python system version, truncated to its first component.
254
+ sys_version = "Python/" + sys.version.split()[0]
255
+
256
+ # The server software version. You may want to override this.
257
+ # The format is multiple whitespace-separated strings,
258
+ # where each string is of the form name[/version].
259
+ server_version = "BaseHTTP/" + __version__
260
+
261
+ error_message_format = DEFAULT_ERROR_MESSAGE
262
+ error_content_type = DEFAULT_ERROR_CONTENT_TYPE
263
+
264
+ # The default request version. This only affects responses up until
265
+ # the point where the request line is parsed, so it mainly decides what
266
+ # the client gets back when sending a malformed request line.
267
+ # Most web servers default to HTTP 0.9, i.e. don't send a status line.
268
+ default_request_version = "HTTP/0.9"
269
+
270
+ def parse_request(self):
271
+ """Parse a request (internal).
272
+
273
+ The request should be stored in self.raw_requestline; the results
274
+ are in self.command, self.path, self.request_version and
275
+ self.headers.
276
+
277
+ Return True for success, False for failure; on failure, any relevant
278
+ error response has already been sent back.
279
+
280
+ """
281
+ self.command = None # set in case of error on the first line
282
+ self.request_version = version = self.default_request_version
283
+ self.close_connection = True
284
+ requestline = str(self.raw_requestline, 'iso-8859-1')
285
+ requestline = requestline.rstrip('\r\n')
286
+ self.requestline = requestline
287
+ words = requestline.split()
288
+ if len(words) == 0:
289
+ return False
290
+
291
+ if len(words) >= 3: # Enough to determine protocol version
292
+ version = words[-1]
293
+ try:
294
+ if not version.startswith('HTTP/'):
295
+ raise ValueError
296
+ base_version_number = version.split('/', 1)[1]
297
+ version_number = base_version_number.split(".")
298
+ # RFC 2145 section 3.1 says there can be only one "." and
299
+ # - major and minor numbers MUST be treated as
300
+ # separate integers;
301
+ # - HTTP/2.4 is a lower version than HTTP/2.13, which in
302
+ # turn is lower than HTTP/12.3;
303
+ # - Leading zeros MUST be ignored by recipients.
304
+ if len(version_number) != 2:
305
+ raise ValueError
306
+ version_number = int(version_number[0]), int(version_number[1])
307
+ except (ValueError, IndexError):
308
+ self.send_error(
309
+ HTTPStatus.BAD_REQUEST,
310
+ "Bad request version (%r)" % version)
311
+ return False
312
+ if version_number >= (1, 1) and self.protocol_version >= "HTTP/1.1":
313
+ self.close_connection = False
314
+ if version_number >= (2, 0):
315
+ self.send_error(
316
+ HTTPStatus.HTTP_VERSION_NOT_SUPPORTED,
317
+ "Invalid HTTP version (%s)" % base_version_number)
318
+ return False
319
+ self.request_version = version
320
+
321
+ if not 2 <= len(words) <= 3:
322
+ self.send_error(
323
+ HTTPStatus.BAD_REQUEST,
324
+ "Bad request syntax (%r)" % requestline)
325
+ return False
326
+ command, path = words[:2]
327
+ if len(words) == 2:
328
+ self.close_connection = True
329
+ if command != 'GET':
330
+ self.send_error(
331
+ HTTPStatus.BAD_REQUEST,
332
+ "Bad HTTP/0.9 request type (%r)" % command)
333
+ return False
334
+ self.command, self.path = command, path
335
+
336
+ # gh-87389: The purpose of replacing '//' with '/' is to protect
337
+ # against open redirect attacks possibly triggered if the path starts
338
+ # with '//' because http clients treat //path as an absolute URI
339
+ # without scheme (similar to http://path) rather than a path.
340
+ if self.path.startswith('//'):
341
+ self.path = '/' + self.path.lstrip('/') # Reduce to a single /
342
+
343
+ # Examine the headers and look for a Connection directive.
344
+ try:
345
+ self.headers = http.client.parse_headers(self.rfile,
346
+ _class=self.MessageClass)
347
+ except http.client.LineTooLong as err:
348
+ self.send_error(
349
+ HTTPStatus.REQUEST_HEADER_FIELDS_TOO_LARGE,
350
+ "Line too long",
351
+ str(err))
352
+ return False
353
+ except http.client.HTTPException as err:
354
+ self.send_error(
355
+ HTTPStatus.REQUEST_HEADER_FIELDS_TOO_LARGE,
356
+ "Too many headers",
357
+ str(err)
358
+ )
359
+ return False
360
+
361
+ conntype = self.headers.get('Connection', "")
362
+ if conntype.lower() == 'close':
363
+ self.close_connection = True
364
+ elif (conntype.lower() == 'keep-alive' and
365
+ self.protocol_version >= "HTTP/1.1"):
366
+ self.close_connection = False
367
+ # Examine the headers and look for an Expect directive
368
+ expect = self.headers.get('Expect', "")
369
+ if (expect.lower() == "100-continue" and
370
+ self.protocol_version >= "HTTP/1.1" and
371
+ self.request_version >= "HTTP/1.1"):
372
+ if not self.handle_expect_100():
373
+ return False
374
+ return True
375
+
376
+ def handle_expect_100(self):
377
+ """Decide what to do with an "Expect: 100-continue" header.
378
+
379
+ If the client is expecting a 100 Continue response, we must
380
+ respond with either a 100 Continue or a final response before
381
+ waiting for the request body. The default is to always respond
382
+ with a 100 Continue. You can behave differently (for example,
383
+ reject unauthorized requests) by overriding this method.
384
+
385
+ This method should either return True (possibly after sending
386
+ a 100 Continue response) or send an error response and return
387
+ False.
388
+
389
+ """
390
+ self.send_response_only(HTTPStatus.CONTINUE)
391
+ self.end_headers()
392
+ return True
393
+
394
+ def handle_one_request(self):
395
+ """Handle a single HTTP request.
396
+
397
+ You normally don't need to override this method; see the class
398
+ __doc__ string for information on how to handle specific HTTP
399
+ commands such as GET and POST.
400
+
401
+ """
402
+ try:
403
+ self.raw_requestline = self.rfile.readline(65537)
404
+ if len(self.raw_requestline) > 65536:
405
+ self.requestline = ''
406
+ self.request_version = ''
407
+ self.command = ''
408
+ self.send_error(HTTPStatus.REQUEST_URI_TOO_LONG)
409
+ return
410
+ if not self.raw_requestline:
411
+ self.close_connection = True
412
+ return
413
+ if not self.parse_request():
414
+ # An error code has been sent, just exit
415
+ return
416
+ mname = 'do_' + self.command
417
+ if not hasattr(self, mname):
418
+ self.send_error(
419
+ HTTPStatus.NOT_IMPLEMENTED,
420
+ "Unsupported method (%r)" % self.command)
421
+ return
422
+ method = getattr(self, mname)
423
+ method()
424
+ self.wfile.flush() #actually send the response if not already done.
425
+ except socket.timeout as e:
426
+ #a read or a write timed out. Discard this connection
427
+ self.log_error("Request timed out: %r", e)
428
+ self.close_connection = True
429
+ return
430
+
431
+ def handle(self):
432
+ """Handle multiple requests if necessary."""
433
+ self.close_connection = True
434
+
435
+ self.handle_one_request()
436
+ while not self.close_connection:
437
+ self.handle_one_request()
438
+
439
+ def send_error(self, code, message=None, explain=None):
440
+ """Send and log an error reply.
441
+
442
+ Arguments are
443
+ * code: an HTTP error code
444
+ 3 digits
445
+ * message: a simple optional 1 line reason phrase.
446
+ *( HTAB / SP / VCHAR / %x80-FF )
447
+ defaults to short entry matching the response code
448
+ * explain: a detailed message defaults to the long entry
449
+ matching the response code.
450
+
451
+ This sends an error response (so it must be called before any
452
+ output has been generated), logs the error, and finally sends
453
+ a piece of HTML explaining the error to the user.
454
+
455
+ """
456
+
457
+ try:
458
+ shortmsg, longmsg = self.responses[code]
459
+ except KeyError:
460
+ shortmsg, longmsg = '???', '???'
461
+ if message is None:
462
+ message = shortmsg
463
+ if explain is None:
464
+ explain = longmsg
465
+ self.log_error("code %d, message %s", code, message)
466
+ self.send_response(code, message)
467
+ self.send_header('Connection', 'close')
468
+
469
+ # Message body is omitted for cases described in:
470
+ # - RFC7230: 3.3. 1xx, 204(No Content), 304(Not Modified)
471
+ # - RFC7231: 6.3.6. 205(Reset Content)
472
+ body = None
473
+ if (code >= 200 and
474
+ code not in (HTTPStatus.NO_CONTENT,
475
+ HTTPStatus.RESET_CONTENT,
476
+ HTTPStatus.NOT_MODIFIED)):
477
+ # HTML encode to prevent Cross Site Scripting attacks
478
+ # (see bug #1100201)
479
+ content = (self.error_message_format % {
480
+ 'code': code,
481
+ 'message': html.escape(message, quote=False),
482
+ 'explain': html.escape(explain, quote=False)
483
+ })
484
+ body = content.encode('UTF-8', 'replace')
485
+ self.send_header("Content-Type", self.error_content_type)
486
+ self.send_header('Content-Length', str(len(body)))
487
+ self.end_headers()
488
+
489
+ if self.command != 'HEAD' and body:
490
+ self.wfile.write(body)
491
+
492
+ def send_response(self, code, message=None):
493
+ """Add the response header to the headers buffer and log the
494
+ response code.
495
+
496
+ Also send two standard headers with the server software
497
+ version and the current date.
498
+
499
+ """
500
+ self.log_request(code)
501
+ self.send_response_only(code, message)
502
+ self.send_header('Server', self.version_string())
503
+ self.send_header('Date', self.date_time_string())
504
+
505
+ def send_response_only(self, code, message=None):
506
+ """Send the response header only."""
507
+ if self.request_version != 'HTTP/0.9':
508
+ if message is None:
509
+ if code in self.responses:
510
+ message = self.responses[code][0]
511
+ else:
512
+ message = ''
513
+ if not hasattr(self, '_headers_buffer'):
514
+ self._headers_buffer = []
515
+ self._headers_buffer.append(("%s %d %s\r\n" %
516
+ (self.protocol_version, code, message)).encode(
517
+ 'latin-1', 'strict'))
518
+
519
+ def send_header(self, keyword, value):
520
+ """Send a MIME header to the headers buffer."""
521
+ if self.request_version != 'HTTP/0.9':
522
+ if not hasattr(self, '_headers_buffer'):
523
+ self._headers_buffer = []
524
+ self._headers_buffer.append(
525
+ ("%s: %s\r\n" % (keyword, value)).encode('latin-1', 'strict'))
526
+
527
+ if keyword.lower() == 'connection':
528
+ if value.lower() == 'close':
529
+ self.close_connection = True
530
+ elif value.lower() == 'keep-alive':
531
+ self.close_connection = False
532
+
533
+ def end_headers(self):
534
+ """Send the blank line ending the MIME headers."""
535
+ if self.request_version != 'HTTP/0.9':
536
+ self._headers_buffer.append(b"\r\n")
537
+ self.flush_headers()
538
+
539
+ def flush_headers(self):
540
+ if hasattr(self, '_headers_buffer'):
541
+ self.wfile.write(b"".join(self._headers_buffer))
542
+ self._headers_buffer = []
543
+
544
+ def log_request(self, code='-', size='-'):
545
+ """Log an accepted request.
546
+
547
+ This is called by send_response().
548
+
549
+ """
550
+ if isinstance(code, HTTPStatus):
551
+ code = code.value
552
+ self.log_message('"%s" %s %s',
553
+ self.requestline, str(code), str(size))
554
+
555
+ def log_error(self, format, *args):
556
+ """Log an error.
557
+
558
+ This is called when a request cannot be fulfilled. By
559
+ default it passes the message on to log_message().
560
+
561
+ Arguments are the same as for log_message().
562
+
563
+ XXX This should go to the separate error log.
564
+
565
+ """
566
+
567
+ self.log_message(format, *args)
568
+
569
+ # https://en.wikipedia.org/wiki/List_of_Unicode_characters#Control_codes
570
+ _control_char_table = str.maketrans(
571
+ {c: fr'\x{c:02x}' for c in itertools.chain(range(0x20), range(0x7f,0xa0))})
572
+ _control_char_table[ord('\\')] = r'\\'
573
+
574
+ def log_message(self, format, *args):
575
+ """Log an arbitrary message.
576
+
577
+ This is used by all other logging functions. Override
578
+ it if you have specific logging wishes.
579
+
580
+ The first argument, FORMAT, is a format string for the
581
+ message to be logged. If the format string contains
582
+ any % escapes requiring parameters, they should be
583
+ specified as subsequent arguments (it's just like
584
+ printf!).
585
+
586
+ The client ip and current date/time are prefixed to
587
+ every message.
588
+
589
+ Unicode control characters are replaced with escaped hex
590
+ before writing the output to stderr.
591
+
592
+ """
593
+
594
+ message = format % args
595
+ sys.stderr.write("%s - - [%s] %s\n" %
596
+ (self.address_string(),
597
+ self.log_date_time_string(),
598
+ message.translate(self._control_char_table)))
599
+
600
+ def version_string(self):
601
+ """Return the server software version string."""
602
+ return self.server_version + ' ' + self.sys_version
603
+
604
+ def date_time_string(self, timestamp=None):
605
+ """Return the current date and time formatted for a message header."""
606
+ if timestamp is None:
607
+ timestamp = time.time()
608
+ return email.utils.formatdate(timestamp, usegmt=True)
609
+
610
+ def log_date_time_string(self):
611
+ """Return the current time formatted for logging."""
612
+ now = time.time()
613
+ year, month, day, hh, mm, ss, x, y, z = time.localtime(now)
614
+ s = "%02d/%3s/%04d %02d:%02d:%02d" % (
615
+ day, self.monthname[month], year, hh, mm, ss)
616
+ return s
617
+
618
+ weekdayname = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
619
+
620
+ monthname = [None,
621
+ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
622
+ 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
623
+
624
+ def address_string(self):
625
+ """Return the client address."""
626
+
627
+ return self.client_address[0]
628
+
629
+ # Essentially static class variables
630
+
631
+ # The version of the HTTP protocol we support.
632
+ # Set this to HTTP/1.1 to enable automatic keepalive
633
+ protocol_version = "HTTP/1.0"
634
+
635
+ # MessageClass used to parse headers
636
+ MessageClass = http.client.HTTPMessage
637
+
638
+ # hack to maintain backwards compatibility
639
+ responses = {
640
+ v: (v.phrase, v.description)
641
+ for v in HTTPStatus.__members__.values()
642
+ }
643
+
644
+
645
+ class SimpleHTTPRequestHandler(BaseHTTPRequestHandler):
646
+
647
+ """Simple HTTP request handler with GET and HEAD commands.
648
+
649
+ This serves files from the current directory and any of its
650
+ subdirectories. The MIME type for files is determined by
651
+ calling the .guess_type() method.
652
+
653
+ The GET and HEAD requests are identical except that the HEAD
654
+ request omits the actual contents of the file.
655
+
656
+ """
657
+
658
+ server_version = "SimpleHTTP/" + __version__
659
+
660
+ def __init__(self, *args, directory=None, **kwargs):
661
+ if directory is None:
662
+ directory = os.getcwd()
663
+ self.directory = directory
664
+ super().__init__(*args, **kwargs)
665
+
666
+ def do_GET(self):
667
+ """Serve a GET request."""
668
+ f = self.send_head()
669
+ if f:
670
+ try:
671
+ self.copyfile(f, self.wfile)
672
+ finally:
673
+ f.close()
674
+
675
+ def do_HEAD(self):
676
+ """Serve a HEAD request."""
677
+ f = self.send_head()
678
+ if f:
679
+ f.close()
680
+
681
+ def send_head(self):
682
+ """Common code for GET and HEAD commands.
683
+
684
+ This sends the response code and MIME headers.
685
+
686
+ Return value is either a file object (which has to be copied
687
+ to the outputfile by the caller unless the command was HEAD,
688
+ and must be closed by the caller under all circumstances), or
689
+ None, in which case the caller has nothing further to do.
690
+
691
+ """
692
+ path = self.translate_path(self.path)
693
+ f = None
694
+ if os.path.isdir(path):
695
+ parts = urllib.parse.urlsplit(self.path)
696
+ if not parts.path.endswith('/'):
697
+ # redirect browser - doing basically what apache does
698
+ self.send_response(HTTPStatus.MOVED_PERMANENTLY)
699
+ new_parts = (parts[0], parts[1], parts[2] + '/',
700
+ parts[3], parts[4])
701
+ new_url = urllib.parse.urlunsplit(new_parts)
702
+ self.send_header("Location", new_url)
703
+ self.end_headers()
704
+ return None
705
+ for index in "index.html", "index.htm":
706
+ index = os.path.join(path, index)
707
+ if os.path.exists(index):
708
+ path = index
709
+ break
710
+ else:
711
+ return self.list_directory(path)
712
+ ctype = self.guess_type(path)
713
+ # check for trailing "/" which should return 404. See Issue17324
714
+ # The test for this was added in test_httpserver.py
715
+ # However, some OS platforms accept a trailingSlash as a filename
716
+ # See discussion on python-dev and Issue34711 regarding
717
+ # parseing and rejection of filenames with a trailing slash
718
+ if path.endswith("/"):
719
+ self.send_error(HTTPStatus.NOT_FOUND, "File not found")
720
+ return None
721
+ try:
722
+ f = open(path, 'rb')
723
+ except OSError:
724
+ self.send_error(HTTPStatus.NOT_FOUND, "File not found")
725
+ return None
726
+
727
+ try:
728
+ fs = os.fstat(f.fileno())
729
+ # Use browser cache if possible
730
+ if ("If-Modified-Since" in self.headers
731
+ and "If-None-Match" not in self.headers):
732
+ # compare If-Modified-Since and time of last file modification
733
+ try:
734
+ ims = email.utils.parsedate_to_datetime(
735
+ self.headers["If-Modified-Since"])
736
+ except (TypeError, IndexError, OverflowError, ValueError):
737
+ # ignore ill-formed values
738
+ pass
739
+ else:
740
+ if ims.tzinfo is None:
741
+ # obsolete format with no timezone, cf.
742
+ # https://tools.ietf.org/html/rfc7231#section-7.1.1.1
743
+ ims = ims.replace(tzinfo=datetime.timezone.utc)
744
+ if ims.tzinfo is datetime.timezone.utc:
745
+ # compare to UTC datetime of last modification
746
+ last_modif = datetime.datetime.fromtimestamp(
747
+ fs.st_mtime, datetime.timezone.utc)
748
+ # remove microseconds, like in If-Modified-Since
749
+ last_modif = last_modif.replace(microsecond=0)
750
+
751
+ if last_modif <= ims:
752
+ self.send_response(HTTPStatus.NOT_MODIFIED)
753
+ self.end_headers()
754
+ f.close()
755
+ return None
756
+
757
+ self.send_response(HTTPStatus.OK)
758
+ self.send_header("Content-type", ctype)
759
+ self.send_header("Content-Length", str(fs[6]))
760
+ self.send_header("Last-Modified",
761
+ self.date_time_string(fs.st_mtime))
762
+ self.end_headers()
763
+ return f
764
+ except:
765
+ f.close()
766
+ raise
767
+
768
+ def list_directory(self, path):
769
+ """Helper to produce a directory listing (absent index.html).
770
+
771
+ Return value is either a file object, or None (indicating an
772
+ error). In either case, the headers are sent, making the
773
+ interface the same as for send_head().
774
+
775
+ """
776
+ try:
777
+ list = os.listdir(path)
778
+ except OSError:
779
+ self.send_error(
780
+ HTTPStatus.NOT_FOUND,
781
+ "No permission to list directory")
782
+ return None
783
+ list.sort(key=lambda a: a.lower())
784
+ r = []
785
+ try:
786
+ displaypath = urllib.parse.unquote(self.path,
787
+ errors='surrogatepass')
788
+ except UnicodeDecodeError:
789
+ displaypath = urllib.parse.unquote(self.path)
790
+ displaypath = html.escape(displaypath, quote=False)
791
+ enc = sys.getfilesystemencoding()
792
+ title = 'Directory listing for %s' % displaypath
793
+ r.append('<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" '
794
+ '"http://www.w3.org/TR/html4/strict.dtd">')
795
+ r.append('<html>\n<head>')
796
+ r.append('<meta http-equiv="Content-Type" '
797
+ 'content="text/html; charset=%s">' % enc)
798
+ r.append('<title>%s</title>\n</head>' % title)
799
+ r.append('<body>\n<h1>%s</h1>' % title)
800
+ r.append('<hr>\n<ul>')
801
+ for name in list:
802
+ fullname = os.path.join(path, name)
803
+ displayname = linkname = name
804
+ # Append / for directories or @ for symbolic links
805
+ if os.path.isdir(fullname):
806
+ displayname = name + "/"
807
+ linkname = name + "/"
808
+ if os.path.islink(fullname):
809
+ displayname = name + "@"
810
+ # Note: a link to a directory displays with @ and links with /
811
+ r.append('<li><a href="%s">%s</a></li>'
812
+ % (urllib.parse.quote(linkname,
813
+ errors='surrogatepass'),
814
+ html.escape(displayname, quote=False)))
815
+ r.append('</ul>\n<hr>\n</body>\n</html>\n')
816
+ encoded = '\n'.join(r).encode(enc, 'surrogateescape')
817
+ f = io.BytesIO()
818
+ f.write(encoded)
819
+ f.seek(0)
820
+ self.send_response(HTTPStatus.OK)
821
+ self.send_header("Content-type", "text/html; charset=%s" % enc)
822
+ self.send_header("Content-Length", str(len(encoded)))
823
+ self.end_headers()
824
+ return f
825
+
826
+ def translate_path(self, path):
827
+ """Translate a /-separated PATH to the local filename syntax.
828
+
829
+ Components that mean special things to the local file system
830
+ (e.g. drive or directory names) are ignored. (XXX They should
831
+ probably be diagnosed.)
832
+
833
+ """
834
+ # abandon query parameters
835
+ path = path.split('?',1)[0]
836
+ path = path.split('#',1)[0]
837
+ # Don't forget explicit trailing slash when normalizing. Issue17324
838
+ trailing_slash = path.rstrip().endswith('/')
839
+ try:
840
+ path = urllib.parse.unquote(path, errors='surrogatepass')
841
+ except UnicodeDecodeError:
842
+ path = urllib.parse.unquote(path)
843
+ path = posixpath.normpath(path)
844
+ words = path.split('/')
845
+ words = filter(None, words)
846
+ path = self.directory
847
+ for word in words:
848
+ if os.path.dirname(word) or word in (os.curdir, os.pardir):
849
+ # Ignore components that are not a simple file/directory name
850
+ continue
851
+ path = os.path.join(path, word)
852
+ if trailing_slash:
853
+ path += '/'
854
+ return path
855
+
856
+ def copyfile(self, source, outputfile):
857
+ """Copy all data between two file objects.
858
+
859
+ The SOURCE argument is a file object open for reading
860
+ (or anything with a read() method) and the DESTINATION
861
+ argument is a file object open for writing (or
862
+ anything with a write() method).
863
+
864
+ The only reason for overriding this would be to change
865
+ the block size or perhaps to replace newlines by CRLF
866
+ -- note however that this the default server uses this
867
+ to copy binary data as well.
868
+
869
+ """
870
+ shutil.copyfileobj(source, outputfile)
871
+
872
+ def guess_type(self, path):
873
+ """Guess the type of a file.
874
+
875
+ Argument is a PATH (a filename).
876
+
877
+ Return value is a string of the form type/subtype,
878
+ usable for a MIME Content-type header.
879
+
880
+ The default implementation looks the file's extension
881
+ up in the table self.extensions_map, using application/octet-stream
882
+ as a default; however it would be permissible (if
883
+ slow) to look inside the data to make a better guess.
884
+
885
+ """
886
+
887
+ base, ext = posixpath.splitext(path)
888
+ if ext in self.extensions_map:
889
+ return self.extensions_map[ext]
890
+ ext = ext.lower()
891
+ if ext in self.extensions_map:
892
+ return self.extensions_map[ext]
893
+ else:
894
+ return self.extensions_map['']
895
+
896
+ if not mimetypes.inited:
897
+ mimetypes.init() # try to read system mime.types
898
+ extensions_map = mimetypes.types_map.copy()
899
+ extensions_map.update({
900
+ '': 'application/octet-stream', # Default
901
+ '.py': 'text/plain',
902
+ '.c': 'text/plain',
903
+ '.h': 'text/plain',
904
+ })
905
+
906
+
907
+ # Utilities for CGIHTTPRequestHandler
908
+
909
+ def _url_collapse_path(path):
910
+ """
911
+ Given a URL path, remove extra '/'s and '.' path elements and collapse
912
+ any '..' references and returns a collapsed path.
913
+
914
+ Implements something akin to RFC-2396 5.2 step 6 to parse relative paths.
915
+ The utility of this function is limited to is_cgi method and helps
916
+ preventing some security attacks.
917
+
918
+ Returns: The reconstituted URL, which will always start with a '/'.
919
+
920
+ Raises: IndexError if too many '..' occur within the path.
921
+
922
+ """
923
+ # Query component should not be involved.
924
+ path, _, query = path.partition('?')
925
+ path = urllib.parse.unquote(path)
926
+
927
+ # Similar to os.path.split(os.path.normpath(path)) but specific to URL
928
+ # path semantics rather than local operating system semantics.
929
+ path_parts = path.split('/')
930
+ head_parts = []
931
+ for part in path_parts[:-1]:
932
+ if part == '..':
933
+ head_parts.pop() # IndexError if more '..' than prior parts
934
+ elif part and part != '.':
935
+ head_parts.append( part )
936
+ if path_parts:
937
+ tail_part = path_parts.pop()
938
+ if tail_part:
939
+ if tail_part == '..':
940
+ head_parts.pop()
941
+ tail_part = ''
942
+ elif tail_part == '.':
943
+ tail_part = ''
944
+ else:
945
+ tail_part = ''
946
+
947
+ if query:
948
+ tail_part = '?'.join((tail_part, query))
949
+
950
+ splitpath = ('/' + '/'.join(head_parts), tail_part)
951
+ collapsed_path = "/".join(splitpath)
952
+
953
+ return collapsed_path
954
+
955
+
956
+
957
+ nobody = None
958
+
959
+ def nobody_uid():
960
+ """Internal routine to get nobody's uid"""
961
+ global nobody
962
+ if nobody:
963
+ return nobody
964
+ try:
965
+ import pwd
966
+ except ImportError:
967
+ return -1
968
+ try:
969
+ nobody = pwd.getpwnam('nobody')[2]
970
+ except KeyError:
971
+ nobody = 1 + max(x[2] for x in pwd.getpwall())
972
+ return nobody
973
+
974
+
975
+ def executable(path):
976
+ """Test for executable file."""
977
+ return os.access(path, os.X_OK)
978
+
979
+
980
+ class CGIHTTPRequestHandler(SimpleHTTPRequestHandler):
981
+
982
+ """Complete HTTP server with GET, HEAD and POST commands.
983
+
984
+ GET and HEAD also support running CGI scripts.
985
+
986
+ The POST command is *only* implemented for CGI scripts.
987
+
988
+ """
989
+
990
+ # Determine platform specifics
991
+ have_fork = hasattr(os, 'fork')
992
+
993
+ # Make rfile unbuffered -- we need to read one line and then pass
994
+ # the rest to a subprocess, so we can't use buffered input.
995
+ rbufsize = 0
996
+
997
+ def do_POST(self):
998
+ """Serve a POST request.
999
+
1000
+ This is only implemented for CGI scripts.
1001
+
1002
+ """
1003
+
1004
+ if self.is_cgi():
1005
+ self.run_cgi()
1006
+ else:
1007
+ self.send_error(
1008
+ HTTPStatus.NOT_IMPLEMENTED,
1009
+ "Can only POST to CGI scripts")
1010
+
1011
+ def send_head(self):
1012
+ """Version of send_head that support CGI scripts"""
1013
+ if self.is_cgi():
1014
+ return self.run_cgi()
1015
+ else:
1016
+ return SimpleHTTPRequestHandler.send_head(self)
1017
+
1018
+ def is_cgi(self):
1019
+ """Test whether self.path corresponds to a CGI script.
1020
+
1021
+ Returns True and updates the cgi_info attribute to the tuple
1022
+ (dir, rest) if self.path requires running a CGI script.
1023
+ Returns False otherwise.
1024
+
1025
+ If any exception is raised, the caller should assume that
1026
+ self.path was rejected as invalid and act accordingly.
1027
+
1028
+ The default implementation tests whether the normalized url
1029
+ path begins with one of the strings in self.cgi_directories
1030
+ (and the next character is a '/' or the end of the string).
1031
+
1032
+ """
1033
+ collapsed_path = _url_collapse_path(self.path)
1034
+ dir_sep = collapsed_path.find('/', 1)
1035
+ head, tail = collapsed_path[:dir_sep], collapsed_path[dir_sep+1:]
1036
+ if head in self.cgi_directories:
1037
+ self.cgi_info = head, tail
1038
+ return True
1039
+ return False
1040
+
1041
+
1042
+ cgi_directories = ['/cgi-bin', '/htbin']
1043
+
1044
+ def is_executable(self, path):
1045
+ """Test whether argument path is an executable file."""
1046
+ return executable(path)
1047
+
1048
+ def is_python(self, path):
1049
+ """Test whether argument path is a Python script."""
1050
+ head, tail = os.path.splitext(path)
1051
+ return tail.lower() in (".py", ".pyw")
1052
+
1053
+ def run_cgi(self):
1054
+ """Execute a CGI script."""
1055
+ dir, rest = self.cgi_info
1056
+ path = dir + '/' + rest
1057
+ i = path.find('/', len(dir)+1)
1058
+ while i >= 0:
1059
+ nextdir = path[:i]
1060
+ nextrest = path[i+1:]
1061
+
1062
+ scriptdir = self.translate_path(nextdir)
1063
+ if os.path.isdir(scriptdir):
1064
+ dir, rest = nextdir, nextrest
1065
+ i = path.find('/', len(dir)+1)
1066
+ else:
1067
+ break
1068
+
1069
+ # find an explicit query string, if present.
1070
+ rest, _, query = rest.partition('?')
1071
+
1072
+ # dissect the part after the directory name into a script name &
1073
+ # a possible additional path, to be stored in PATH_INFO.
1074
+ i = rest.find('/')
1075
+ if i >= 0:
1076
+ script, rest = rest[:i], rest[i:]
1077
+ else:
1078
+ script, rest = rest, ''
1079
+
1080
+ scriptname = dir + '/' + script
1081
+ scriptfile = self.translate_path(scriptname)
1082
+ if not os.path.exists(scriptfile):
1083
+ self.send_error(
1084
+ HTTPStatus.NOT_FOUND,
1085
+ "No such CGI script (%r)" % scriptname)
1086
+ return
1087
+ if not os.path.isfile(scriptfile):
1088
+ self.send_error(
1089
+ HTTPStatus.FORBIDDEN,
1090
+ "CGI script is not a plain file (%r)" % scriptname)
1091
+ return
1092
+ ispy = self.is_python(scriptname)
1093
+ if self.have_fork or not ispy:
1094
+ if not self.is_executable(scriptfile):
1095
+ self.send_error(
1096
+ HTTPStatus.FORBIDDEN,
1097
+ "CGI script is not executable (%r)" % scriptname)
1098
+ return
1099
+
1100
+ # Reference: http://hoohoo.ncsa.uiuc.edu/cgi/env.html
1101
+ # XXX Much of the following could be prepared ahead of time!
1102
+ env = copy.deepcopy(os.environ)
1103
+ env['SERVER_SOFTWARE'] = self.version_string()
1104
+ env['SERVER_NAME'] = self.server.server_name
1105
+ env['GATEWAY_INTERFACE'] = 'CGI/1.1'
1106
+ env['SERVER_PROTOCOL'] = self.protocol_version
1107
+ env['SERVER_PORT'] = str(self.server.server_port)
1108
+ env['REQUEST_METHOD'] = self.command
1109
+ uqrest = urllib.parse.unquote(rest)
1110
+ env['PATH_INFO'] = uqrest
1111
+ env['PATH_TRANSLATED'] = self.translate_path(uqrest)
1112
+ env['SCRIPT_NAME'] = scriptname
1113
+ if query:
1114
+ env['QUERY_STRING'] = query
1115
+ env['REMOTE_ADDR'] = self.client_address[0]
1116
+ authorization = self.headers.get("authorization")
1117
+ if authorization:
1118
+ authorization = authorization.split()
1119
+ if len(authorization) == 2:
1120
+ import base64, binascii
1121
+ env['AUTH_TYPE'] = authorization[0]
1122
+ if authorization[0].lower() == "basic":
1123
+ try:
1124
+ authorization = authorization[1].encode('ascii')
1125
+ authorization = base64.decodebytes(authorization).\
1126
+ decode('ascii')
1127
+ except (binascii.Error, UnicodeError):
1128
+ pass
1129
+ else:
1130
+ authorization = authorization.split(':')
1131
+ if len(authorization) == 2:
1132
+ env['REMOTE_USER'] = authorization[0]
1133
+ # XXX REMOTE_IDENT
1134
+ if self.headers.get('content-type') is None:
1135
+ env['CONTENT_TYPE'] = self.headers.get_content_type()
1136
+ else:
1137
+ env['CONTENT_TYPE'] = self.headers['content-type']
1138
+ length = self.headers.get('content-length')
1139
+ if length:
1140
+ env['CONTENT_LENGTH'] = length
1141
+ referer = self.headers.get('referer')
1142
+ if referer:
1143
+ env['HTTP_REFERER'] = referer
1144
+ accept = []
1145
+ for line in self.headers.getallmatchingheaders('accept'):
1146
+ if line[:1] in "\t\n\r ":
1147
+ accept.append(line.strip())
1148
+ else:
1149
+ accept = accept + line[7:].split(',')
1150
+ env['HTTP_ACCEPT'] = ','.join(accept)
1151
+ ua = self.headers.get('user-agent')
1152
+ if ua:
1153
+ env['HTTP_USER_AGENT'] = ua
1154
+ co = filter(None, self.headers.get_all('cookie', []))
1155
+ cookie_str = ', '.join(co)
1156
+ if cookie_str:
1157
+ env['HTTP_COOKIE'] = cookie_str
1158
+ # XXX Other HTTP_* headers
1159
+ # Since we're setting the env in the parent, provide empty
1160
+ # values to override previously set values
1161
+ for k in ('QUERY_STRING', 'REMOTE_HOST', 'CONTENT_LENGTH',
1162
+ 'HTTP_USER_AGENT', 'HTTP_COOKIE', 'HTTP_REFERER'):
1163
+ env.setdefault(k, "")
1164
+
1165
+ self.send_response(HTTPStatus.OK, "Script output follows")
1166
+ self.flush_headers()
1167
+
1168
+ decoded_query = query.replace('+', ' ')
1169
+
1170
+ if self.have_fork:
1171
+ # Unix -- fork as we should
1172
+ args = [script]
1173
+ if '=' not in decoded_query:
1174
+ args.append(decoded_query)
1175
+ nobody = nobody_uid()
1176
+ self.wfile.flush() # Always flush before forking
1177
+ pid = os.fork()
1178
+ if pid != 0:
1179
+ # Parent
1180
+ pid, sts = os.waitpid(pid, 0)
1181
+ # throw away additional data [see bug #427345]
1182
+ while select.select([self.rfile], [], [], 0)[0]:
1183
+ if not self.rfile.read(1):
1184
+ break
1185
+ if sts:
1186
+ self.log_error("CGI script exit status %#x", sts)
1187
+ return
1188
+ # Child
1189
+ try:
1190
+ try:
1191
+ os.setuid(nobody)
1192
+ except OSError:
1193
+ pass
1194
+ os.dup2(self.rfile.fileno(), 0)
1195
+ os.dup2(self.wfile.fileno(), 1)
1196
+ os.execve(scriptfile, args, env)
1197
+ except:
1198
+ self.server.handle_error(self.request, self.client_address)
1199
+ os._exit(127)
1200
+
1201
+ else:
1202
+ # Non-Unix -- use subprocess
1203
+ import subprocess
1204
+ cmdline = [scriptfile]
1205
+ if self.is_python(scriptfile):
1206
+ interp = sys.executable
1207
+ if interp.lower().endswith("w.exe"):
1208
+ # On Windows, use python.exe, not pythonw.exe
1209
+ interp = interp[:-5] + interp[-4:]
1210
+ cmdline = [interp, '-u'] + cmdline
1211
+ if '=' not in query:
1212
+ cmdline.append(query)
1213
+ self.log_message("command: %s", subprocess.list2cmdline(cmdline))
1214
+ try:
1215
+ nbytes = int(length)
1216
+ except (TypeError, ValueError):
1217
+ nbytes = 0
1218
+ p = subprocess.Popen(cmdline,
1219
+ stdin=subprocess.PIPE,
1220
+ stdout=subprocess.PIPE,
1221
+ stderr=subprocess.PIPE,
1222
+ env = env
1223
+ )
1224
+ if self.command.lower() == "post" and nbytes > 0:
1225
+ data = self.rfile.read(nbytes)
1226
+ else:
1227
+ data = None
1228
+ # throw away additional data [see bug #427345]
1229
+ while select.select([self.rfile._sock], [], [], 0)[0]:
1230
+ if not self.rfile._sock.recv(1):
1231
+ break
1232
+ stdout, stderr = p.communicate(data)
1233
+ self.wfile.write(stdout)
1234
+ if stderr:
1235
+ self.log_error('%s', stderr)
1236
+ p.stderr.close()
1237
+ p.stdout.close()
1238
+ status = p.returncode
1239
+ if status:
1240
+ self.log_error("CGI script exit status %#x", status)
1241
+ else:
1242
+ self.log_message("CGI script exited OK")
1243
+
1244
+
1245
+ def _get_best_family(*address):
1246
+ infos = socket.getaddrinfo(
1247
+ *address,
1248
+ type=socket.SOCK_STREAM,
1249
+ flags=socket.AI_PASSIVE,
1250
+ )
1251
+ family, type, proto, canonname, sockaddr = next(iter(infos))
1252
+ return family, sockaddr
1253
+
1254
+
1255
+ def test(HandlerClass=BaseHTTPRequestHandler,
1256
+ ServerClass=ThreadingHTTPServer,
1257
+ protocol="HTTP/1.0", port=8000, bind=None):
1258
+ """Test the HTTP request handler class.
1259
+
1260
+ This runs an HTTP server on port 8000 (or the port argument).
1261
+
1262
+ """
1263
+ ServerClass.address_family, addr = _get_best_family(bind, port)
1264
+
1265
+ HandlerClass.protocol_version = protocol
1266
+ with ServerClass(addr, HandlerClass) as httpd:
1267
+ host, port = httpd.socket.getsockname()[:2]
1268
+ url_host = f'[{host}]' if ':' in host else host
1269
+ print(
1270
+ f"Serving HTTP on {host} port {port} "
1271
+ f"(http://{url_host}:{port}/) ..."
1272
+ )
1273
+ try:
1274
+ httpd.serve_forever()
1275
+ except KeyboardInterrupt:
1276
+ print("\nKeyboard interrupt received, exiting.")
1277
+ sys.exit(0)
1278
+
1279
+ if __name__ == '__main__':
1280
+ import argparse
1281
+
1282
+ parser = argparse.ArgumentParser()
1283
+ parser.add_argument('--cgi', action='store_true',
1284
+ help='Run as CGI Server')
1285
+ parser.add_argument('--bind', '-b', metavar='ADDRESS',
1286
+ help='Specify alternate bind address '
1287
+ '[default: all interfaces]')
1288
+ parser.add_argument('--directory', '-d', default=os.getcwd(),
1289
+ help='Specify alternative directory '
1290
+ '[default:current directory]')
1291
+ parser.add_argument('port', action='store',
1292
+ default=8000, type=int,
1293
+ nargs='?',
1294
+ help='Specify alternate port [default: 8000]')
1295
+ args = parser.parse_args()
1296
+ if args.cgi:
1297
+ handler_class = CGIHTTPRequestHandler
1298
+ else:
1299
+ handler_class = partial(SimpleHTTPRequestHandler,
1300
+ directory=args.directory)
1301
+
1302
+ # ensure dual-stack is not disabled; ref #38907
1303
+ class DualStackServer(ThreadingHTTPServer):
1304
+ def server_bind(self):
1305
+ # suppress exception when protocol is IPv4
1306
+ with contextlib.suppress(Exception):
1307
+ self.socket.setsockopt(
1308
+ socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 0)
1309
+ return super().server_bind()
1310
+
1311
+ test(
1312
+ HandlerClass=handler_class,
1313
+ ServerClass=DualStackServer,
1314
+ port=args.port,
1315
+ bind=args.bind,
1316
+ )
my_container_sandbox/workspace/anaconda3/lib/tcl8/8.4/platform-1.0.18.tm ADDED
@@ -0,0 +1,439 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # -*- tcl -*-
2
+ # ### ### ### ######### ######### #########
3
+ ## Overview
4
+
5
+ # Heuristics to assemble a platform identifier from publicly available
6
+ # information. The identifier describes the platform of the currently
7
+ # running tcl shell. This is a mixture of the runtime environment and
8
+ # of build-time properties of the executable itself.
9
+ #
10
+ # Examples:
11
+ # <1> A tcl shell executing on a x86_64 processor, but having a
12
+ # wordsize of 4 was compiled for the x86 environment, i.e. 32
13
+ # bit, and loaded packages have to match that, and not the
14
+ # actual cpu.
15
+ #
16
+ # <2> The hp/solaris 32/64 bit builds of the core cannot be
17
+ # distinguished by looking at tcl_platform. As packages have to
18
+ # match the 32/64 information we have to look in more places. In
19
+ # this case we inspect the executable itself (magic numbers,
20
+ # i.e. fileutil::magic::filetype).
21
+ #
22
+ # The basic information used comes out of the 'os' and 'machine'
23
+ # entries of the 'tcl_platform' array. A number of general and
24
+ # os/machine specific transformation are applied to get a canonical
25
+ # result.
26
+ #
27
+ # General
28
+ # Only the first element of 'os' is used - we don't care whether we
29
+ # are on "Windows NT" or "Windows XP" or whatever.
30
+ #
31
+ # Machine specific
32
+ # % amd64 -> x86_64
33
+ # % arm* -> arm
34
+ # % sun4* -> sparc
35
+ # % ia32* -> ix86
36
+ # % intel -> ix86
37
+ # % i*86* -> ix86
38
+ # % Power* -> powerpc
39
+ # % x86_64 + wordSize 4 => x86 code
40
+ #
41
+ # OS specific
42
+ # % AIX are always powerpc machines
43
+ # % HP-UX 9000/800 etc means parisc
44
+ # % linux has to take glibc version into account
45
+ # % sunos -> solaris, and keep version number
46
+ #
47
+ # NOTE: A platform like linux glibc 2.3, which can use glibc 2.2 stuff
48
+ # has to provide all possible allowed platform identifiers when
49
+ # searching search. Ditto a solaris 2.8 platform can use solaris 2.6
50
+ # packages. Etc. This is handled by the other procedure, see below.
51
+
52
+ # ### ### ### ######### ######### #########
53
+ ## Requirements
54
+
55
+ namespace eval ::platform {}
56
+
57
+ # ### ### ### ######### ######### #########
58
+ ## Implementation
59
+
60
+ # -- platform::generic
61
+ #
62
+ # Assembles an identifier for the generic platform. It leaves out
63
+ # details like kernel version, libc version, etc.
64
+
65
+ proc ::platform::generic {} {
66
+ global tcl_platform
67
+
68
+ set plat [string tolower [lindex $tcl_platform(os) 0]]
69
+ set cpu $tcl_platform(machine)
70
+
71
+ switch -glob -- $cpu {
72
+ sun4* {
73
+ set cpu sparc
74
+ }
75
+ intel -
76
+ ia32* -
77
+ i*86* {
78
+ set cpu ix86
79
+ }
80
+ x86_64 {
81
+ if {$tcl_platform(wordSize) == 4} {
82
+ # See Example <1> at the top of this file.
83
+ set cpu ix86
84
+ }
85
+ }
86
+ ppc -
87
+ "Power*" {
88
+ set cpu powerpc
89
+ }
90
+ "arm*" {
91
+ set cpu arm
92
+ }
93
+ ia64 {
94
+ if {$tcl_platform(wordSize) == 4} {
95
+ append cpu _32
96
+ }
97
+ }
98
+ }
99
+
100
+ switch -glob -- $plat {
101
+ windows {
102
+ if {$tcl_platform(platform) == "unix"} {
103
+ set plat cygwin
104
+ } else {
105
+ set plat win32
106
+ }
107
+ if {$cpu eq "amd64"} {
108
+ # Do not check wordSize, win32-x64 is an IL32P64 platform.
109
+ set cpu x86_64
110
+ }
111
+ }
112
+ sunos {
113
+ set plat solaris
114
+ if {[string match "ix86" $cpu]} {
115
+ if {$tcl_platform(wordSize) == 8} {
116
+ set cpu x86_64
117
+ }
118
+ } elseif {![string match "ia64*" $cpu]} {
119
+ # sparc
120
+ if {$tcl_platform(wordSize) == 8} {
121
+ append cpu 64
122
+ }
123
+ }
124
+ }
125
+ darwin {
126
+ set plat macosx
127
+ # Correctly identify the cpu when running as a 64bit
128
+ # process on a machine with a 32bit kernel
129
+ if {$cpu eq "ix86"} {
130
+ if {$tcl_platform(wordSize) == 8} {
131
+ set cpu x86_64
132
+ }
133
+ }
134
+ }
135
+ aix {
136
+ set cpu powerpc
137
+ if {$tcl_platform(wordSize) == 8} {
138
+ append cpu 64
139
+ }
140
+ }
141
+ hp-ux {
142
+ set plat hpux
143
+ if {![string match "ia64*" $cpu]} {
144
+ set cpu parisc
145
+ if {$tcl_platform(wordSize) == 8} {
146
+ append cpu 64
147
+ }
148
+ }
149
+ }
150
+ osf1 {
151
+ set plat tru64
152
+ }
153
+ default {
154
+ set plat [lindex [split $plat _-] 0]
155
+ }
156
+ }
157
+
158
+ return "${plat}-${cpu}"
159
+ }
160
+
161
+ # -- platform::identify
162
+ #
163
+ # Assembles an identifier for the exact platform, by extending the
164
+ # generic identifier. I.e. it adds in details like kernel version,
165
+ # libc version, etc., if they are relevant for the loading of
166
+ # packages on the platform.
167
+
168
+ proc ::platform::identify {} {
169
+ global tcl_platform
170
+
171
+ set id [generic]
172
+ regexp {^([^-]+)-([^-]+)$} $id -> plat cpu
173
+
174
+ switch -- $plat {
175
+ solaris {
176
+ regsub {^5} $tcl_platform(osVersion) 2 text
177
+ append plat $text
178
+ return "${plat}-${cpu}"
179
+ }
180
+ macosx {
181
+ set major [lindex [split $tcl_platform(osVersion) .] 0]
182
+ if {$major > 19} {
183
+ set minor [lindex [split $tcl_platform(osVersion) .] 1]
184
+ incr major -9
185
+ append plat $major.[expr {$minor - 1}]
186
+ } else {
187
+ incr major -4
188
+ append plat 10.$major
189
+ return "${plat}-${cpu}"
190
+ }
191
+ return "${plat}-${cpu}"
192
+ }
193
+ linux {
194
+ # Look for the libc*.so and determine its version
195
+ # (libc5/6, libc6 further glibc 2.X)
196
+
197
+ set v unknown
198
+
199
+ # Determine in which directory to look. /lib, or /lib64.
200
+ # For that we use the tcl_platform(wordSize).
201
+ #
202
+ # We could use the 'cpu' info, per the equivalence below,
203
+ # that however would be restricted to intel. And this may
204
+ # be a arm, mips, etc. system. The wordsize is more
205
+ # fundamental.
206
+ #
207
+ # ix86 <=> (wordSize == 4) <=> 32 bit ==> /lib
208
+ # x86_64 <=> (wordSize == 8) <=> 64 bit ==> /lib64
209
+ #
210
+ # Do not look into /lib64 even if present, if the cpu
211
+ # doesn't fit.
212
+
213
+ # TODO: Determine the prefixes (i386, x86_64, ...) for
214
+ # other cpus. The path after the generic one is utterly
215
+ # specific to intel right now. Ok, on Ubuntu, possibly
216
+ # other Debian systems we may apparently be able to query
217
+ # the necessary CPU code. If we can't we simply use the
218
+ # hardwired fallback.
219
+
220
+ switch -exact -- $tcl_platform(wordSize) {
221
+ 4 {
222
+ lappend bases /lib
223
+ if {[catch {
224
+ exec dpkg-architecture -qDEB_HOST_MULTIARCH
225
+ } res]} {
226
+ lappend bases /lib/i386-linux-gnu
227
+ } else {
228
+ # dpkg-arch returns the full tripled, not just cpu.
229
+ lappend bases /lib/$res
230
+ }
231
+ }
232
+ 8 {
233
+ lappend bases /lib64
234
+ if {[catch {
235
+ exec dpkg-architecture -qDEB_HOST_MULTIARCH
236
+ } res]} {
237
+ lappend bases /lib/x86_64-linux-gnu
238
+ } else {
239
+ # dpkg-arch returns the full tripled, not just cpu.
240
+ lappend bases /lib/$res
241
+ }
242
+ }
243
+ default {
244
+ return -code error "Bad wordSize $tcl_platform(wordSize), expected 4 or 8"
245
+ }
246
+ }
247
+
248
+ foreach base $bases {
249
+ if {[LibcVersion $base -> v]} break
250
+ }
251
+
252
+ append plat -$v
253
+ return "${plat}-${cpu}"
254
+ }
255
+ }
256
+
257
+ return $id
258
+ }
259
+
260
+ proc ::platform::LibcVersion {base _->_ vv} {
261
+ upvar 1 $vv v
262
+ set libclist [lsort [glob -nocomplain -directory $base libc*]]
263
+
264
+ if {![llength $libclist]} { return 0 }
265
+
266
+ set libc [lindex $libclist 0]
267
+
268
+ # Try executing the library first. This should suceed
269
+ # for a glibc library, and return the version
270
+ # information.
271
+
272
+ if {![catch {
273
+ set vdata [lindex [split [exec $libc] \n] 0]
274
+ }]} {
275
+ regexp {version ([0-9]+(\.[0-9]+)*)} $vdata -> v
276
+ foreach {major minor} [split $v .] break
277
+ set v glibc${major}.${minor}
278
+ return 1
279
+ } else {
280
+ # We had trouble executing the library. We are now
281
+ # inspecting its name to determine the version
282
+ # number. This code by Larry McVoy.
283
+
284
+ if {[regexp -- {libc-([0-9]+)\.([0-9]+)} $libc -> major minor]} {
285
+ set v glibc${major}.${minor}
286
+ return 1
287
+ }
288
+ }
289
+ return 0
290
+ }
291
+
292
+ # -- platform::patterns
293
+ #
294
+ # Given an exact platform identifier, i.e. _not_ the generic
295
+ # identifier it assembles a list of exact platform identifier
296
+ # describing platform which should be compatible with the
297
+ # input.
298
+ #
299
+ # I.e. packages for all platforms in the result list should be
300
+ # loadable on the specified platform.
301
+
302
+ # << Should we add the generic identifier to the list as well ? In
303
+ # general it is not compatible I believe. So better not. In many
304
+ # cases the exact identifier is identical to the generic one
305
+ # anyway.
306
+ # >>
307
+
308
+ proc ::platform::patterns {id} {
309
+ set res [list $id]
310
+ if {$id eq "tcl"} {return $res}
311
+
312
+ switch -glob -- $id {
313
+ solaris*-* {
314
+ if {[regexp {solaris([^-]*)-(.*)} $id -> v cpu]} {
315
+ if {$v eq ""} {return $id}
316
+ foreach {major minor} [split $v .] break
317
+ incr minor -1
318
+ for {set j $minor} {$j >= 6} {incr j -1} {
319
+ lappend res solaris${major}.${j}-${cpu}
320
+ }
321
+ }
322
+ }
323
+ linux*-* {
324
+ if {[regexp {linux-glibc([^-]*)-(.*)} $id -> v cpu]} {
325
+ foreach {major minor} [split $v .] break
326
+ incr minor -1
327
+ for {set j $minor} {$j >= 0} {incr j -1} {
328
+ lappend res linux-glibc${major}.${j}-${cpu}
329
+ }
330
+ }
331
+ }
332
+ macosx-powerpc {
333
+ lappend res macosx-universal
334
+ }
335
+ macosx-x86_64 {
336
+ lappend res macosx-i386-x86_64
337
+ }
338
+ macosx-ix86 {
339
+ lappend res macosx-universal macosx-i386-x86_64
340
+ }
341
+ macosx*-* {
342
+ # 10.5+,11.0+
343
+ if {[regexp {macosx([^-]*)-(.*)} $id -> v cpu]} {
344
+
345
+ switch -exact -- $cpu {
346
+ ix86 {
347
+ lappend alt i386-x86_64
348
+ lappend alt universal
349
+ }
350
+ x86_64 {
351
+ if {[lindex [split $::tcl_platform(osVersion) .] 0] < 19} {
352
+ set alt i386-x86_64
353
+ } else {
354
+ set alt {}
355
+ }
356
+ }
357
+ arm {
358
+ lappend alt x86_64
359
+ }
360
+ default { set alt {} }
361
+ }
362
+
363
+ if {$v ne ""} {
364
+ foreach {major minor} [split $v .] break
365
+
366
+ set res {}
367
+ if {$major eq 12} {
368
+ # Add 12.0 to 12.minor to patterns.
369
+ for {set j $minor} {$j >= 0} {incr j -1} {
370
+ lappend res macosx${major}.${j}-${cpu}
371
+ foreach a $alt {
372
+ lappend res macosx${major}.${j}-$a
373
+ }
374
+ }
375
+ set major 11
376
+ set minor 5
377
+ }
378
+ if {$major eq 11} {
379
+ # Add 11.0 to 11.minor to patterns.
380
+ for {set j $minor} {$j >= 0} {incr j -1} {
381
+ lappend res macosx${major}.${j}-${cpu}
382
+ foreach a $alt {
383
+ lappend res macosx${major}.${j}-$a
384
+ }
385
+ }
386
+ set major 10
387
+ set minor 15
388
+ }
389
+ # Add 10.5 to 10.minor to patterns.
390
+ for {set j $minor} {$j >= 5} {incr j -1} {
391
+ if {$cpu ne "arm"} {
392
+ lappend res macosx${major}.${j}-${cpu}
393
+ }
394
+ foreach a $alt {
395
+ lappend res macosx${major}.${j}-$a
396
+ }
397
+ }
398
+
399
+ # Add unversioned patterns for 10.3/10.4 builds.
400
+ lappend res macosx-${cpu}
401
+ foreach a $alt {
402
+ lappend res macosx-$a
403
+ }
404
+ } else {
405
+ # No version, just do unversioned patterns.
406
+ foreach a $alt {
407
+ lappend res macosx-$a
408
+ }
409
+ }
410
+ } else {
411
+ # no v, no cpu ... nothing
412
+ }
413
+ }
414
+ }
415
+ lappend res tcl ; # Pure tcl packages are always compatible.
416
+ return $res
417
+ }
418
+
419
+
420
+ # ### ### ### ######### ######### #########
421
+ ## Ready
422
+
423
+ package provide platform 1.0.18
424
+
425
+ # ### ### ### ######### ######### #########
426
+ ## Demo application
427
+
428
+ if {[info exists argv0] && ($argv0 eq [info script])} {
429
+ puts ====================================
430
+ parray tcl_platform
431
+ puts ====================================
432
+ puts Generic\ identification:\ [::platform::generic]
433
+ puts Exact\ identification:\ \ \ [::platform::identify]
434
+ puts ====================================
435
+ puts Search\ patterns:
436
+ puts *\ [join [::platform::patterns [::platform::identify]] \n*\ ]
437
+ puts ====================================
438
+ exit 0
439
+ }
my_container_sandbox/workspace/anaconda3/lib/tcl8/8.4/platform/shell-1.1.4.tm ADDED
@@ -0,0 +1,241 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ # -*- tcl -*-
3
+ # ### ### ### ######### ######### #########
4
+ ## Overview
5
+
6
+ # Higher-level commands which invoke the functionality of this package
7
+ # for an arbitrary tcl shell (tclsh, wish, ...). This is required by a
8
+ # repository as while the tcl shell executing packages uses the same
9
+ # platform in general as a repository application there can be
10
+ # differences in detail (i.e. 32/64 bit builds).
11
+
12
+ # ### ### ### ######### ######### #########
13
+ ## Requirements
14
+
15
+ package require platform
16
+ namespace eval ::platform::shell {}
17
+
18
+ # ### ### ### ######### ######### #########
19
+ ## Implementation
20
+
21
+ # -- platform::shell::generic
22
+
23
+ proc ::platform::shell::generic {shell} {
24
+ # Argument is the path to a tcl shell.
25
+
26
+ CHECK $shell
27
+ LOCATE base out
28
+
29
+ set code {}
30
+ # Forget any pre-existing platform package, it might be in
31
+ # conflict with this one.
32
+ lappend code {package forget platform}
33
+ # Inject our platform package
34
+ lappend code [list source $base]
35
+ # Query and print the architecture
36
+ lappend code {puts [platform::generic]}
37
+ # And done
38
+ lappend code {exit 0}
39
+
40
+ set arch [RUN $shell [join $code \n]]
41
+
42
+ if {$out} {file delete -force $base}
43
+ return $arch
44
+ }
45
+
46
+ # -- platform::shell::identify
47
+
48
+ proc ::platform::shell::identify {shell} {
49
+ # Argument is the path to a tcl shell.
50
+
51
+ CHECK $shell
52
+ LOCATE base out
53
+
54
+ set code {}
55
+ # Forget any pre-existing platform package, it might be in
56
+ # conflict with this one.
57
+ lappend code {package forget platform}
58
+ # Inject our platform package
59
+ lappend code [list source $base]
60
+ # Query and print the architecture
61
+ lappend code {puts [platform::identify]}
62
+ # And done
63
+ lappend code {exit 0}
64
+
65
+ set arch [RUN $shell [join $code \n]]
66
+
67
+ if {$out} {file delete -force $base}
68
+ return $arch
69
+ }
70
+
71
+ # -- platform::shell::platform
72
+
73
+ proc ::platform::shell::platform {shell} {
74
+ # Argument is the path to a tcl shell.
75
+
76
+ CHECK $shell
77
+
78
+ set code {}
79
+ lappend code {puts $tcl_platform(platform)}
80
+ lappend code {exit 0}
81
+
82
+ return [RUN $shell [join $code \n]]
83
+ }
84
+
85
+ # ### ### ### ######### ######### #########
86
+ ## Internal helper commands.
87
+
88
+ proc ::platform::shell::CHECK {shell} {
89
+ if {![file exists $shell]} {
90
+ return -code error "Shell \"$shell\" does not exist"
91
+ }
92
+ if {![file executable $shell]} {
93
+ return -code error "Shell \"$shell\" is not executable (permissions)"
94
+ }
95
+ return
96
+ }
97
+
98
+ proc ::platform::shell::LOCATE {bv ov} {
99
+ upvar 1 $bv base $ov out
100
+
101
+ # Locate the platform package for injection into the specified
102
+ # shell. We are using package management to find it, whereever it
103
+ # is, instead of using hardwired relative paths. This allows us to
104
+ # install the two packages as TMs without breaking the code
105
+ # here. If the found package is wrapped we copy the code somewhere
106
+ # where the spawned shell will be able to read it.
107
+
108
+ # This code is brittle, it needs has to adapt to whatever changes
109
+ # are made to the TM code, i.e. the provide statement generated by
110
+ # tm.tcl
111
+
112
+ set pl [package ifneeded platform [package require platform]]
113
+ set base [lindex $pl end]
114
+
115
+ set out 0
116
+ if {[lindex [file system $base]] ne "native"} {
117
+ set temp [TEMP]
118
+ file copy -force $base $temp
119
+ set base $temp
120
+ set out 1
121
+ }
122
+ return
123
+ }
124
+
125
+ proc ::platform::shell::RUN {shell code} {
126
+ set c [TEMP]
127
+ set cc [open $c w]
128
+ puts $cc $code
129
+ close $cc
130
+
131
+ set e [TEMP]
132
+
133
+ set code [catch {
134
+ exec $shell $c 2> $e
135
+ } res]
136
+
137
+ file delete $c
138
+
139
+ if {$code} {
140
+ append res \n[read [set chan [open $e r]]][close $chan]
141
+ file delete $e
142
+ return -code error "Shell \"$shell\" is not executable ($res)"
143
+ }
144
+
145
+ file delete $e
146
+ return $res
147
+ }
148
+
149
+ proc ::platform::shell::TEMP {} {
150
+ set prefix platform
151
+
152
+ # This code is copied out of Tcllib's fileutil package.
153
+ # (TempFile/tempfile)
154
+
155
+ set tmpdir [DIR]
156
+
157
+ set chars "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
158
+ set nrand_chars 10
159
+ set maxtries 10
160
+ set access [list RDWR CREAT EXCL TRUNC]
161
+ set permission 0600
162
+ set channel ""
163
+ set checked_dir_writable 0
164
+ set mypid [pid]
165
+ for {set i 0} {$i < $maxtries} {incr i} {
166
+ set newname $prefix
167
+ for {set j 0} {$j < $nrand_chars} {incr j} {
168
+ append newname [string index $chars \
169
+ [expr {int(rand()*62)}]]
170
+ }
171
+ set newname [file join $tmpdir $newname]
172
+ if {[file exists $newname]} {
173
+ after 1
174
+ } else {
175
+ if {[catch {open $newname $access $permission} channel]} {
176
+ if {!$checked_dir_writable} {
177
+ set dirname [file dirname $newname]
178
+ if {![file writable $dirname]} {
179
+ return -code error "Directory $dirname is not writable"
180
+ }
181
+ set checked_dir_writable 1
182
+ }
183
+ } else {
184
+ # Success
185
+ close $channel
186
+ return [file normalize $newname]
187
+ }
188
+ }
189
+ }
190
+ if {$channel ne ""} {
191
+ return -code error "Failed to open a temporary file: $channel"
192
+ } else {
193
+ return -code error "Failed to find an unused temporary file name"
194
+ }
195
+ }
196
+
197
+ proc ::platform::shell::DIR {} {
198
+ # This code is copied out of Tcllib's fileutil package.
199
+ # (TempDir/tempdir)
200
+
201
+ global tcl_platform env
202
+
203
+ set attempdirs [list]
204
+
205
+ foreach tmp {TMPDIR TEMP TMP} {
206
+ if { [info exists env($tmp)] } {
207
+ lappend attempdirs $env($tmp)
208
+ }
209
+ }
210
+
211
+ switch $tcl_platform(platform) {
212
+ windows {
213
+ lappend attempdirs "C:\\TEMP" "C:\\TMP" "\\TEMP" "\\TMP"
214
+ }
215
+ macintosh {
216
+ set tmpdir $env(TRASH_FOLDER) ;# a better place?
217
+ }
218
+ default {
219
+ lappend attempdirs \
220
+ [file join / tmp] \
221
+ [file join / var tmp] \
222
+ [file join / usr tmp]
223
+ }
224
+ }
225
+
226
+ lappend attempdirs [pwd]
227
+
228
+ foreach tmp $attempdirs {
229
+ if { [file isdirectory $tmp] && [file writable $tmp] } {
230
+ return [file normalize $tmp]
231
+ }
232
+ }
233
+
234
+ # Fail if nothing worked.
235
+ return -code error "Unable to determine a proper directory for temporary files"
236
+ }
237
+
238
+ # ### ### ### ######### ######### #########
239
+ ## Ready
240
+
241
+ package provide platform::shell 1.1.4
my_container_sandbox/workspace/anaconda3/lib/tcl8/8.5/msgcat-1.6.1.tm ADDED
@@ -0,0 +1,1210 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # msgcat.tcl --
2
+ #
3
+ # This file defines various procedures which implement a
4
+ # message catalog facility for Tcl programs. It should be
5
+ # loaded with the command "package require msgcat".
6
+ #
7
+ # Copyright (c) 2010-2015 Harald Oehlmann.
8
+ # Copyright (c) 1998-2000 Ajuba Solutions.
9
+ # Copyright (c) 1998 Mark Harrison.
10
+ #
11
+ # See the file "license.terms" for information on usage and redistribution
12
+ # of this file, and for a DISCLAIMER OF ALL WARRANTIES.
13
+
14
+ package require Tcl 8.5-
15
+ # When the version number changes, be sure to update the pkgIndex.tcl file,
16
+ # and the installation directory in the Makefiles.
17
+ package provide msgcat 1.6.1
18
+
19
+ namespace eval msgcat {
20
+ namespace export mc mcexists mcload mclocale mcmax mcmset mcpreferences mcset\
21
+ mcunknown mcflset mcflmset mcloadedlocales mcforgetpackage\
22
+ mcpackageconfig mcpackagelocale
23
+
24
+ # Records the list of locales to search
25
+ variable Loclist {}
26
+
27
+ # List of currently loaded locales
28
+ variable LoadedLocales {}
29
+
30
+ # Records the locale of the currently sourced message catalogue file
31
+ variable FileLocale
32
+
33
+ # Configuration values per Package (e.g. client namespace).
34
+ # The dict key is of the form "<option> <namespace>" and the value is the
35
+ # configuration option. A nonexisting key is an unset option.
36
+ variable PackageConfig [dict create mcfolder {} loadcmd {} changecmd {}\
37
+ unknowncmd {} loadedlocales {} loclist {}]
38
+
39
+ # Records the mapping between source strings and translated strings. The
40
+ # dict key is of the form "<namespace> <locale> <src>", where locale and
41
+ # namespace should be themselves dict values and the value is
42
+ # the translated string.
43
+ variable Msgs [dict create]
44
+
45
+ # Map of language codes used in Windows registry to those of ISO-639
46
+ if {[info sharedlibextension] eq ".dll"} {
47
+ variable WinRegToISO639 [dict create {*}{
48
+ 01 ar 0401 ar_SA 0801 ar_IQ 0c01 ar_EG 1001 ar_LY 1401 ar_DZ
49
+ 1801 ar_MA 1c01 ar_TN 2001 ar_OM 2401 ar_YE 2801 ar_SY
50
+ 2c01 ar_JO 3001 ar_LB 3401 ar_KW 3801 ar_AE 3c01 ar_BH
51
+ 4001 ar_QA
52
+ 02 bg 0402 bg_BG
53
+ 03 ca 0403 ca_ES
54
+ 04 zh 0404 zh_TW 0804 zh_CN 0c04 zh_HK 1004 zh_SG 1404 zh_MO
55
+ 05 cs 0405 cs_CZ
56
+ 06 da 0406 da_DK
57
+ 07 de 0407 de_DE 0807 de_CH 0c07 de_AT 1007 de_LU 1407 de_LI
58
+ 08 el 0408 el_GR
59
+ 09 en 0409 en_US 0809 en_GB 0c09 en_AU 1009 en_CA 1409 en_NZ
60
+ 1809 en_IE 1c09 en_ZA 2009 en_JM 2409 en_GD 2809 en_BZ
61
+ 2c09 en_TT 3009 en_ZW 3409 en_PH
62
+ 0a es 040a es_ES 080a es_MX 0c0a es_ES@modern 100a es_GT 140a es_CR
63
+ 180a es_PA 1c0a es_DO 200a es_VE 240a es_CO 280a es_PE
64
+ 2c0a es_AR 300a es_EC 340a es_CL 380a es_UY 3c0a es_PY
65
+ 400a es_BO 440a es_SV 480a es_HN 4c0a es_NI 500a es_PR
66
+ 0b fi 040b fi_FI
67
+ 0c fr 040c fr_FR 080c fr_BE 0c0c fr_CA 100c fr_CH 140c fr_LU
68
+ 180c fr_MC
69
+ 0d he 040d he_IL
70
+ 0e hu 040e hu_HU
71
+ 0f is 040f is_IS
72
+ 10 it 0410 it_IT 0810 it_CH
73
+ 11 ja 0411 ja_JP
74
+ 12 ko 0412 ko_KR
75
+ 13 nl 0413 nl_NL 0813 nl_BE
76
+ 14 no 0414 no_NO 0814 nn_NO
77
+ 15 pl 0415 pl_PL
78
+ 16 pt 0416 pt_BR 0816 pt_PT
79
+ 17 rm 0417 rm_CH
80
+ 18 ro 0418 ro_RO 0818 ro_MO
81
+ 19 ru 0819 ru_MO
82
+ 1a hr 041a hr_HR 081a sr_YU 0c1a sr_YU@cyrillic
83
+ 1b sk 041b sk_SK
84
+ 1c sq 041c sq_AL
85
+ 1d sv 041d sv_SE 081d sv_FI
86
+ 1e th 041e th_TH
87
+ 1f tr 041f tr_TR
88
+ 20 ur 0420 ur_PK 0820 ur_IN
89
+ 21 id 0421 id_ID
90
+ 22 uk 0422 uk_UA
91
+ 23 be 0423 be_BY
92
+ 24 sl 0424 sl_SI
93
+ 25 et 0425 et_EE
94
+ 26 lv 0426 lv_LV
95
+ 27 lt 0427 lt_LT
96
+ 28 tg 0428 tg_TJ
97
+ 29 fa 0429 fa_IR
98
+ 2a vi 042a vi_VN
99
+ 2b hy 042b hy_AM
100
+ 2c az 042c az_AZ@latin 082c az_AZ@cyrillic
101
+ 2d eu
102
+ 2e wen 042e wen_DE
103
+ 2f mk 042f mk_MK
104
+ 30 bnt 0430 bnt_TZ
105
+ 31 ts 0431 ts_ZA
106
+ 32 tn
107
+ 33 ven 0433 ven_ZA
108
+ 34 xh 0434 xh_ZA
109
+ 35 zu 0435 zu_ZA
110
+ 36 af 0436 af_ZA
111
+ 37 ka 0437 ka_GE
112
+ 38 fo 0438 fo_FO
113
+ 39 hi 0439 hi_IN
114
+ 3a mt 043a mt_MT
115
+ 3b se 043b se_NO
116
+ 043c gd_UK 083c ga_IE
117
+ 3d yi 043d yi_IL
118
+ 3e ms 043e ms_MY 083e ms_BN
119
+ 3f kk 043f kk_KZ
120
+ 40 ky 0440 ky_KG
121
+ 41 sw 0441 sw_KE
122
+ 42 tk 0442 tk_TM
123
+ 43 uz 0443 uz_UZ@latin 0843 uz_UZ@cyrillic
124
+ 44 tt 0444 tt_RU
125
+ 45 bn 0445 bn_IN
126
+ 46 pa 0446 pa_IN
127
+ 47 gu 0447 gu_IN
128
+ 48 or 0448 or_IN
129
+ 49 ta
130
+ 4a te 044a te_IN
131
+ 4b kn 044b kn_IN
132
+ 4c ml 044c ml_IN
133
+ 4d as 044d as_IN
134
+ 4e mr 044e mr_IN
135
+ 4f sa 044f sa_IN
136
+ 50 mn
137
+ 51 bo 0451 bo_CN
138
+ 52 cy 0452 cy_GB
139
+ 53 km 0453 km_KH
140
+ 54 lo 0454 lo_LA
141
+ 55 my 0455 my_MM
142
+ 56 gl 0456 gl_ES
143
+ 57 kok 0457 kok_IN
144
+ 58 mni 0458 mni_IN
145
+ 59 sd
146
+ 5a syr 045a syr_TR
147
+ 5b si 045b si_LK
148
+ 5c chr 045c chr_US
149
+ 5d iu 045d iu_CA
150
+ 5e am 045e am_ET
151
+ 5f ber 045f ber_MA
152
+ 60 ks 0460 ks_PK 0860 ks_IN
153
+ 61 ne 0461 ne_NP 0861 ne_IN
154
+ 62 fy 0462 fy_NL
155
+ 63 ps
156
+ 64 tl 0464 tl_PH
157
+ 65 div 0465 div_MV
158
+ 66 bin 0466 bin_NG
159
+ 67 ful 0467 ful_NG
160
+ 68 ha 0468 ha_NG
161
+ 69 nic 0469 nic_NG
162
+ 6a yo 046a yo_NG
163
+ 70 ibo 0470 ibo_NG
164
+ 71 kau 0471 kau_NG
165
+ 72 om 0472 om_ET
166
+ 73 ti 0473 ti_ET
167
+ 74 gn 0474 gn_PY
168
+ 75 cpe 0475 cpe_US
169
+ 76 la 0476 la_VA
170
+ 77 so 0477 so_SO
171
+ 78 sit 0478 sit_CN
172
+ 79 pap 0479 pap_AN
173
+ }]
174
+ }
175
+ }
176
+
177
+ # msgcat::mc --
178
+ #
179
+ # Find the translation for the given string based on the current
180
+ # locale setting. Check the local namespace first, then look in each
181
+ # parent namespace until the source is found. If additional args are
182
+ # specified, use the format command to work them into the traslated
183
+ # string.
184
+ # If no catalog item is found, mcunknown is called in the caller frame
185
+ # and its result is returned.
186
+ #
187
+ # Arguments:
188
+ # src The string to translate.
189
+ # args Args to pass to the format command
190
+ #
191
+ # Results:
192
+ # Returns the translated string. Propagates errors thrown by the
193
+ # format command.
194
+
195
+ proc msgcat::mc {src args} {
196
+ # this may be replaced by:
197
+ # return [mcget -namespace [uplevel 1 [list ::namespace current]] --\
198
+ # $src {*}$args]
199
+
200
+ # Check for the src in each namespace starting from the local and
201
+ # ending in the global.
202
+
203
+ variable Msgs
204
+ variable Loclist
205
+
206
+ set ns [uplevel 1 [list ::namespace current]]
207
+ set loclist [PackagePreferences $ns]
208
+
209
+ set nscur $ns
210
+ while {$nscur != ""} {
211
+ foreach loc $loclist {
212
+ if {[dict exists $Msgs $nscur $loc $src]} {
213
+ return [DefaultUnknown "" [dict get $Msgs $nscur $loc $src]\
214
+ {*}$args]
215
+ }
216
+ }
217
+ set nscur [namespace parent $nscur]
218
+ }
219
+ # call package local or default unknown command
220
+ set args [linsert $args 0 [lindex $loclist 0] $src]
221
+ switch -exact -- [Invoke unknowncmd $args $ns result 1] {
222
+ 0 { return [uplevel 1 [linsert $args 0 [namespace origin mcunknown]]] }
223
+ 1 { return [DefaultUnknown {*}$args] }
224
+ default { return $result }
225
+ }
226
+ }
227
+
228
+ # msgcat::mcexists --
229
+ #
230
+ # Check if a catalog item is set or if mc would invoke mcunknown.
231
+ #
232
+ # Arguments:
233
+ # -exactnamespace Only check the exact namespace and no
234
+ # parent namespaces
235
+ # -exactlocale Only check the exact locale and not all members
236
+ # of the preferences list
237
+ # src Message catalog key
238
+ #
239
+ # Results:
240
+ # true if an adequate catalog key was found
241
+
242
+ proc msgcat::mcexists {args} {
243
+
244
+ variable Msgs
245
+ variable Loclist
246
+ variable PackageConfig
247
+
248
+ set ns [uplevel 1 [list ::namespace current]]
249
+ set loclist [PackagePreferences $ns]
250
+
251
+ while {[llength $args] != 1} {
252
+ set args [lassign $args option]
253
+ switch -glob -- $option {
254
+ -exactnamespace { set exactnamespace 1 }
255
+ -exactlocale { set loclist [lrange $loclist 0 0] }
256
+ -* { return -code error "unknown option \"$option\"" }
257
+ default {
258
+ return -code error "wrong # args: should be\
259
+ \"[lindex [info level 0] 0] ?-exactnamespace?\
260
+ ?-exactlocale? src\""
261
+ }
262
+ }
263
+ }
264
+ set src [lindex $args 0]
265
+
266
+ while {$ns ne ""} {
267
+ foreach loc $loclist {
268
+ if {[dict exists $Msgs $ns $loc $src]} {
269
+ return 1
270
+ }
271
+ }
272
+ if {[info exists exactnamespace]} {return 0}
273
+ set ns [namespace parent $ns]
274
+ }
275
+ return 0
276
+ }
277
+
278
+ # msgcat::mclocale --
279
+ #
280
+ # Query or set the current locale.
281
+ #
282
+ # Arguments:
283
+ # newLocale (Optional) The new locale string. Locale strings
284
+ # should be composed of one or more sublocale parts
285
+ # separated by underscores (e.g. en_US).
286
+ #
287
+ # Results:
288
+ # Returns the normalized set locale.
289
+
290
+ proc msgcat::mclocale {args} {
291
+ variable Loclist
292
+ variable LoadedLocales
293
+ set len [llength $args]
294
+
295
+ if {$len > 1} {
296
+ return -code error "wrong # args: should be\
297
+ \"[lindex [info level 0] 0] ?newLocale?\""
298
+ }
299
+
300
+ if {$len == 1} {
301
+ set newLocale [string tolower [lindex $args 0]]
302
+ if {$newLocale ne [file tail $newLocale]} {
303
+ return -code error "invalid newLocale value \"$newLocale\":\
304
+ could be path to unsafe code."
305
+ }
306
+ if {[lindex $Loclist 0] ne $newLocale} {
307
+ set Loclist [GetPreferences $newLocale]
308
+
309
+ # locale not loaded jet
310
+ LoadAll $Loclist
311
+ # Invoke callback
312
+ Invoke changecmd $Loclist
313
+ }
314
+ }
315
+ return [lindex $Loclist 0]
316
+ }
317
+
318
+ # msgcat::GetPreferences --
319
+ #
320
+ # Get list of locales from a locale.
321
+ # The first element is always the lowercase locale.
322
+ # Other elements have one component separated by "_" less.
323
+ # Multiple "_" are seen as one separator: de__ch_spec de__ch de {}
324
+ #
325
+ # Arguments:
326
+ # Locale.
327
+ #
328
+ # Results:
329
+ # Locale list
330
+
331
+ proc msgcat::GetPreferences {locale} {
332
+ set locale [string tolower $locale]
333
+ set loclist [list $locale]
334
+ while {-1 !=[set pos [string last "_" $locale]]} {
335
+ set locale [string range $locale 0 $pos-1]
336
+ if { "_" ne [string index $locale end] } {
337
+ lappend loclist $locale
338
+ }
339
+ }
340
+ if {"" ne [lindex $loclist end]} {
341
+ lappend loclist {}
342
+ }
343
+ return $loclist
344
+ }
345
+
346
+ # msgcat::mcpreferences --
347
+ #
348
+ # Fetch the list of locales used to look up strings, ordered from
349
+ # most preferred to least preferred.
350
+ #
351
+ # Arguments:
352
+ # None.
353
+ #
354
+ # Results:
355
+ # Returns an ordered list of the locales preferred by the user.
356
+
357
+ proc msgcat::mcpreferences {} {
358
+ variable Loclist
359
+ return $Loclist
360
+ }
361
+
362
+ # msgcat::mcloadedlocales --
363
+ #
364
+ # Get or change the list of currently loaded default locales
365
+ #
366
+ # The following subcommands are available:
367
+ # loaded
368
+ # Get the current list of loaded locales
369
+ # clear
370
+ # Remove all loaded locales not present in mcpreferences.
371
+ #
372
+ # Arguments:
373
+ # subcommand One of loaded or clear
374
+ #
375
+ # Results:
376
+ # Empty string, if not stated differently for the subcommand
377
+
378
+ proc msgcat::mcloadedlocales {subcommand} {
379
+ variable Loclist
380
+ variable LoadedLocales
381
+ variable Msgs
382
+ variable PackageConfig
383
+ switch -exact -- $subcommand {
384
+ clear {
385
+ # Remove all locales not contained in Loclist
386
+ # skip any packages with package locale
387
+ set LoadedLocales $Loclist
388
+ foreach ns [dict keys $Msgs] {
389
+ if {![dict exists $PackageConfig loclist $ns]} {
390
+ foreach locale [dict keys [dict get $Msgs $ns]] {
391
+ if {$locale ni $Loclist} {
392
+ dict unset Msgs $ns $locale
393
+ }
394
+ }
395
+ }
396
+ }
397
+ }
398
+ loaded { return $LoadedLocales }
399
+ default {
400
+ return -code error "unknown subcommand \"$subcommand\": must be\
401
+ clear, or loaded"
402
+ }
403
+ }
404
+ return
405
+ }
406
+
407
+ # msgcat::mcpackagelocale --
408
+ #
409
+ # Get or change the package locale of the calling package.
410
+ #
411
+ # The following subcommands are available:
412
+ # set
413
+ # Set a package locale.
414
+ # This may load message catalog files and may clear message catalog
415
+ # items, if the former locale was the default locale.
416
+ # Returns the normalized set locale.
417
+ # The default locale is taken, if locale is not given.
418
+ # get
419
+ # Get the locale valid for this package.
420
+ # isset
421
+ # Returns true, if a package locale is set
422
+ # unset
423
+ # Unset the package locale and activate the default locale.
424
+ # This loads message catalog file which where missing in the package
425
+ # locale.
426
+ # preferences
427
+ # Return locale preference list valid for the package.
428
+ # loaded
429
+ # Return loaded locale list valid for the current package.
430
+ # clear
431
+ # If the current package has a package locale, remove all package
432
+ # locales not containes in package mcpreferences.
433
+ # It is an error to call this without a package locale set.
434
+ #
435
+ # The subcommands get, preferences and loaded return the corresponding
436
+ # default data, if no package locale is set.
437
+ #
438
+ # Arguments:
439
+ # subcommand see list above
440
+ # locale package locale (only set subcommand)
441
+ #
442
+ # Results:
443
+ # Empty string, if not stated differently for the subcommand
444
+
445
+ proc msgcat::mcpackagelocale {subcommand {locale ""}} {
446
+ # todo: implement using an ensemble
447
+ variable Loclist
448
+ variable LoadedLocales
449
+ variable Msgs
450
+ variable PackageConfig
451
+ # Check option
452
+ # check if required item is exactly provided
453
+ if {[llength [info level 0]] == 2} {
454
+ # locale not given
455
+ unset locale
456
+ } else {
457
+ # locale given
458
+ if {$subcommand in
459
+ {"get" "isset" "unset" "preferences" "loaded" "clear"} } {
460
+ return -code error "wrong # args: should be\
461
+ \"[lrange [info level 0] 0 1]\""
462
+ }
463
+ set locale [string tolower $locale]
464
+ }
465
+ set ns [uplevel 1 {::namespace current}]
466
+
467
+ switch -exact -- $subcommand {
468
+ get { return [lindex [PackagePreferences $ns] 0] }
469
+ preferences { return [PackagePreferences $ns] }
470
+ loaded { return [PackageLocales $ns] }
471
+ present { return [expr {$locale in [PackageLocales $ns]} ]}
472
+ isset { return [dict exists $PackageConfig loclist $ns] }
473
+ set { # set a package locale or add a package locale
474
+
475
+ # Copy the default locale if no package locale set so far
476
+ if {![dict exists $PackageConfig loclist $ns]} {
477
+ dict set PackageConfig loclist $ns $Loclist
478
+ dict set PackageConfig loadedlocales $ns $LoadedLocales
479
+ }
480
+
481
+ # Check if changed
482
+ set loclist [dict get $PackageConfig loclist $ns]
483
+ if {! [info exists locale] || $locale eq [lindex $loclist 0] } {
484
+ return [lindex $loclist 0]
485
+ }
486
+
487
+ # Change loclist
488
+ set loclist [GetPreferences $locale]
489
+ set locale [lindex $loclist 0]
490
+ dict set PackageConfig loclist $ns $loclist
491
+
492
+ # load eventual missing locales
493
+ set loadedLocales [dict get $PackageConfig loadedlocales $ns]
494
+ if {$locale in $loadedLocales} { return $locale }
495
+ set loadLocales [ListComplement $loadedLocales $loclist]
496
+ dict set PackageConfig loadedlocales $ns\
497
+ [concat $loadedLocales $loadLocales]
498
+ Load $ns $loadLocales
499
+ return $locale
500
+ }
501
+ clear { # Remove all locales not contained in Loclist
502
+ if {![dict exists $PackageConfig loclist $ns]} {
503
+ return -code error "clear only when package locale set"
504
+ }
505
+ set loclist [dict get $PackageConfig loclist $ns]
506
+ dict set PackageConfig loadedlocales $ns $loclist
507
+ if {[dict exists $Msgs $ns]} {
508
+ foreach locale [dict keys [dict get $Msgs $ns]] {
509
+ if {$locale ni $loclist} {
510
+ dict unset Msgs $ns $locale
511
+ }
512
+ }
513
+ }
514
+ }
515
+ unset { # unset package locale and restore default locales
516
+
517
+ if { ![dict exists $PackageConfig loclist $ns] } { return }
518
+
519
+ # unset package locale
520
+ set loadLocales [ListComplement\
521
+ [dict get $PackageConfig loadedlocales $ns] $LoadedLocales]
522
+ dict unset PackageConfig loadedlocales $ns
523
+ dict unset PackageConfig loclist $ns
524
+
525
+ # unset keys not in global loaded locales
526
+ if {[dict exists $Msgs $ns]} {
527
+ foreach locale [dict keys [dict get $Msgs $ns]] {
528
+ if {$locale ni $LoadedLocales} {
529
+ dict unset Msgs $ns $locale
530
+ }
531
+ }
532
+ }
533
+
534
+ # Add missing locales
535
+ Load $ns $loadLocales
536
+ }
537
+ default {
538
+ return -code error "unknown subcommand \"$subcommand\": must be\
539
+ clear, get, isset, loaded, present, set, or unset"
540
+ }
541
+ }
542
+ return
543
+ }
544
+
545
+ # msgcat::mcforgetpackage --
546
+ #
547
+ # Remove any data of the calling package from msgcat
548
+ #
549
+
550
+ proc msgcat::mcforgetpackage {} {
551
+ # todo: this may be implemented using an ensemble
552
+ variable PackageConfig
553
+ variable Msgs
554
+ set ns [uplevel 1 {::namespace current}]
555
+ # Remove MC items
556
+ dict unset Msgs $ns
557
+ # Remove config items
558
+ foreach key [dict keys $PackageConfig] {
559
+ dict unset PackageConfig $key $ns
560
+ }
561
+ return
562
+ }
563
+
564
+ # msgcat::mcpackageconfig --
565
+ #
566
+ # Get or modify the per caller namespace (e.g. packages) config options.
567
+ #
568
+ # Available subcommands are:
569
+ #
570
+ # get get the current value or an error if not set.
571
+ # isset return true, if the option is set
572
+ # set set the value (see also distinct option).
573
+ # Returns the number of loaded message files.
574
+ # unset Clear option. return "".
575
+ #
576
+ # Available options are:
577
+ #
578
+ # mcfolder
579
+ # The message catalog folder of the package.
580
+ # This is automatically set by mcload.
581
+ # If the value is changed using the set subcommand, an evntual
582
+ # loadcmd is invoked and all message files of the package locale are
583
+ # loaded.
584
+ #
585
+ # loadcmd
586
+ # The command gets executed before a message file would be
587
+ # sourced for this module.
588
+ # The command is invoked with the expanded locale list to load.
589
+ # The command is not invoked if the registering package namespace
590
+ # is not present.
591
+ # This callback might also be used as an alternative to message
592
+ # files.
593
+ # If the value is changed using the set subcommand, the callback is
594
+ # directly invoked with the current file locale list. No file load is
595
+ # executed.
596
+ #
597
+ # changecmd
598
+ # The command is invoked, after an executed locale change.
599
+ # Appended argument is expanded mcpreferences.
600
+ #
601
+ # unknowncmd
602
+ # Use a package locale mcunknown procedure instead the global one.
603
+ # The appended arguments are identical to mcunknown.
604
+ # A default unknown handler is used if set to the empty string.
605
+ # This consists in returning the key if no arguments are given.
606
+ # With given arguments, format is used to process the arguments.
607
+ #
608
+ # Arguments:
609
+ # subcommand Operation on the package
610
+ # option The package option to get or set.
611
+ # ?value? Eventual value for the subcommand
612
+ #
613
+ # Results:
614
+ # Depends on the subcommand and option and is described there
615
+
616
+ proc msgcat::mcpackageconfig {subcommand option {value ""}} {
617
+ variable PackageConfig
618
+ # get namespace
619
+ set ns [uplevel 1 {::namespace current}]
620
+
621
+ if {$option ni {"mcfolder" "loadcmd" "changecmd" "unknowncmd"}} {
622
+ return -code error "bad option \"$option\": must be mcfolder, loadcmd,\
623
+ changecmd, or unknowncmd"
624
+ }
625
+
626
+ # check if value argument is exactly provided
627
+ if {[llength [info level 0]] == 4 } {
628
+ # value provided
629
+ if {$subcommand in {"get" "isset" "unset"}} {
630
+ return -code error "wrong # args: should be\
631
+ \"[lrange [info level 0] 0 2] value\""
632
+ }
633
+ } elseif {$subcommand eq "set"} {
634
+ return -code error\
635
+ "wrong # args: should be \"[lrange [info level 0] 0 2]\""
636
+ }
637
+
638
+ # Execute subcommands
639
+ switch -exact -- $subcommand {
640
+ get { # Operation get return current value
641
+ if {![dict exists $PackageConfig $option $ns]} {
642
+ return -code error "package option \"$option\" not set"
643
+ }
644
+ return [dict get $PackageConfig $option $ns]
645
+ }
646
+ isset { return [dict exists $PackageConfig $option $ns] }
647
+ unset { dict unset PackageConfig $option $ns }
648
+ set { # Set option
649
+
650
+ if {$option eq "mcfolder"} {
651
+ set value [file normalize $value]
652
+ }
653
+ # Check if changed
654
+ if { [dict exists $PackageConfig $option $ns]
655
+ && $value eq [dict get $PackageConfig $option $ns] } {
656
+ return 0
657
+ }
658
+
659
+ # set new value
660
+ dict set PackageConfig $option $ns $value
661
+
662
+ # Reload pending message catalogs
663
+ switch -exact -- $option {
664
+ mcfolder { return [Load $ns [PackageLocales $ns]] }
665
+ loadcmd { return [Load $ns [PackageLocales $ns] 1] }
666
+ }
667
+ return 0
668
+ }
669
+ default {
670
+ return -code error "unknown subcommand \"$subcommand\":\
671
+ must be get, isset, set, or unset"
672
+ }
673
+ }
674
+ return
675
+ }
676
+
677
+ # msgcat::PackagePreferences --
678
+ #
679
+ # Return eventual present package preferences or the default list if not
680
+ # present.
681
+ #
682
+ # Arguments:
683
+ # ns Package namespace
684
+ #
685
+ # Results:
686
+ # locale list
687
+
688
+ proc msgcat::PackagePreferences {ns} {
689
+ variable PackageConfig
690
+ if {[dict exists $PackageConfig loclist $ns]} {
691
+ return [dict get $PackageConfig loclist $ns]
692
+ }
693
+ variable Loclist
694
+ return $Loclist
695
+ }
696
+
697
+ # msgcat::PackageLocales --
698
+ #
699
+ # Return eventual present package locales or the default list if not
700
+ # present.
701
+ #
702
+ # Arguments:
703
+ # ns Package namespace
704
+ #
705
+ # Results:
706
+ # locale list
707
+
708
+ proc msgcat::PackageLocales {ns} {
709
+ variable PackageConfig
710
+ if {[dict exists $PackageConfig loadedlocales $ns]} {
711
+ return [dict get $PackageConfig loadedlocales $ns]
712
+ }
713
+ variable LoadedLocales
714
+ return $LoadedLocales
715
+ }
716
+
717
+ # msgcat::ListComplement --
718
+ #
719
+ # Build the complement of two lists.
720
+ # Return a list with all elements in list2 but not in list1.
721
+ # Optionally return the intersection.
722
+ #
723
+ # Arguments:
724
+ # list1 excluded list
725
+ # list2 included list
726
+ # inlistname If not "", write in this variable the intersection list
727
+ #
728
+ # Results:
729
+ # list with all elements in list2 but not in list1
730
+
731
+ proc msgcat::ListComplement {list1 list2 {inlistname ""}} {
732
+ if {"" ne $inlistname} {
733
+ upvar 1 $inlistname inlist
734
+ }
735
+ set inlist {}
736
+ set outlist {}
737
+ foreach item $list2 {
738
+ if {$item in $list1} {
739
+ lappend inlist $item
740
+ } else {
741
+ lappend outlist $item
742
+ }
743
+ }
744
+ return $outlist
745
+ }
746
+
747
+ # msgcat::mcload --
748
+ #
749
+ # Attempt to load message catalogs for each locale in the
750
+ # preference list from the specified directory.
751
+ #
752
+ # Arguments:
753
+ # langdir The directory to search.
754
+ #
755
+ # Results:
756
+ # Returns the number of message catalogs that were loaded.
757
+
758
+ proc msgcat::mcload {langdir} {
759
+ return [uplevel 1 [list\
760
+ [namespace origin mcpackageconfig] set mcfolder $langdir]]
761
+ }
762
+
763
+ # msgcat::LoadAll --
764
+ #
765
+ # Load a list of locales for all packages not having a package locale
766
+ # list.
767
+ #
768
+ # Arguments:
769
+ # langdir The directory to search.
770
+ #
771
+ # Results:
772
+ # Returns the number of message catalogs that were loaded.
773
+
774
+ proc msgcat::LoadAll {locales} {
775
+ variable PackageConfig
776
+ variable LoadedLocales
777
+ if {0 == [llength $locales]} { return {} }
778
+ # filter jet unloaded locales
779
+ set locales [ListComplement $LoadedLocales $locales]
780
+ if {0 == [llength $locales]} { return {} }
781
+ lappend LoadedLocales {*}$locales
782
+
783
+ set packages [lsort -unique [concat\
784
+ [dict keys [dict get $PackageConfig loadcmd]]\
785
+ [dict keys [dict get $PackageConfig mcfolder]]]]
786
+ foreach ns $packages {
787
+ if {! [dict exists $PackageConfig loclist $ns] } {
788
+ Load $ns $locales
789
+ }
790
+ }
791
+ return $locales
792
+ }
793
+
794
+ # msgcat::Load --
795
+ #
796
+ # Invoke message load callback and load message catalog files.
797
+ #
798
+ # Arguments:
799
+ # ns Namespace (equal package) to load the message catalog.
800
+ # locales List of locales to load.
801
+ # callbackonly true if only callback should be invoked
802
+ #
803
+ # Results:
804
+ # Returns the number of message catalogs that were loaded.
805
+
806
+ proc msgcat::Load {ns locales {callbackonly 0}} {
807
+ variable FileLocale
808
+ variable PackageConfig
809
+ variable LoadedLocals
810
+
811
+ if {0 == [llength $locales]} { return 0 }
812
+
813
+ # Invoke callback
814
+ Invoke loadcmd $locales $ns
815
+
816
+ if {$callbackonly || ![dict exists $PackageConfig mcfolder $ns]} {
817
+ return 0
818
+ }
819
+
820
+ # Invoke file load
821
+ set langdir [dict get $PackageConfig mcfolder $ns]
822
+
823
+ # Save the file locale if we are recursively called
824
+ if {[info exists FileLocale]} {
825
+ set nestedFileLocale $FileLocale
826
+ }
827
+ set x 0
828
+ foreach p $locales {
829
+ if {$p eq {}} {
830
+ set p ROOT
831
+ }
832
+ set langfile [file join $langdir $p.msg]
833
+ if {[file exists $langfile]} {
834
+ incr x
835
+ set FileLocale [string tolower\
836
+ [file tail [file rootname $langfile]]]
837
+ if {"root" eq $FileLocale} {
838
+ set FileLocale ""
839
+ }
840
+ namespace inscope $ns [list ::source -encoding utf-8 $langfile]
841
+ unset FileLocale
842
+ }
843
+ }
844
+ if {[info exists nestedFileLocale]} {
845
+ set FileLocale $nestedFileLocale
846
+ }
847
+ return $x
848
+ }
849
+
850
+ # msgcat::Invoke --
851
+ #
852
+ # Invoke a set of registered callbacks.
853
+ # The callback is only invoked, if its registered namespace exists.
854
+ #
855
+ # Arguments:
856
+ # index Index into PackageConfig to get callback command
857
+ # arglist parameters to the callback invocation
858
+ # ns (Optional) package to call.
859
+ # If not given or empty, check all registered packages.
860
+ # resultname Variable to save the callback result of the last called
861
+ # callback to. May be set to "" to discard the result.
862
+ # failerror (0) Fail on error if true. Otherwise call bgerror.
863
+ #
864
+ # Results:
865
+ # Possible values:
866
+ # - 0: no valid command registered
867
+ # - 1: registered command was the empty string
868
+ # - 2: registered command called, resultname is set
869
+ # - 3: registered command failed
870
+ # If multiple commands are called, the maximum of all results is returned.
871
+
872
+ proc msgcat::Invoke {index arglist {ns ""} {resultname ""} {failerror 0}} {
873
+ variable PackageConfig
874
+ variable Config
875
+ if {"" ne $resultname} {
876
+ upvar 1 $resultname result
877
+ }
878
+ if {"" eq $ns} {
879
+ set packageList [dict keys [dict get $PackageConfig $index]]
880
+ } else {
881
+ set packageList [list $ns]
882
+ }
883
+ set ret 0
884
+ foreach ns $packageList {
885
+ if {[dict exists $PackageConfig $index $ns] && [namespace exists $ns]} {
886
+ set cmd [dict get $PackageConfig $index $ns]
887
+ if {"" eq $cmd} {
888
+ if {$ret == 0} {set ret 1}
889
+ } else {
890
+ if {$failerror} {
891
+ set result [namespace inscope $ns $cmd {*}$arglist]
892
+ set ret 2
893
+ } elseif {1 == [catch {
894
+ set result [namespace inscope $ns $cmd {*}$arglist]
895
+ if {$ret < 2} {set ret 2}
896
+ } err derr]} {
897
+ after idle [concat [::interp bgerror ""]\
898
+ [list $err $derr]]
899
+ set ret 3
900
+ }
901
+ }
902
+ }
903
+ }
904
+ return $ret
905
+ }
906
+
907
+ # msgcat::mcset --
908
+ #
909
+ # Set the translation for a given string in a specified locale.
910
+ #
911
+ # Arguments:
912
+ # locale The locale to use.
913
+ # src The source string.
914
+ # dest (Optional) The translated string. If omitted,
915
+ # the source string is used.
916
+ #
917
+ # Results:
918
+ # Returns the new locale.
919
+
920
+ proc msgcat::mcset {locale src {dest ""}} {
921
+ variable Msgs
922
+ if {[llength [info level 0]] == 3} { ;# dest not specified
923
+ set dest $src
924
+ }
925
+
926
+ set ns [uplevel 1 [list ::namespace current]]
927
+
928
+ set locale [string tolower $locale]
929
+
930
+ dict set Msgs $ns $locale $src $dest
931
+ return $dest
932
+ }
933
+
934
+ # msgcat::mcflset --
935
+ #
936
+ # Set the translation for a given string in the current file locale.
937
+ #
938
+ # Arguments:
939
+ # src The source string.
940
+ # dest (Optional) The translated string. If omitted,
941
+ # the source string is used.
942
+ #
943
+ # Results:
944
+ # Returns the new locale.
945
+
946
+ proc msgcat::mcflset {src {dest ""}} {
947
+ variable FileLocale
948
+ variable Msgs
949
+
950
+ if {![info exists FileLocale]} {
951
+ return -code error "must only be used inside a message catalog loaded\
952
+ with ::msgcat::mcload"
953
+ }
954
+ return [uplevel 1 [list [namespace origin mcset] $FileLocale $src $dest]]
955
+ }
956
+
957
+ # msgcat::mcmset --
958
+ #
959
+ # Set the translation for multiple strings in a specified locale.
960
+ #
961
+ # Arguments:
962
+ # locale The locale to use.
963
+ # pairs One or more src/dest pairs (must be even length)
964
+ #
965
+ # Results:
966
+ # Returns the number of pairs processed
967
+
968
+ proc msgcat::mcmset {locale pairs} {
969
+ variable Msgs
970
+
971
+ set length [llength $pairs]
972
+ if {$length % 2} {
973
+ return -code error "bad translation list:\
974
+ should be \"[lindex [info level 0] 0] locale {src dest ...}\""
975
+ }
976
+
977
+ set locale [string tolower $locale]
978
+ set ns [uplevel 1 [list ::namespace current]]
979
+
980
+ foreach {src dest} $pairs {
981
+ dict set Msgs $ns $locale $src $dest
982
+ }
983
+
984
+ return [expr {$length / 2}]
985
+ }
986
+
987
+ # msgcat::mcflmset --
988
+ #
989
+ # Set the translation for multiple strings in the mc file locale.
990
+ #
991
+ # Arguments:
992
+ # pairs One or more src/dest pairs (must be even length)
993
+ #
994
+ # Results:
995
+ # Returns the number of pairs processed
996
+
997
+ proc msgcat::mcflmset {pairs} {
998
+ variable FileLocale
999
+ variable Msgs
1000
+
1001
+ if {![info exists FileLocale]} {
1002
+ return -code error "must only be used inside a message catalog loaded\
1003
+ with ::msgcat::mcload"
1004
+ }
1005
+ return [uplevel 1 [list [namespace origin mcmset] $FileLocale $pairs]]
1006
+ }
1007
+
1008
+ # msgcat::mcunknown --
1009
+ #
1010
+ # This routine is called by msgcat::mc if a translation cannot
1011
+ # be found for a string and no unknowncmd is set for the current
1012
+ # package. This routine is intended to be replaced
1013
+ # by an application specific routine for error reporting
1014
+ # purposes. The default behavior is to return the source string.
1015
+ # If additional args are specified, the format command will be used
1016
+ # to work them into the traslated string.
1017
+ #
1018
+ # Arguments:
1019
+ # locale The current locale.
1020
+ # src The string to be translated.
1021
+ # args Args to pass to the format command
1022
+ #
1023
+ # Results:
1024
+ # Returns the translated value.
1025
+
1026
+ proc msgcat::mcunknown {args} {
1027
+ return [uplevel 1 [list [namespace origin DefaultUnknown] {*}$args]]
1028
+ }
1029
+
1030
+ # msgcat::DefaultUnknown --
1031
+ #
1032
+ # This routine is called by msgcat::mc if a translation cannot
1033
+ # be found for a string in the following circumstances:
1034
+ # - Default global handler, if mcunknown is not redefined.
1035
+ # - Per package handler, if the package sets unknowncmd to the empty
1036
+ # string.
1037
+ # It returna the source string if the argument list is empty.
1038
+ # If additional args are specified, the format command will be used
1039
+ # to work them into the traslated string.
1040
+ #
1041
+ # Arguments:
1042
+ # locale (unused) The current locale.
1043
+ # src The string to be translated.
1044
+ # args Args to pass to the format command
1045
+ #
1046
+ # Results:
1047
+ # Returns the translated value.
1048
+
1049
+ proc msgcat::DefaultUnknown {locale src args} {
1050
+ if {[llength $args]} {
1051
+ return [format $src {*}$args]
1052
+ } else {
1053
+ return $src
1054
+ }
1055
+ }
1056
+
1057
+ # msgcat::mcmax --
1058
+ #
1059
+ # Calculates the maximum length of the translated strings of the given
1060
+ # list.
1061
+ #
1062
+ # Arguments:
1063
+ # args strings to translate.
1064
+ #
1065
+ # Results:
1066
+ # Returns the length of the longest translated string.
1067
+
1068
+ proc msgcat::mcmax {args} {
1069
+ set max 0
1070
+ foreach string $args {
1071
+ set translated [uplevel 1 [list [namespace origin mc] $string]]
1072
+ set len [string length $translated]
1073
+ if {$len>$max} {
1074
+ set max $len
1075
+ }
1076
+ }
1077
+ return $max
1078
+ }
1079
+
1080
+ # Convert the locale values stored in environment variables to a form
1081
+ # suitable for passing to [mclocale]
1082
+ proc msgcat::ConvertLocale {value} {
1083
+ # Assume $value is of form: $language[_$territory][.$codeset][@modifier]
1084
+ # Convert to form: $language[_$territory][_$modifier]
1085
+ #
1086
+ # Comment out expanded RE version -- bugs alleged
1087
+ # regexp -expanded {
1088
+ # ^ # Match all the way to the beginning
1089
+ # ([^_.@]*) # Match "lanugage"; ends with _, ., or @
1090
+ # (_([^.@]*))? # Match (optional) "territory"; starts with _
1091
+ # ([.]([^@]*))? # Match (optional) "codeset"; starts with .
1092
+ # (@(.*))? # Match (optional) "modifier"; starts with @
1093
+ # $ # Match all the way to the end
1094
+ # } $value -> language _ territory _ codeset _ modifier
1095
+ if {![regexp {^([^_.@]+)(_([^.@]*))?([.]([^@]*))?(@(.*))?$} $value \
1096
+ -> language _ territory _ codeset _ modifier]} {
1097
+ return -code error "invalid locale '$value': empty language part"
1098
+ }
1099
+ set ret $language
1100
+ if {[string length $territory]} {
1101
+ append ret _$territory
1102
+ }
1103
+ if {[string length $modifier]} {
1104
+ append ret _$modifier
1105
+ }
1106
+ return $ret
1107
+ }
1108
+
1109
+ # Initialize the default locale
1110
+ proc msgcat::Init {} {
1111
+ global env
1112
+
1113
+ #
1114
+ # set default locale, try to get from environment
1115
+ #
1116
+ foreach varName {LC_ALL LC_MESSAGES LANG} {
1117
+ if {[info exists env($varName)] && ("" ne $env($varName))} {
1118
+ if {![catch {
1119
+ mclocale [ConvertLocale $env($varName)]
1120
+ }]} {
1121
+ return
1122
+ }
1123
+ }
1124
+ }
1125
+ #
1126
+ # On Darwin, fallback to current CFLocale identifier if available.
1127
+ #
1128
+ if {[info exists ::tcl::mac::locale] && $::tcl::mac::locale ne ""} {
1129
+ if {![catch {
1130
+ mclocale [ConvertLocale $::tcl::mac::locale]
1131
+ }]} {
1132
+ return
1133
+ }
1134
+ }
1135
+ #
1136
+ # The rest of this routine is special processing for Windows or
1137
+ # Cygwin. All other platforms, get out now.
1138
+ #
1139
+ if {([info sharedlibextension] ne ".dll")
1140
+ || [catch {package require registry}]} {
1141
+ mclocale C
1142
+ return
1143
+ }
1144
+ #
1145
+ # On Windows or Cygwin, try to set locale depending on registry
1146
+ # settings, or fall back on locale of "C".
1147
+ #
1148
+
1149
+ # On Vista and later:
1150
+ # HCU/Control Panel/Desktop : PreferredUILanguages is for language packs,
1151
+ # HCU/Control Pannel/International : localName is the default locale.
1152
+ #
1153
+ # They contain the local string as RFC5646, composed of:
1154
+ # [a-z]{2,3} : language
1155
+ # -[a-z]{4} : script (optional, translated by table Latn->latin)
1156
+ # -[a-z]{2}|[0-9]{3} : territory (optional, numerical region codes not used)
1157
+ # (-.*)* : variant, extension, private use (optional, not used)
1158
+ # Those are translated to local strings.
1159
+ # Examples: de-CH -> de_ch, sr-Latn-CS -> sr_cs@latin, es-419 -> es
1160
+ #
1161
+ foreach key {{HKEY_CURRENT_USER\Control Panel\Desktop} {HKEY_CURRENT_USER\Control Panel\International}}\
1162
+ value {PreferredUILanguages localeName} {
1163
+ if {![catch {registry get $key $value} localeName]
1164
+ && [regexp {^([a-z]{2,3})(?:-([a-z]{4}))?(?:-([a-z]{2}))?(?:-.+)?$}\
1165
+ [string tolower $localeName] match locale script territory]} {
1166
+ if {"" ne $territory} {
1167
+ append locale _ $territory
1168
+ }
1169
+ set modifierDict [dict create latn latin cyrl cyrillic]
1170
+ if {[dict exists $modifierDict $script]} {
1171
+ append locale @ [dict get $modifierDict $script]
1172
+ }
1173
+ if {![catch {mclocale [ConvertLocale $locale]}]} {
1174
+ return
1175
+ }
1176
+ }
1177
+ }
1178
+
1179
+ # then check value locale which contains a numerical language ID
1180
+ if {[catch {
1181
+ set locale [registry get $key "locale"]
1182
+ }]} {
1183
+ mclocale C
1184
+ return
1185
+ }
1186
+ #
1187
+ # Keep trying to match against smaller and smaller suffixes
1188
+ # of the registry value, since the latter hexadigits appear
1189
+ # to determine general language and earlier hexadigits determine
1190
+ # more precise information, such as territory. For example,
1191
+ # 0409 - English - United States
1192
+ # 0809 - English - United Kingdom
1193
+ # Add more translations to the WinRegToISO639 array above.
1194
+ #
1195
+ variable WinRegToISO639
1196
+ set locale [string tolower $locale]
1197
+ while {[string length $locale]} {
1198
+ if {![catch {
1199
+ mclocale [ConvertLocale [dict get $WinRegToISO639 $locale]]
1200
+ }]} {
1201
+ return
1202
+ }
1203
+ set locale [string range $locale 1 end]
1204
+ }
1205
+ #
1206
+ # No translation known. Fall back on "C" locale
1207
+ #
1208
+ mclocale C
1209
+ }
1210
+ msgcat::Init
my_container_sandbox/workspace/anaconda3/lib/tcl8/8.5/tcltest-2.5.3.tm ADDED
The diff for this file is too large to render. See raw diff
 
my_container_sandbox/workspace/anaconda3/lib/tcl8/8.6/http-2.9.5.tm ADDED
The diff for this file is too large to render. See raw diff
 
my_container_sandbox/workspace/anaconda3/lib/tcl8/8.6/tdbc/sqlite3-1.1.3.tm ADDED
@@ -0,0 +1,715 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # tdbcsqlite3.tcl --
2
+ #
3
+ # SQLite3 database driver for TDBC
4
+ #
5
+ # Copyright (c) 2008 by Kevin B. Kenny.
6
+ # See the file "license.terms" for information on usage and redistribution
7
+ # of this file, and for a DISCLAIMER OF ALL WARRANTIES.
8
+ #
9
+ # RCS: @(#) $Id: tdbcodbc.tcl,v 1.47 2008/02/27 02:08:27 kennykb Exp $
10
+ #
11
+ #------------------------------------------------------------------------------
12
+
13
+ package require tdbc
14
+ package require sqlite3
15
+
16
+ package provide tdbc::sqlite3 1.1.3
17
+
18
+ namespace eval tdbc::sqlite3 {
19
+ namespace export connection
20
+ }
21
+
22
+ #------------------------------------------------------------------------------
23
+ #
24
+ # tdbc::sqlite3::connection --
25
+ #
26
+ # Class representing a SQLite3 database connection
27
+ #
28
+ #------------------------------------------------------------------------------
29
+
30
+ ::oo::class create ::tdbc::sqlite3::connection {
31
+
32
+ superclass ::tdbc::connection
33
+
34
+ variable timeout
35
+
36
+ # The constructor accepts a database name and opens the database.
37
+
38
+ constructor {databaseName args} {
39
+ set timeout 0
40
+ if {[llength $args] % 2 != 0} {
41
+ set cmd [lrange [info level 0] 0 end-[llength $args]]
42
+ return -code error \
43
+ -errorcode {TDBC GENERAL_ERROR HY000 SQLITE3 WRONGNUMARGS} \
44
+ "wrong # args, should be \"$cmd ?-option value?...\""
45
+ }
46
+ next
47
+ sqlite3 [namespace current]::db $databaseName
48
+ if {[llength $args] > 0} {
49
+ my configure {*}$args
50
+ }
51
+ db nullvalue \ufffd
52
+ }
53
+
54
+ # The 'statementCreate' method forwards to the constructor of the
55
+ # statement class
56
+
57
+ forward statementCreate ::tdbc::sqlite3::statement create
58
+
59
+ # The 'configure' method queries and sets options to the database
60
+
61
+ method configure args {
62
+ if {[llength $args] == 0} {
63
+
64
+ # Query all configuration options
65
+
66
+ set result {-encoding utf-8}
67
+ lappend result -isolation
68
+ if {[db onecolumn {PRAGMA read_uncommitted}]} {
69
+ lappend result readuncommitted
70
+ } else {
71
+ lappend result serializable
72
+ }
73
+ lappend result -readonly 0
74
+ lappend result -timeout $timeout
75
+ return $result
76
+
77
+ } elseif {[llength $args] == 1} {
78
+
79
+ # Query a single option
80
+
81
+ set option [lindex $args 0]
82
+ switch -exact -- $option {
83
+ -e - -en - -enc - -enco - -encod - -encodi - -encodin -
84
+ -encoding {
85
+ return utf-8
86
+ }
87
+ -i - -is - -iso - -isol - -isola - -isolat - -isolati -
88
+ -isolatio - -isolation {
89
+ if {[db onecolumn {PRAGMA read_uncommitted}]} {
90
+ return readuncommitted
91
+ } else {
92
+ return serializable
93
+ }
94
+ }
95
+ -r - -re - -rea - -read - -reado - -readon - -readonl -
96
+ -readonly {
97
+ return 0
98
+ }
99
+ -t - -ti - -tim - -time - -timeo - -timeou - -timeout {
100
+ return $timeout
101
+ }
102
+ default {
103
+ return -code error \
104
+ -errorcode [list TDBC GENERAL_ERROR HY000 SQLITE3 \
105
+ BADOPTION $option] \
106
+ "bad option \"$option\": must be\
107
+ -encoding, -isolation, -readonly or -timeout"
108
+
109
+ }
110
+ }
111
+
112
+ } elseif {[llength $args] % 2 != 0} {
113
+
114
+ # Syntax error
115
+
116
+ set cmd [lrange [info level 0] 0 end-[llength $args]]
117
+ return -code error \
118
+ -errorcode [list TDBC GENERAL_ERROR HY000 \
119
+ SQLITE3 WRONGNUMARGS] \
120
+ "wrong # args, should be \" $cmd ?-option value?...\""
121
+ }
122
+
123
+ # Set one or more options
124
+
125
+ foreach {option value} $args {
126
+ switch -exact -- $option {
127
+ -e - -en - -enc - -enco - -encod - -encodi - -encodin -
128
+ -encoding {
129
+ if {$value ne {utf-8}} {
130
+ return -code error \
131
+ -errorcode [list TDBC FEATURE_NOT_SUPPORTED 0A000 \
132
+ SQLITE3 ENCODING] \
133
+ "-encoding not supported. SQLite3 is always \
134
+ Unicode."
135
+ }
136
+ }
137
+ -i - -is - -iso - -isol - -isola - -isolat - -isolati -
138
+ -isolatio - -isolation {
139
+ switch -exact -- $value {
140
+ readu - readun - readunc - readunco - readuncom -
141
+ readuncomm - readuncommi - readuncommit -
142
+ readuncommitt - readuncommitte - readuncommitted {
143
+ db eval {PRAGMA read_uncommitted = 1}
144
+ }
145
+ readc - readco - readcom - readcomm - readcommi -
146
+ readcommit - readcommitt - readcommitte -
147
+ readcommitted -
148
+ rep - repe - repea - repeat - repeata - repeatab -
149
+ repeatabl - repeatable - repeatabler - repeatablere -
150
+ repeatablerea - repeatablread -
151
+ s - se - ser - seri - seria - serial - seriali -
152
+ serializ - serializa - serializab - serializabl -
153
+ serializable -
154
+ reado - readon - readonl - readonly {
155
+ db eval {PRAGMA read_uncommitted = 0}
156
+ }
157
+ default {
158
+ return -code error \
159
+ -errorcode [list TDBC GENERAL_ERROR HY000 \
160
+ SQLITE3 BADISOLATION $value] \
161
+ "bad isolation level \"$value\":\
162
+ should be readuncommitted, readcommitted,\
163
+ repeatableread, serializable, or readonly"
164
+ }
165
+ }
166
+ }
167
+ -r - -re - -rea - -read - -reado - -readon - -readonl -
168
+ -readonly {
169
+ if {$value} {
170
+ return -code error \
171
+ -errorcode [list TDBC FEATURE_NOT_SUPPORTED 0A000 \
172
+ SQLITE3 READONLY] \
173
+ "SQLite3's Tcl API does not support read-only\
174
+ access"
175
+ }
176
+ }
177
+ -t - -ti - -tim - -time - -timeo - -timeou - -timeout {
178
+ if {![string is integer $value]} {
179
+ return -code error \
180
+ -errorcode [list TDBC DATA_EXCEPTION 22018 \
181
+ SQLITE3 $value] \
182
+ "expected integer but got \"$value\""
183
+ }
184
+ db timeout $value
185
+ set timeout $value
186
+ }
187
+ default {
188
+ return -code error \
189
+ -errorcode [list TDBC GENERAL_ERROR HY000 \
190
+ SQLITE3 BADOPTION $value] \
191
+ "bad option \"$option\": must be\
192
+ -encoding, -isolation, -readonly or -timeout"
193
+
194
+ }
195
+ }
196
+ }
197
+ return
198
+ }
199
+
200
+ # The 'tables' method introspects on the tables in the database.
201
+
202
+ method tables {{pattern %}} {
203
+ set retval {}
204
+ my foreach row {
205
+ SELECT * from sqlite_master
206
+ WHERE type IN ('table', 'view')
207
+ AND name LIKE :pattern
208
+ } {
209
+ dict set row name [string tolower [dict get $row name]]
210
+ dict set retval [dict get $row name] $row
211
+ }
212
+ return $retval
213
+ }
214
+
215
+ # The 'columns' method introspects on columns of a table.
216
+
217
+ method columns {table {pattern %}} {
218
+ regsub -all ' $table '' table
219
+ set retval {}
220
+ set pattern [string map [list \
221
+ * {[*]} \
222
+ ? {[?]} \
223
+ \[ \\\[ \
224
+ \] \\\[ \
225
+ _ ? \
226
+ % *] [string tolower $pattern]]
227
+ my foreach origrow "PRAGMA table_info('$table')" {
228
+ set row {}
229
+ dict for {key value} $origrow {
230
+ dict set row [string tolower $key] $value
231
+ }
232
+ dict set row name [string tolower [dict get $row name]]
233
+ if {![string match $pattern [dict get $row name]]} {
234
+ continue
235
+ }
236
+ switch -regexp -matchvar info [dict get $row type] {
237
+ {^(.+)\(\s*([[:digit:]]+)\s*,\s*([[:digit:]]+)\s*\)\s*$} {
238
+ dict set row type [string tolower [lindex $info 1]]
239
+ dict set row precision [lindex $info 2]
240
+ dict set row scale [lindex $info 3]
241
+ }
242
+ {^(.+)\(\s*([[:digit:]]+)\s*\)\s*$} {
243
+ dict set row type [string tolower [lindex $info 1]]
244
+ dict set row precision [lindex $info 2]
245
+ dict set row scale 0
246
+ }
247
+ default {
248
+ dict set row type [string tolower [dict get $row type]]
249
+ dict set row precision 0
250
+ dict set row scale 0
251
+ }
252
+ }
253
+ dict set row nullable [expr {![dict get $row notnull]}]
254
+ dict set retval [dict get $row name] $row
255
+ }
256
+ return $retval
257
+ }
258
+
259
+ # The 'primarykeys' method enumerates the primary keys on a table.
260
+
261
+ method primarykeys {table} {
262
+ set result {}
263
+ my foreach row "PRAGMA table_info($table)" {
264
+ if {[dict get $row pk]} {
265
+ lappend result [dict create ordinalPosition \
266
+ [expr {[dict get $row cid]+1}] \
267
+ columnName \
268
+ [dict get $row name]]
269
+ }
270
+ }
271
+ return $result
272
+ }
273
+
274
+ # The 'foreignkeys' method enumerates the foreign keys that are
275
+ # declared in a table or that refer to a given table.
276
+
277
+ method foreignkeys {args} {
278
+
279
+ variable ::tdbc::generalError
280
+
281
+ # Check arguments
282
+
283
+ set argdict {}
284
+ if {[llength $args] % 2 != 0} {
285
+ set errorcode $generalError
286
+ lappend errorcode wrongNumArgs
287
+ return -code error -errorcode $errorcode \
288
+ "wrong # args: should be [lrange [info level 0] 0 1]\
289
+ ?-option value?..."
290
+ }
291
+ foreach {key value} $args {
292
+ if {$key ni {-primary -foreign}} {
293
+ set errorcode $generalError
294
+ lappend errorcode badOption
295
+ return -code error -errorcode $errorcode \
296
+ "bad option \"$key\", must be -primary or -foreign"
297
+ }
298
+ set key [string range $key 1 end]
299
+ if {[dict exists $argdict $key]} {
300
+ set errorcode $generalError
301
+ lappend errorcode dupOption
302
+ return -code error -errorcode $errorcode \
303
+ "duplicate option \"$key\" supplied"
304
+ }
305
+ dict set argdict $key $value
306
+ }
307
+
308
+ # If we know the table with the foreign key, search just its
309
+ # foreign keys. Otherwise, iterate over all the tables in the
310
+ # database.
311
+
312
+ if {[dict exists $argdict foreign]} {
313
+ return [my ForeignKeysForTable [dict get $argdict foreign] \
314
+ $argdict]
315
+ } else {
316
+ set result {}
317
+ foreach foreignTable [dict keys [my tables]] {
318
+ lappend result {*}[my ForeignKeysForTable \
319
+ $foreignTable $argdict]
320
+ }
321
+ return $result
322
+ }
323
+
324
+ }
325
+
326
+ # The private ForeignKeysForTable method enumerates the foreign keys
327
+ # in a specific table.
328
+ #
329
+ # Parameters:
330
+ #
331
+ # foreignTable - Name of the table containing foreign keys.
332
+ # argdict - Dictionary that may or may not contain a key,
333
+ # 'primary', whose value is the name of a table that
334
+ # must hold the primary key corresponding to the foreign
335
+ # key. If the 'primary' key is absent, all tables are
336
+ # candidates.
337
+ # Results:
338
+ #
339
+ # Returns the list of foreign keys that meed the specified
340
+ # conditions, as a list of dictionaries, each containing the
341
+ # keys, foreignConstraintName, foreignTable, foreignColumn,
342
+ # primaryTable, primaryColumn, and ordinalPosition. Note that the
343
+ # foreign constraint name is constructed arbitrarily, since SQLite3
344
+ # does not report this information.
345
+
346
+ method ForeignKeysForTable {foreignTable argdict} {
347
+
348
+ set result {}
349
+ set n 0
350
+
351
+ # Go through the foreign keys in the given table, looking for
352
+ # ones that refer to the primary table (if one is given), or
353
+ # for any primary keys if none is given.
354
+ my foreach row "PRAGMA foreign_key_list($foreignTable)" {
355
+ if {(![dict exists $argdict primary])
356
+ || ([string tolower [dict get $row table]]
357
+ eq [dict get $argdict primary])} {
358
+
359
+ # Construct a dictionary for each key, translating
360
+ # SQLite names to TDBC ones and converting sequence
361
+ # numbers to 1-based indexing.
362
+
363
+ set rrow [dict create foreignTable $foreignTable \
364
+ foreignConstraintName \
365
+ ?$foreignTable?[dict get $row id]]
366
+ if {[dict exists $row seq]} {
367
+ dict set rrow ordinalPosition \
368
+ [expr {1 + [dict get $row seq]}]
369
+ }
370
+ foreach {to from} {
371
+ foreignColumn from
372
+ primaryTable table
373
+ primaryColumn to
374
+ deleteAction on_delete
375
+ updateAction on_update
376
+ } {
377
+ if {[dict exists $row $from]} {
378
+ dict set rrow $to [dict get $row $from]
379
+ }
380
+ }
381
+
382
+ # Add the newly-constucted dictionary to the result list
383
+
384
+ lappend result $rrow
385
+ }
386
+ }
387
+
388
+ return $result
389
+ }
390
+
391
+ # The 'preparecall' method prepares a call to a stored procedure.
392
+ # SQLite3 does not have stored procedures, since it's an in-process
393
+ # server.
394
+
395
+ method preparecall {call} {
396
+ return -code error \
397
+ -errorcode [list TDBC FEATURE_NOT_SUPPORTED 0A000 \
398
+ SQLITE3 PREPARECALL] \
399
+ {SQLite3 does not support stored procedures}
400
+ }
401
+
402
+ # The 'begintransaction' method launches a database transaction
403
+
404
+ method begintransaction {} {
405
+ db eval {BEGIN TRANSACTION}
406
+ }
407
+
408
+ # The 'commit' method commits a database transaction
409
+
410
+ method commit {} {
411
+ db eval {COMMIT}
412
+ }
413
+
414
+ # The 'rollback' method abandons a database transaction
415
+
416
+ method rollback {} {
417
+ db eval {ROLLBACK}
418
+ }
419
+
420
+ # The 'transaction' method executes a script as a single transaction.
421
+ # We override the 'transaction' method of the base class, since SQLite3
422
+ # has a faster implementation of the same thing. (The base class's generic
423
+ # method should also work.)
424
+ # (Don't overload the base class method, because 'break', 'continue'
425
+ # and 'return' in the transaction body don't work!)
426
+
427
+ #method transaction {script} {
428
+ # uplevel 1 [list {*}[namespace code db] transaction $script]
429
+ #}
430
+
431
+ method prepare {sqlCode} {
432
+ set result [next $sqlCode]
433
+ return $result
434
+ }
435
+
436
+ method getDBhandle {} {
437
+ return [namespace which db]
438
+ }
439
+ }
440
+
441
+ #------------------------------------------------------------------------------
442
+ #
443
+ # tdbc::sqlite3::statement --
444
+ #
445
+ # Class representing a statement to execute against a SQLite3 database
446
+ #
447
+ #------------------------------------------------------------------------------
448
+
449
+ ::oo::class create ::tdbc::sqlite3::statement {
450
+
451
+ superclass ::tdbc::statement
452
+
453
+ variable Params db sql
454
+
455
+ # The constructor accepts the handle to the connection and the SQL
456
+ # code for the statement to prepare. All that it does is to parse the
457
+ # statement and store it. The parse is used to support the
458
+ # 'params' and 'paramtype' methods.
459
+
460
+ constructor {connection sqlcode} {
461
+ next
462
+ set Params {}
463
+ set db [$connection getDBhandle]
464
+ set sql $sqlcode
465
+ foreach token [::tdbc::tokenize $sqlcode] {
466
+ if {[string index $token 0] in {$ : @}} {
467
+ dict set Params [string range $token 1 end] \
468
+ {type Tcl_Obj precision 0 scale 0 nullable 1 direction in}
469
+ }
470
+ }
471
+ }
472
+
473
+ # The 'resultSetCreate' method relays to the result set constructor
474
+
475
+ forward resultSetCreate ::tdbc::sqlite3::resultset create
476
+
477
+ # The 'params' method returns descriptions of the parameters accepted
478
+ # by the statement
479
+
480
+ method params {} {
481
+ return $Params
482
+ }
483
+
484
+ # The 'paramtype' method need do nothing; Sqlite3 uses manifest typing.
485
+
486
+ method paramtype args {;}
487
+
488
+ method getDBhandle {} {
489
+ return $db
490
+ }
491
+
492
+ method getSql {} {
493
+ return $sql
494
+ }
495
+
496
+ }
497
+
498
+ #-------------------------------------------------------------------------------
499
+ #
500
+ # tdbc::sqlite3::resultset --
501
+ #
502
+ # Class that represents a SQLlite result set in Tcl
503
+ #
504
+ #-------------------------------------------------------------------------------
505
+
506
+ ::oo::class create ::tdbc::sqlite3::resultset {
507
+
508
+ superclass ::tdbc::resultset
509
+
510
+ # The variables of this class all have peculiar names. The reason is
511
+ # that the RunQuery method needs to execute with an activation record
512
+ # that has no local variables whose names could conflict with names
513
+ # in the SQL query. We start the variable names with hyphens because
514
+ # they can't be bind variables.
515
+
516
+ variable -set {*}{
517
+ -columns -db -needcolumns -resultArray
518
+ -results -sql -Cursor -RowCount -END
519
+ }
520
+
521
+ constructor {statement args} {
522
+ next
523
+ set -db [$statement getDBhandle]
524
+ set -sql [$statement getSql]
525
+ set -columns {}
526
+ set -results {}
527
+ ${-db} trace [namespace code {my RecordStatement}]
528
+ if {[llength $args] == 0} {
529
+
530
+ # Variable substitutions are evaluated in caller's context
531
+
532
+ uplevel 1 [list ${-db} eval ${-sql} \
533
+ [namespace which -variable -resultArray] \
534
+ [namespace code {my RecordResult}]]
535
+
536
+ } elseif {[llength $args] == 1} {
537
+
538
+ # Variable substitutions are in the dictionary at [lindex $args 0].
539
+
540
+ set -paramDict [lindex $args 0]
541
+
542
+ # At this point, the activation record must contain no variables
543
+ # that might be bound within the query. All variables at this point
544
+ # begin with hyphens so that they are syntactically incorrect
545
+ # as bound variables in SQL.
546
+
547
+ unset args
548
+ unset statement
549
+
550
+ dict with -paramDict {
551
+ ${-db} eval ${-sql} -resultArray {
552
+ my RecordResult
553
+ }
554
+ }
555
+
556
+ } else {
557
+
558
+ ${-db} trace {}
559
+
560
+ # Too many args
561
+
562
+ return -code error \
563
+ -errorcode [list TDBC GENERAL_ERROR HY000 \
564
+ SQLITE3 WRONGNUMARGS] \
565
+ "wrong # args: should be\
566
+ [lrange [info level 0] 0 1] statement ?dictionary?"
567
+
568
+ }
569
+ ${-db} trace {}
570
+ set -Cursor 0
571
+ if {${-Cursor} < [llength ${-results}]
572
+ && [lindex ${-results} ${-Cursor}] eq {statement}} {
573
+ incr -Cursor 2
574
+ }
575
+ if {${-Cursor} < [llength ${-results}]
576
+ && [lindex ${-results} ${-Cursor}] eq {columns}} {
577
+ incr -Cursor
578
+ set -columns [lindex ${-results} ${-Cursor}]
579
+ incr -Cursor
580
+ }
581
+ set -RowCount [${-db} changes]
582
+ }
583
+
584
+ # Record the start of a SQL statement
585
+
586
+ method RecordStatement {stmt} {
587
+ set -needcolumns 1
588
+ lappend -results statement {}
589
+ }
590
+
591
+ # Record one row of results from a query by appending it as a dictionary
592
+ # to the 'results' list. As a side effect, set 'columns' to a list
593
+ # comprising the names of the columns of the result.
594
+
595
+ method RecordResult {} {
596
+ set columns ${-resultArray(*)}
597
+ if {[info exists -needcolumns]} {
598
+ lappend -results columns $columns
599
+ unset -needcolumns
600
+ }
601
+ set dict {}
602
+ foreach key $columns {
603
+ if {[set -resultArray($key)] ne "\ufffd"} {
604
+ dict set dict $key [set -resultArray($key)]
605
+ }
606
+ }
607
+ lappend -results row $dict
608
+ }
609
+
610
+ # Advance to the next result set
611
+
612
+ method nextresults {} {
613
+ set have 0
614
+ while {${-Cursor} < [llength ${-results}]} {
615
+ if {[lindex ${-results} ${-Cursor}] eq {statement}} {
616
+ set have 1
617
+ incr -Cursor 2
618
+ break
619
+ }
620
+ incr -Cursor 2
621
+ }
622
+ if {!$have} {
623
+ set -END {}
624
+ }
625
+ if {${-Cursor} >= [llength ${-results}]} {
626
+ set -columns {}
627
+ } elseif {[lindex ${-results} ${-Cursor}] eq {columns}} {
628
+ incr -Cursor
629
+ set -columns [lindex ${-results} ${-Cursor}]
630
+ incr -Cursor
631
+ } else {
632
+ set -columns {}
633
+ }
634
+ return $have
635
+ }
636
+
637
+ method getDBhandle {} {
638
+ return ${-db}
639
+ }
640
+
641
+ # Return a list of the columns
642
+
643
+ method columns {} {
644
+ if {[info exists -END]} {
645
+ return -code error \
646
+ -errorcode {TDBC GENERAL_ERROR HY010 SQLITE3 FUNCTIONSEQ} \
647
+ "Function sequence error: result set is exhausted."
648
+ }
649
+ return ${-columns}
650
+ }
651
+
652
+ # Return the next row of the result set as a list
653
+
654
+ method nextlist var {
655
+
656
+ upvar 1 $var row
657
+
658
+ if {[info exists -END]} {
659
+ return -code error \
660
+ -errorcode {TDBC GENERAL_ERROR HY010 SQLITE3 FUNCTIONSEQ} \
661
+ "Function sequence error: result set is exhausted."
662
+ }
663
+ if {${-Cursor} >= [llength ${-results}]
664
+ || [lindex ${-results} ${-Cursor}] ne {row}} {
665
+ return 0
666
+ } else {
667
+ set row {}
668
+ incr -Cursor
669
+ set d [lindex ${-results} ${-Cursor}]
670
+ incr -Cursor
671
+ foreach key ${-columns} {
672
+ if {[dict exists $d $key]} {
673
+ lappend row [dict get $d $key]
674
+ } else {
675
+ lappend row {}
676
+ }
677
+ }
678
+ }
679
+ return 1
680
+ }
681
+
682
+ # Return the next row of the result set as a dict
683
+
684
+ method nextdict var {
685
+
686
+ upvar 1 $var row
687
+
688
+ if {[info exists -END]} {
689
+ return -code error \
690
+ -errorcode {TDBC GENERAL_ERROR HY010 SQLITE3 FUNCTIONSEQ} \
691
+ "Function sequence error: result set is exhausted."
692
+ }
693
+ if {${-Cursor} >= [llength ${-results}]
694
+ || [lindex ${-results} ${-Cursor}] ne {row}} {
695
+ return 0
696
+ } else {
697
+ incr -Cursor
698
+ set row [lindex ${-results} ${-Cursor}]
699
+ incr -Cursor
700
+ }
701
+ return 1
702
+ }
703
+
704
+ # Return the number of rows affected by a statement
705
+
706
+ method rowcount {} {
707
+ if {[info exists -END]} {
708
+ return -code error \
709
+ -errorcode {TDBC GENERAL_ERROR HY010 SQLITE3 FUNCTIONSEQ} \
710
+ "Function sequence error: result set is exhausted."
711
+ }
712
+ return ${-RowCount}
713
+ }
714
+
715
+ }
my_container_sandbox/workspace/anaconda3/lib/tk8.6/demos/images/earth.gif ADDED
my_container_sandbox/workspace/anaconda3/lib/tk8.6/demos/images/earthmenu.png ADDED
my_container_sandbox/workspace/anaconda3/lib/tk8.6/demos/images/earthris.gif ADDED
my_container_sandbox/workspace/anaconda3/lib/tk8.6/demos/images/flagdown.xbm ADDED
my_container_sandbox/workspace/anaconda3/lib/tk8.6/demos/images/flagup.xbm ADDED
my_container_sandbox/workspace/anaconda3/lib/tk8.6/demos/images/gray25.xbm ADDED
my_container_sandbox/workspace/anaconda3/lib/tk8.6/demos/images/letters.xbm ADDED
my_container_sandbox/workspace/anaconda3/lib/tk8.6/demos/images/noletter.xbm ADDED
my_container_sandbox/workspace/anaconda3/lib/tk8.6/demos/images/ouster.png ADDED
my_container_sandbox/workspace/anaconda3/lib/tk8.6/demos/images/pattern.xbm ADDED
my_container_sandbox/workspace/anaconda3/lib/tk8.6/demos/images/tcllogo.gif ADDED
my_container_sandbox/workspace/anaconda3/lib/tk8.6/images/README ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ README - images directory
2
+
3
+ This directory includes images for the Tcl Logo and the Tcl Powered
4
+ Logo. Please feel free to use the Tcl Powered Logo on any of your
5
+ products that employ the use of Tcl or Tk. The Tcl logo may also be
6
+ used to promote Tcl in your product documentation, web site or other
7
+ places you so desire.
my_container_sandbox/workspace/anaconda3/lib/tk8.6/images/logo.eps ADDED
@@ -0,0 +1,2091 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ %!PS-Adobe-3.0 EPSF-3.0
2
+ %%Creator: Adobe Illustrator(TM) 5.5
3
+ %%For: (Bud Northern) (Mark Anderson Design)
4
+ %%Title: (TCL/TK LOGO.ILLUS)
5
+ %%CreationDate: (8/1/96) (4:58 PM)
6
+ %%BoundingBox: 251 331 371 512
7
+ %%HiResBoundingBox: 251.3386 331.5616 370.5213 511.775
8
+ %%DocumentProcessColors: Cyan Magenta Yellow
9
+ %%DocumentSuppliedResources: procset Adobe_level2_AI5 1.0 0
10
+ %%+ procset Adobe_IllustratorA_AI5 1.0 0
11
+ %AI5_FileFormat 1.2
12
+ %AI3_ColorUsage: Color
13
+ %%DocumentCustomColors: (TCL RED)
14
+ %%CMYKCustomColor: 0 0.45 1 0 (Orange)
15
+ %%+ 0 0.25 1 0 (Orange Yellow)
16
+ %%+ 0 0.79 0.91 0 (TCL RED)
17
+ %AI3_TemplateBox: 306 396 306 396
18
+ %AI3_TileBox: 12 12 600 780
19
+ %AI3_DocumentPreview: Macintosh_ColorPic
20
+ %AI5_ArtSize: 612 792
21
+ %AI5_RulerUnits: 0
22
+ %AI5_ArtFlags: 1 0 0 1 0 0 1 1 0
23
+ %AI5_TargetResolution: 800
24
+ %AI5_NumLayers: 1
25
+ %AI5_OpenToView: 90 576 2 938 673 18 1 1 2 40
26
+ %AI5_OpenViewLayers: 7
27
+ %%EndComments
28
+ %%BeginProlog
29
+ %%BeginResource: procset Adobe_level2_AI5 1.0 0
30
+ %%Title: (Adobe Illustrator (R) Version 5.0 Level 2 Emulation)
31
+ %%Version: 1.0
32
+ %%CreationDate: (04/10/93) ()
33
+ %%Copyright: ((C) 1987-1993 Adobe Systems Incorporated All Rights Reserved)
34
+ userdict /Adobe_level2_AI5 21 dict dup begin
35
+ put
36
+ /packedarray where not
37
+ {
38
+ userdict begin
39
+ /packedarray
40
+ {
41
+ array astore readonly
42
+ } bind def
43
+ /setpacking /pop load def
44
+ /currentpacking false def
45
+ end
46
+ 0
47
+ } if
48
+ pop
49
+ userdict /defaultpacking currentpacking put true setpacking
50
+ /initialize
51
+ {
52
+ Adobe_level2_AI5 begin
53
+ } bind def
54
+ /terminate
55
+ {
56
+ currentdict Adobe_level2_AI5 eq
57
+ {
58
+ end
59
+ } if
60
+ } bind def
61
+ mark
62
+ /setcustomcolor where not
63
+ {
64
+ /findcmykcustomcolor
65
+ {
66
+ 5 packedarray
67
+ } bind def
68
+ /setcustomcolor
69
+ {
70
+ exch aload pop pop
71
+ 4
72
+ {
73
+ 4 index mul 4 1 roll
74
+ } repeat
75
+ 5 -1 roll pop
76
+ setcmykcolor
77
+ }
78
+ def
79
+ } if
80
+
81
+ /gt38? mark {version cvx exec} stopped {cleartomark true} {38 gt exch pop} ifelse def
82
+ userdict /deviceDPI 72 0 matrix defaultmatrix dtransform dup mul exch dup mul add sqrt put
83
+ userdict /level2?
84
+ systemdict /languagelevel known dup
85
+ {
86
+ pop systemdict /languagelevel get 2 ge
87
+ } if
88
+ put
89
+ level2? not
90
+ {
91
+ /setcmykcolor where not
92
+ {
93
+ /setcmykcolor
94
+ {
95
+ exch .11 mul add exch .59 mul add exch .3 mul add
96
+ 1 exch sub setgray
97
+ } def
98
+ } if
99
+ /currentcmykcolor where not
100
+ {
101
+ /currentcmykcolor
102
+ {
103
+ 0 0 0 1 currentgray sub
104
+ } def
105
+ } if
106
+ /setoverprint where not
107
+ {
108
+ /setoverprint /pop load def
109
+ } if
110
+ /selectfont where not
111
+ {
112
+ /selectfont
113
+ {
114
+ exch findfont exch
115
+ dup type /arraytype eq
116
+ {
117
+ makefont
118
+ }
119
+ {
120
+ scalefont
121
+ } ifelse
122
+ setfont
123
+ } bind def
124
+ } if
125
+ /cshow where not
126
+ {
127
+ /cshow
128
+ {
129
+ [
130
+ 0 0 5 -1 roll aload pop
131
+ ] cvx bind forall
132
+ } bind def
133
+ } if
134
+ } if
135
+ cleartomark
136
+ /anyColor?
137
+ {
138
+ add add add 0 ne
139
+ } bind def
140
+ /testColor
141
+ {
142
+ gsave
143
+ setcmykcolor currentcmykcolor
144
+ grestore
145
+ } bind def
146
+ /testCMYKColorThrough
147
+ {
148
+ testColor anyColor?
149
+ } bind def
150
+ userdict /composite?
151
+ level2?
152
+ {
153
+ gsave 1 1 1 1 setcmykcolor currentcmykcolor grestore
154
+ add add add 4 eq
155
+ }
156
+ {
157
+ 1 0 0 0 testCMYKColorThrough
158
+ 0 1 0 0 testCMYKColorThrough
159
+ 0 0 1 0 testCMYKColorThrough
160
+ 0 0 0 1 testCMYKColorThrough
161
+ and and and
162
+ } ifelse
163
+ put
164
+ composite? not
165
+ {
166
+ userdict begin
167
+ gsave
168
+ /cyan? 1 0 0 0 testCMYKColorThrough def
169
+ /magenta? 0 1 0 0 testCMYKColorThrough def
170
+ /yellow? 0 0 1 0 testCMYKColorThrough def
171
+ /black? 0 0 0 1 testCMYKColorThrough def
172
+ grestore
173
+ /isCMYKSep? cyan? magenta? yellow? black? or or or def
174
+ /customColor? isCMYKSep? not def
175
+ end
176
+ } if
177
+ end defaultpacking setpacking
178
+ %%EndResource
179
+ %%BeginResource: procset Adobe_IllustratorA_AI5 1.1 0
180
+ %%Title: (Adobe Illustrator (R) Version 5.0 Abbreviated Prolog)
181
+ %%Version: 1.1
182
+ %%CreationDate: (3/7/1994) ()
183
+ %%Copyright: ((C) 1987-1994 Adobe Systems Incorporated All Rights Reserved)
184
+ currentpacking true setpacking
185
+ userdict /Adobe_IllustratorA_AI5_vars 70 dict dup begin
186
+ put
187
+ /_lp /none def
188
+ /_pf
189
+ {
190
+ } def
191
+ /_ps
192
+ {
193
+ } def
194
+ /_psf
195
+ {
196
+ } def
197
+ /_pss
198
+ {
199
+ } def
200
+ /_pjsf
201
+ {
202
+ } def
203
+ /_pjss
204
+ {
205
+ } def
206
+ /_pola 0 def
207
+ /_doClip 0 def
208
+ /cf currentflat def
209
+ /_tm matrix def
210
+ /_renderStart
211
+ [
212
+ /e0 /r0 /a0 /o0 /e1 /r1 /a1 /i0
213
+ ] def
214
+ /_renderEnd
215
+ [
216
+ null null null null /i1 /i1 /i1 /i1
217
+ ] def
218
+ /_render -1 def
219
+ /_rise 0 def
220
+ /_ax 0 def
221
+ /_ay 0 def
222
+ /_cx 0 def
223
+ /_cy 0 def
224
+ /_leading
225
+ [
226
+ 0 0
227
+ ] def
228
+ /_ctm matrix def
229
+ /_mtx matrix def
230
+ /_sp 16#020 def
231
+ /_hyphen (-) def
232
+ /_fScl 0 def
233
+ /_cnt 0 def
234
+ /_hs 1 def
235
+ /_nativeEncoding 0 def
236
+ /_useNativeEncoding 0 def
237
+ /_tempEncode 0 def
238
+ /_pntr 0 def
239
+ /_tDict 2 dict def
240
+ /_wv 0 def
241
+ /Tx
242
+ {
243
+ } def
244
+ /Tj
245
+ {
246
+ } def
247
+ /CRender
248
+ {
249
+ } def
250
+ /_AI3_savepage
251
+ {
252
+ } def
253
+ /_gf null def
254
+ /_cf 4 array def
255
+ /_if null def
256
+ /_of false def
257
+ /_fc
258
+ {
259
+ } def
260
+ /_gs null def
261
+ /_cs 4 array def
262
+ /_is null def
263
+ /_os false def
264
+ /_sc
265
+ {
266
+ } def
267
+ /discardSave null def
268
+ /buffer 256 string def
269
+ /beginString null def
270
+ /endString null def
271
+ /endStringLength null def
272
+ /layerCnt 1 def
273
+ /layerCount 1 def
274
+ /perCent (%) 0 get def
275
+ /perCentSeen? false def
276
+ /newBuff null def
277
+ /newBuffButFirst null def
278
+ /newBuffLast null def
279
+ /clipForward? false def
280
+ end
281
+ userdict /Adobe_IllustratorA_AI5 74 dict dup begin
282
+ put
283
+ /initialize
284
+ {
285
+ Adobe_IllustratorA_AI5 dup begin
286
+ Adobe_IllustratorA_AI5_vars begin
287
+ discardDict
288
+ {
289
+ bind pop pop
290
+ } forall
291
+ dup /nc get begin
292
+ {
293
+ dup xcheck 1 index type /operatortype ne and
294
+ {
295
+ bind
296
+ } if
297
+ pop pop
298
+ } forall
299
+ end
300
+ newpath
301
+ } def
302
+ /terminate
303
+ {
304
+ end
305
+ end
306
+ } def
307
+ /_
308
+ null def
309
+ /ddef
310
+ {
311
+ Adobe_IllustratorA_AI5_vars 3 1 roll put
312
+ } def
313
+ /xput
314
+ {
315
+ dup load dup length exch maxlength eq
316
+ {
317
+ dup dup load dup
318
+ length 2 mul dict copy def
319
+ } if
320
+ load begin
321
+ def
322
+ end
323
+ } def
324
+ /npop
325
+ {
326
+ {
327
+ pop
328
+ } repeat
329
+ } def
330
+ /sw
331
+ {
332
+ dup length exch stringwidth
333
+ exch 5 -1 roll 3 index mul add
334
+ 4 1 roll 3 1 roll mul add
335
+ } def
336
+ /swj
337
+ {
338
+ dup 4 1 roll
339
+ dup length exch stringwidth
340
+ exch 5 -1 roll 3 index mul add
341
+ 4 1 roll 3 1 roll mul add
342
+ 6 2 roll /_cnt 0 ddef
343
+ {
344
+ 1 index eq
345
+ {
346
+ /_cnt _cnt 1 add ddef
347
+ } if
348
+ } forall
349
+ pop
350
+ exch _cnt mul exch _cnt mul 2 index add 4 1 roll 2 index add 4 1 roll pop pop
351
+ } def
352
+ /ss
353
+ {
354
+ 4 1 roll
355
+ {
356
+ 2 npop
357
+ (0) exch 2 copy 0 exch put pop
358
+ gsave
359
+ false charpath currentpoint
360
+ 4 index setmatrix
361
+ stroke
362
+ grestore
363
+ moveto
364
+ 2 copy rmoveto
365
+ } exch cshow
366
+ 3 npop
367
+ } def
368
+ /jss
369
+ {
370
+ 4 1 roll
371
+ {
372
+ 2 npop
373
+ (0) exch 2 copy 0 exch put
374
+ gsave
375
+ _sp eq
376
+ {
377
+ exch 6 index 6 index 6 index 5 -1 roll widthshow
378
+ currentpoint
379
+ }
380
+ {
381
+ false charpath currentpoint
382
+ 4 index setmatrix stroke
383
+ } ifelse
384
+ grestore
385
+ moveto
386
+ 2 copy rmoveto
387
+ } exch cshow
388
+ 6 npop
389
+ } def
390
+ /sp
391
+ {
392
+ {
393
+ 2 npop (0) exch
394
+ 2 copy 0 exch put pop
395
+ false charpath
396
+ 2 copy rmoveto
397
+ } exch cshow
398
+ 2 npop
399
+ } def
400
+ /jsp
401
+ {
402
+ {
403
+ 2 npop
404
+ (0) exch 2 copy 0 exch put
405
+ _sp eq
406
+ {
407
+ exch 5 index 5 index 5 index 5 -1 roll widthshow
408
+ }
409
+ {
410
+ false charpath
411
+ } ifelse
412
+ 2 copy rmoveto
413
+ } exch cshow
414
+ 5 npop
415
+ } def
416
+ /pl
417
+ {
418
+ transform
419
+ 0.25 sub round 0.25 add exch
420
+ 0.25 sub round 0.25 add exch
421
+ itransform
422
+ } def
423
+ /setstrokeadjust where
424
+ {
425
+ pop true setstrokeadjust
426
+ /c
427
+ {
428
+ curveto
429
+ } def
430
+ /C
431
+ /c load def
432
+ /v
433
+ {
434
+ currentpoint 6 2 roll curveto
435
+ } def
436
+ /V
437
+ /v load def
438
+ /y
439
+ {
440
+ 2 copy curveto
441
+ } def
442
+ /Y
443
+ /y load def
444
+ /l
445
+ {
446
+ lineto
447
+ } def
448
+ /L
449
+ /l load def
450
+ /m
451
+ {
452
+ moveto
453
+ } def
454
+ }
455
+ {
456
+ /c
457
+ {
458
+ pl curveto
459
+ } def
460
+ /C
461
+ /c load def
462
+ /v
463
+ {
464
+ currentpoint 6 2 roll pl curveto
465
+ } def
466
+ /V
467
+ /v load def
468
+ /y
469
+ {
470
+ pl 2 copy curveto
471
+ } def
472
+ /Y
473
+ /y load def
474
+ /l
475
+ {
476
+ pl lineto
477
+ } def
478
+ /L
479
+ /l load def
480
+ /m
481
+ {
482
+ pl moveto
483
+ } def
484
+ } ifelse
485
+ /d
486
+ {
487
+ setdash
488
+ } def
489
+ /cf
490
+ {
491
+ } def
492
+ /i
493
+ {
494
+ dup 0 eq
495
+ {
496
+ pop cf
497
+ } if
498
+ setflat
499
+ } def
500
+ /j
501
+ {
502
+ setlinejoin
503
+ } def
504
+ /J
505
+ {
506
+ setlinecap
507
+ } def
508
+ /M
509
+ {
510
+ setmiterlimit
511
+ } def
512
+ /w
513
+ {
514
+ setlinewidth
515
+ } def
516
+ /H
517
+ {
518
+ } def
519
+ /h
520
+ {
521
+ closepath
522
+ } def
523
+ /N
524
+ {
525
+ _pola 0 eq
526
+ {
527
+ _doClip 1 eq
528
+ {
529
+ clip /_doClip 0 ddef
530
+ } if
531
+ newpath
532
+ }
533
+ {
534
+ /CRender
535
+ {
536
+ N
537
+ } ddef
538
+ } ifelse
539
+ } def
540
+ /n
541
+ {
542
+ N
543
+ } def
544
+ /F
545
+ {
546
+ _pola 0 eq
547
+ {
548
+ _doClip 1 eq
549
+ {
550
+ gsave _pf grestore clip newpath /_lp /none ddef _fc
551
+ /_doClip 0 ddef
552
+ }
553
+ {
554
+ _pf
555
+ } ifelse
556
+ }
557
+ {
558
+ /CRender
559
+ {
560
+ F
561
+ } ddef
562
+ } ifelse
563
+ } def
564
+ /f
565
+ {
566
+ closepath
567
+ F
568
+ } def
569
+ /S
570
+ {
571
+ _pola 0 eq
572
+ {
573
+ _doClip 1 eq
574
+ {
575
+ gsave _ps grestore clip newpath /_lp /none ddef _sc
576
+ /_doClip 0 ddef
577
+ }
578
+ {
579
+ _ps
580
+ } ifelse
581
+ }
582
+ {
583
+ /CRender
584
+ {
585
+ S
586
+ } ddef
587
+ } ifelse
588
+ } def
589
+ /s
590
+ {
591
+ closepath
592
+ S
593
+ } def
594
+ /B
595
+ {
596
+ _pola 0 eq
597
+ {
598
+ _doClip 1 eq
599
+ gsave F grestore
600
+ {
601
+ gsave S grestore clip newpath /_lp /none ddef _sc
602
+ /_doClip 0 ddef
603
+ }
604
+ {
605
+ S
606
+ } ifelse
607
+ }
608
+ {
609
+ /CRender
610
+ {
611
+ B
612
+ } ddef
613
+ } ifelse
614
+ } def
615
+ /b
616
+ {
617
+ closepath
618
+ B
619
+ } def
620
+ /W
621
+ {
622
+ /_doClip 1 ddef
623
+ } def
624
+ /*
625
+ {
626
+ count 0 ne
627
+ {
628
+ dup type /stringtype eq
629
+ {
630
+ pop
631
+ } if
632
+ } if
633
+ newpath
634
+ } def
635
+ /u
636
+ {
637
+ } def
638
+ /U
639
+ {
640
+ } def
641
+ /q
642
+ {
643
+ _pola 0 eq
644
+ {
645
+ gsave
646
+ } if
647
+ } def
648
+ /Q
649
+ {
650
+ _pola 0 eq
651
+ {
652
+ grestore
653
+ } if
654
+ } def
655
+ /*u
656
+ {
657
+ _pola 1 add /_pola exch ddef
658
+ } def
659
+ /*U
660
+ {
661
+ _pola 1 sub /_pola exch ddef
662
+ _pola 0 eq
663
+ {
664
+ CRender
665
+ } if
666
+ } def
667
+ /D
668
+ {
669
+ pop
670
+ } def
671
+ /*w
672
+ {
673
+ } def
674
+ /*W
675
+ {
676
+ } def
677
+ /`
678
+ {
679
+ /_i save ddef
680
+ clipForward?
681
+ {
682
+ nulldevice
683
+ } if
684
+ 6 1 roll 4 npop
685
+ concat pop
686
+ userdict begin
687
+ /showpage
688
+ {
689
+ } def
690
+ 0 setgray
691
+ 0 setlinecap
692
+ 1 setlinewidth
693
+ 0 setlinejoin
694
+ 10 setmiterlimit
695
+ [] 0 setdash
696
+ /setstrokeadjust where {pop false setstrokeadjust} if
697
+ newpath
698
+ 0 setgray
699
+ false setoverprint
700
+ } def
701
+ /~
702
+ {
703
+ end
704
+ _i restore
705
+ } def
706
+ /O
707
+ {
708
+ 0 ne
709
+ /_of exch ddef
710
+ /_lp /none ddef
711
+ } def
712
+ /R
713
+ {
714
+ 0 ne
715
+ /_os exch ddef
716
+ /_lp /none ddef
717
+ } def
718
+ /g
719
+ {
720
+ /_gf exch ddef
721
+ /_fc
722
+ {
723
+ _lp /fill ne
724
+ {
725
+ _of setoverprint
726
+ _gf setgray
727
+ /_lp /fill ddef
728
+ } if
729
+ } ddef
730
+ /_pf
731
+ {
732
+ _fc
733
+ fill
734
+ } ddef
735
+ /_psf
736
+ {
737
+ _fc
738
+ ashow
739
+ } ddef
740
+ /_pjsf
741
+ {
742
+ _fc
743
+ awidthshow
744
+ } ddef
745
+ /_lp /none ddef
746
+ } def
747
+ /G
748
+ {
749
+ /_gs exch ddef
750
+ /_sc
751
+ {
752
+ _lp /stroke ne
753
+ {
754
+ _os setoverprint
755
+ _gs setgray
756
+ /_lp /stroke ddef
757
+ } if
758
+ } ddef
759
+ /_ps
760
+ {
761
+ _sc
762
+ stroke
763
+ } ddef
764
+ /_pss
765
+ {
766
+ _sc
767
+ ss
768
+ } ddef
769
+ /_pjss
770
+ {
771
+ _sc
772
+ jss
773
+ } ddef
774
+ /_lp /none ddef
775
+ } def
776
+ /k
777
+ {
778
+ _cf astore pop
779
+ /_fc
780
+ {
781
+ _lp /fill ne
782
+ {
783
+ _of setoverprint
784
+ _cf aload pop setcmykcolor
785
+ /_lp /fill ddef
786
+ } if
787
+ } ddef
788
+ /_pf
789
+ {
790
+ _fc
791
+ fill
792
+ } ddef
793
+ /_psf
794
+ {
795
+ _fc
796
+ ashow
797
+ } ddef
798
+ /_pjsf
799
+ {
800
+ _fc
801
+ awidthshow
802
+ } ddef
803
+ /_lp /none ddef
804
+ } def
805
+ /K
806
+ {
807
+ _cs astore pop
808
+ /_sc
809
+ {
810
+ _lp /stroke ne
811
+ {
812
+ _os setoverprint
813
+ _cs aload pop setcmykcolor
814
+ /_lp /stroke ddef
815
+ } if
816
+ } ddef
817
+ /_ps
818
+ {
819
+ _sc
820
+ stroke
821
+ } ddef
822
+ /_pss
823
+ {
824
+ _sc
825
+ ss
826
+ } ddef
827
+ /_pjss
828
+ {
829
+ _sc
830
+ jss
831
+ } ddef
832
+ /_lp /none ddef
833
+ } def
834
+ /x
835
+ {
836
+ /_gf exch ddef
837
+ findcmykcustomcolor
838
+ /_if exch ddef
839
+ /_fc
840
+ {
841
+ _lp /fill ne
842
+ {
843
+ _of setoverprint
844
+ _if _gf 1 exch sub setcustomcolor
845
+ /_lp /fill ddef
846
+ } if
847
+ } ddef
848
+ /_pf
849
+ {
850
+ _fc
851
+ fill
852
+ } ddef
853
+ /_psf
854
+ {
855
+ _fc
856
+ ashow
857
+ } ddef
858
+ /_pjsf
859
+ {
860
+ _fc
861
+ awidthshow
862
+ } ddef
863
+ /_lp /none ddef
864
+ } def
865
+ /X
866
+ {
867
+ /_gs exch ddef
868
+ findcmykcustomcolor
869
+ /_is exch ddef
870
+ /_sc
871
+ {
872
+ _lp /stroke ne
873
+ {
874
+ _os setoverprint
875
+ _is _gs 1 exch sub setcustomcolor
876
+ /_lp /stroke ddef
877
+ } if
878
+ } ddef
879
+ /_ps
880
+ {
881
+ _sc
882
+ stroke
883
+ } ddef
884
+ /_pss
885
+ {
886
+ _sc
887
+ ss
888
+ } ddef
889
+ /_pjss
890
+ {
891
+ _sc
892
+ jss
893
+ } ddef
894
+ /_lp /none ddef
895
+ } def
896
+ /A
897
+ {
898
+ pop
899
+ } def
900
+ /annotatepage
901
+ {
902
+ userdict /annotatepage 2 copy known {get exec} {pop pop} ifelse
903
+ } def
904
+ /discard
905
+ {
906
+ save /discardSave exch store
907
+ discardDict begin
908
+ /endString exch store
909
+ gt38?
910
+ {
911
+ 2 add
912
+ } if
913
+ load
914
+ stopped
915
+ pop
916
+ end
917
+ discardSave restore
918
+ } bind def
919
+ userdict /discardDict 7 dict dup begin
920
+ put
921
+ /pre38Initialize
922
+ {
923
+ /endStringLength endString length store
924
+ /newBuff buffer 0 endStringLength getinterval store
925
+ /newBuffButFirst newBuff 1 endStringLength 1 sub getinterval store
926
+ /newBuffLast newBuff endStringLength 1 sub 1 getinterval store
927
+ } def
928
+ /shiftBuffer
929
+ {
930
+ newBuff 0 newBuffButFirst putinterval
931
+ newBuffLast 0
932
+ currentfile read not
933
+ {
934
+ stop
935
+ } if
936
+ put
937
+ } def
938
+ 0
939
+ {
940
+ pre38Initialize
941
+ mark
942
+ currentfile newBuff readstring exch pop
943
+ {
944
+ {
945
+ newBuff endString eq
946
+ {
947
+ cleartomark stop
948
+ } if
949
+ shiftBuffer
950
+ } loop
951
+ }
952
+ {
953
+ stop
954
+ } ifelse
955
+ } def
956
+ 1
957
+ {
958
+ pre38Initialize
959
+ /beginString exch store
960
+ mark
961
+ currentfile newBuff readstring exch pop
962
+ {
963
+ {
964
+ newBuff beginString eq
965
+ {
966
+ /layerCount dup load 1 add store
967
+ }
968
+ {
969
+ newBuff endString eq
970
+ {
971
+ /layerCount dup load 1 sub store
972
+ layerCount 0 eq
973
+ {
974
+ cleartomark stop
975
+ } if
976
+ } if
977
+ } ifelse
978
+ shiftBuffer
979
+ } loop
980
+ }
981
+ {
982
+ stop
983
+ } ifelse
984
+ } def
985
+ 2
986
+ {
987
+ mark
988
+ {
989
+ currentfile buffer readline not
990
+ {
991
+ stop
992
+ } if
993
+ endString eq
994
+ {
995
+ cleartomark stop
996
+ } if
997
+ } loop
998
+ } def
999
+ 3
1000
+ {
1001
+ /beginString exch store
1002
+ /layerCnt 1 store
1003
+ mark
1004
+ {
1005
+ currentfile buffer readline not
1006
+ {
1007
+ stop
1008
+ } if
1009
+ dup beginString eq
1010
+ {
1011
+ pop /layerCnt dup load 1 add store
1012
+ }
1013
+ {
1014
+ endString eq
1015
+ {
1016
+ layerCnt 1 eq
1017
+ {
1018
+ cleartomark stop
1019
+ }
1020
+ {
1021
+ /layerCnt dup load 1 sub store
1022
+ } ifelse
1023
+ } if
1024
+ } ifelse
1025
+ } loop
1026
+ } def
1027
+ end
1028
+ userdict /clipRenderOff 15 dict dup begin
1029
+ put
1030
+ {
1031
+ /n /N /s /S /f /F /b /B
1032
+ }
1033
+ {
1034
+ {
1035
+ _doClip 1 eq
1036
+ {
1037
+ /_doClip 0 ddef clip
1038
+ } if
1039
+ newpath
1040
+ } def
1041
+ } forall
1042
+ /Tr /pop load def
1043
+ /Bb {} def
1044
+ /BB /pop load def
1045
+ /Bg {12 npop} def
1046
+ /Bm {6 npop} def
1047
+ /Bc /Bm load def
1048
+ /Bh {4 npop} def
1049
+ end
1050
+ /Lb
1051
+ {
1052
+ 4 npop
1053
+ 6 1 roll
1054
+ pop
1055
+ 4 1 roll
1056
+ pop pop pop
1057
+ 0 eq
1058
+ {
1059
+ 0 eq
1060
+ {
1061
+ (%AI5_BeginLayer) 1 (%AI5_EndLayer--) discard
1062
+ }
1063
+ {
1064
+ /clipForward? true def
1065
+
1066
+ /Tx /pop load def
1067
+ /Tj /pop load def
1068
+ currentdict end clipRenderOff begin begin
1069
+ } ifelse
1070
+ }
1071
+ {
1072
+ 0 eq
1073
+ {
1074
+ save /discardSave exch store
1075
+ } if
1076
+ } ifelse
1077
+ } bind def
1078
+ /LB
1079
+ {
1080
+ discardSave dup null ne
1081
+ {
1082
+ restore
1083
+ }
1084
+ {
1085
+ pop
1086
+ clipForward?
1087
+ {
1088
+ currentdict
1089
+ end
1090
+ end
1091
+ begin
1092
+
1093
+ /clipForward? false ddef
1094
+ } if
1095
+ } ifelse
1096
+ } bind def
1097
+ /Pb
1098
+ {
1099
+ pop pop
1100
+ 0 (%AI5_EndPalette) discard
1101
+ } bind def
1102
+ /Np
1103
+ {
1104
+ 0 (%AI5_End_NonPrinting--) discard
1105
+ } bind def
1106
+ /Ln /pop load def
1107
+ /Ap
1108
+ /pop load def
1109
+ /Ar
1110
+ {
1111
+ 72 exch div
1112
+ 0 dtransform dup mul exch dup mul add sqrt
1113
+ dup 1 lt
1114
+ {
1115
+ pop 1
1116
+ } if
1117
+ setflat
1118
+ } def
1119
+ /Mb
1120
+ {
1121
+ q
1122
+ } def
1123
+ /Md
1124
+ {
1125
+ } def
1126
+ /MB
1127
+ {
1128
+ Q
1129
+ } def
1130
+ /nc 3 dict def
1131
+ nc begin
1132
+ /setgray
1133
+ {
1134
+ pop
1135
+ } bind def
1136
+ /setcmykcolor
1137
+ {
1138
+ 4 npop
1139
+ } bind def
1140
+ /setcustomcolor
1141
+ {
1142
+ 2 npop
1143
+ } bind def
1144
+ currentdict readonly pop
1145
+ end
1146
+ currentdict readonly pop
1147
+ end
1148
+ setpacking
1149
+ %%EndResource
1150
+ %%EndProlog
1151
+ %%BeginSetup
1152
+ Adobe_level2_AI5 /initialize get exec
1153
+ Adobe_IllustratorA_AI5 /initialize get exec
1154
+ %AI5_Begin_NonPrinting
1155
+ Np
1156
+ %AI3_BeginPattern: (Yellow Stripe)
1157
+ (Yellow Stripe) 8.4499 4.6 80.4499 76.6 [
1158
+ %AI3_Tile
1159
+ (0 O 0 R 0 0.4 1 0 k 0 0.4 1 0 K) @
1160
+ (
1161
+ 800 Ar
1162
+ 0 J 0 j 3.6 w 4 M []0 d
1163
+ %AI3_Note:
1164
+ 0 D
1165
+ 8.1999 8.1999 m
1166
+ 80.6999 8.1999 L
1167
+ S
1168
+ 8.1999 22.6 m
1169
+ 80.6999 22.6 L
1170
+ S
1171
+ 8.1999 37.0001 m
1172
+ 80.6999 37.0001 L
1173
+ S
1174
+ 8.1999 51.3999 m
1175
+ 80.6999 51.3999 L
1176
+ S
1177
+ 8.1999 65.8 m
1178
+ 80.6999 65.8 L
1179
+ S
1180
+ 8.1999 15.3999 m
1181
+ 80.6999 15.3999 L
1182
+ S
1183
+ 8.1999 29.8 m
1184
+ 80.6999 29.8 L
1185
+ S
1186
+ 8.1999 44.1999 m
1187
+ 80.6999 44.1999 L
1188
+ S
1189
+ 8.1999 58.6 m
1190
+ 80.6999 58.6 L
1191
+ S
1192
+ 8.1999 73.0001 m
1193
+ 80.6999 73.0001 L
1194
+ S
1195
+ ) &
1196
+ ] E
1197
+ %AI3_EndPattern
1198
+ %AI5_End_NonPrinting--
1199
+ %AI5_Begin_NonPrinting
1200
+ Np
1201
+ 3 Bn
1202
+ %AI5_BeginGradient: (Black & White)
1203
+ (Black & White) 0 2 Bd
1204
+ [
1205
+ <
1206
+ FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8
1207
+ D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0
1208
+ AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A8988
1209
+ 87868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A69686766656463626160
1210
+ 5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A3938
1211
+ 37363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A19181716151413121110
1212
+ 0F0E0D0C0B0A09080706050403020100
1213
+ >
1214
+ 0 %_Br
1215
+ [
1216
+ 0 0 50 100 %_Bs
1217
+ 1 0 50 0 %_Bs
1218
+ BD
1219
+ %AI5_EndGradient
1220
+ %AI5_BeginGradient: (Red & Yellow)
1221
+ (Red & Yellow) 0 2 Bd
1222
+ [
1223
+ 0
1224
+ <
1225
+ 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627
1226
+ 28292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F
1227
+ 505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F7071727374757677
1228
+ 78797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F
1229
+ A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7
1230
+ C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEF
1231
+ F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF
1232
+ >
1233
+ <
1234
+ FFFFFEFEFDFDFDFCFCFBFBFBFAFAF9F9F9F8F8F7F7F7F6F6F5F5F5F4F4F3F3F3F2F2F1F1F1F0F0EF
1235
+ EFEFEEEEEDEDEDECECEBEBEBEAEAE9E9E9E8E8E7E7E7E6E6E5E5E5E4E4E3E3E3E2E2E1E1E1E0E0DF
1236
+ DFDFDEDEDDDDDDDCDCDBDBDBDADAD9D9D9D8D8D7D7D7D6D6D5D5D5D4D4D3D3D3D2D2D1D1D1D0D0CF
1237
+ CFCFCECECDCDCDCCCCCBCBCBCACAC9C9C9C8C8C7C7C7C6C6C5C5C5C4C4C3C3C3C2C2C1C1C1C0C0BF
1238
+ BFBFBEBEBDBDBDBCBCBBBBBBBABAB9B9B9B8B8B7B7B7B6B6B5B5B5B4B4B3B3B3B2B2B1B1B1B0B0AF
1239
+ AFAFAEAEADADADACACABABABAAAAA9A9A9A8A8A7A7A7A6A6A5A5A5A4A4A3A3A3A2A2A1A1A1A0A09F
1240
+ 9F9F9E9E9D9D9D9C9C9B9B9B9A9A9999
1241
+ >
1242
+ 0
1243
+ 1 %_Br
1244
+ [
1245
+ 0 1 0.6 0 1 50 100 %_Bs
1246
+ 0 0 1 0 1 50 0 %_Bs
1247
+ BD
1248
+ %AI5_EndGradient
1249
+ %AI5_BeginGradient: (Yellow & Blue Radial)
1250
+ (Yellow & Blue Radial) 1 2 Bd
1251
+ [
1252
+ <
1253
+ 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627
1254
+ 28292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F
1255
+ 505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F7071727374757677
1256
+ 78797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F
1257
+ A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7
1258
+ C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEF
1259
+ F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF
1260
+ >
1261
+ <
1262
+ 1415161718191A1B1C1D1E1F1F202122232425262728292A2A2B2C2D2E2F30313233343536363738
1263
+ 393A3B3C3D3E3F40414142434445464748494A4B4C4D4D4E4F50515253545556575858595A5B5C5D
1264
+ 5E5F60616263646465666768696A6B6C6D6E6F6F707172737475767778797A7B7B7C7D7E7F808182
1265
+ 83848586868788898A8B8C8D8E8F90919292939495969798999A9B9C9D9D9E9FA0A1A2A3A4A5A6A7
1266
+ A8A9A9AAABACADAEAFB0B1B2B3B4B4B5B6B7B8B9BABBBCBDBEBFC0C0C1C2C3C4C5C6C7C8C9CACBCB
1267
+ CCCDCECFD0D1D2D3D4D5D6D7D7D8D9DADBDCDDDEDFE0E1E2E2E3E4E5E6E7E8E9EAEBECEDEEEEEFF0
1268
+ F1F2F3F4F5F6F7F8F9F9FAFBFCFDFEFF
1269
+ >
1270
+ <
1271
+ ABAAAAA9A8A7A7A6A5A5A4A3A3A2A1A1A09F9F9E9D9D9C9B9B9A9999989797969595949393929191
1272
+ 908F8F8E8D8D8C8B8B8A8989888787868585848383828181807F7F7E7D7D7C7B7B7A797978777776
1273
+ 7575747373727171706F6F6E6D6D6C6B6B6A6969686767666565646362626160605F5E5E5D5C5C5B
1274
+ 5A5A5958585756565554545352525150504F4E4E4D4C4C4B4A4A4948484746464544444342424140
1275
+ 403F3E3E3D3C3C3B3A3A3938383736363534343332323130302F2E2E2D2C2C2B2A2A292828272626
1276
+ 25242423222121201F1F1E1D1D1C1B1B1A1919181717161515141313121111100F0F0E0D0D0C0B0B
1277
+ 0A090908070706050504030302010100
1278
+ >
1279
+ 0
1280
+ 1 %_Br
1281
+ [
1282
+ 0 0.08 0.67 0 1 50 14 %_Bs
1283
+ 1 1 0 0 1 50 100 %_Bs
1284
+ BD
1285
+ %AI5_EndGradient
1286
+ %AI5_End_NonPrinting--
1287
+ %AI5_BeginPalette
1288
+ 144 170 Pb
1289
+ Pn
1290
+ Pc
1291
+ 1 g
1292
+ Pc
1293
+ 0 g
1294
+ Pc
1295
+ 0 0 0 0 k
1296
+ Pc
1297
+ 0.75 g
1298
+ Pc
1299
+ 0.5 g
1300
+ Pc
1301
+ 0.25 g
1302
+ Pc
1303
+ 0 g
1304
+ Pc
1305
+ Bb
1306
+ 2 (Black & White) -4014 4716 0 0 1 0 0 1 0 0 Bg
1307
+ 0 BB
1308
+ Pc
1309
+ 0.25 0 0 0 k
1310
+ Pc
1311
+ 0.5 0 0 0 k
1312
+ Pc
1313
+ 0.75 0 0 0 k
1314
+ Pc
1315
+ 1 0 0 0 k
1316
+ Pc
1317
+ 0.25 0.25 0 0 k
1318
+ Pc
1319
+ 0.5 0.5 0 0 k
1320
+ Pc
1321
+ 0.75 0.75 0 0 k
1322
+ Pc
1323
+ 1 1 0 0 k
1324
+ Pc
1325
+ Bb
1326
+ 2 (Red & Yellow) -4014 4716 0 0 1 0 0 1 0 0 Bg
1327
+ 0 BB
1328
+ Pc
1329
+ 0 0.25 0 0 k
1330
+ Pc
1331
+ 0 0.5 0 0 k
1332
+ Pc
1333
+ 0 0.75 0 0 k
1334
+ Pc
1335
+ 0 1 0 0 k
1336
+ Pc
1337
+ 0 0.25 0.25 0 k
1338
+ Pc
1339
+ 0 0.5 0.5 0 k
1340
+ Pc
1341
+ 0 0.75 0.75 0 k
1342
+ Pc
1343
+ 0 1 1 0 k
1344
+ Pc
1345
+ Bb
1346
+ 0 0 0 0 Bh
1347
+ 2 (Yellow & Blue Radial) -4014 4716 0 0 1 0 0 1 0 0 Bg
1348
+ 0 BB
1349
+ Pc
1350
+ 0 0 0.25 0 k
1351
+ Pc
1352
+ 0 0 0.5 0 k
1353
+ Pc
1354
+ 0 0 0.75 0 k
1355
+ Pc
1356
+ 0 0 1 0 k
1357
+ Pc
1358
+ 0.25 0 0.25 0 k
1359
+ Pc
1360
+ 0.5 0 0.5 0 k
1361
+ Pc
1362
+ 0.75 0 0.75 0 k
1363
+ Pc
1364
+ 1 0 1 0 k
1365
+ Pc
1366
+ (Yellow Stripe) 0 0 1 1 0 0 0 0 0 [1 0 0 1 0 0] p
1367
+ Pc
1368
+ 0.25 0.125 0 0 k
1369
+ Pc
1370
+ 0.5 0.25 0 0 k
1371
+ Pc
1372
+ 0.75 0.375 0 0 k
1373
+ Pc
1374
+ 1 0.5 0 0 k
1375
+ Pc
1376
+ 0.125 0.25 0 0 k
1377
+ Pc
1378
+ 0.25 0.5 0 0 k
1379
+ Pc
1380
+ 0.375 0.75 0 0 k
1381
+ Pc
1382
+ 0.5 1 0 0 k
1383
+ Pc
1384
+ 0.375 0.375 0.75 0 k
1385
+ Pc
1386
+ 0 0.25 0.125 0 k
1387
+ Pc
1388
+ 0 0.5 0.25 0 k
1389
+ Pc
1390
+ 0 0.75 0.375 0 k
1391
+ Pc
1392
+ 0 1 0.5 0 k
1393
+ Pc
1394
+ 0 0.125 0.25 0 k
1395
+ Pc
1396
+ 0 0.25 0.5 0 k
1397
+ Pc
1398
+ 0 0.375 0.75 0 k
1399
+ Pc
1400
+ 0 0.5 1 0 k
1401
+ Pc
1402
+ 0 0.79 0.91 0 (TCL RED) 0 x
1403
+ Pc
1404
+ 0.125 0 0.25 0 k
1405
+ Pc
1406
+ 0.25 0 0.5 0 k
1407
+ Pc
1408
+ 0.375 0 0.75 0 k
1409
+ Pc
1410
+ 0.5 0 1 0 k
1411
+ Pc
1412
+ 0.25 0 0.125 0 k
1413
+ Pc
1414
+ 0.5 0 0.25 0 k
1415
+ Pc
1416
+ 0.75 0 0.375 0 k
1417
+ Pc
1418
+ 1 0 0.5 0 k
1419
+ Pc
1420
+ 0.5 1 0 0 k
1421
+ Pc
1422
+ 0.25 0.125 0.125 0 k
1423
+ Pc
1424
+ 0.5 0.25 0.25 0 k
1425
+ Pc
1426
+ 0.75 0.375 0.375 0 k
1427
+ Pc
1428
+ 1 0.5 0.5 0 k
1429
+ Pc
1430
+ 0.25 0.25 0.125 0 k
1431
+ Pc
1432
+ 0.5 0.5 0.25 0 k
1433
+ Pc
1434
+ 0.75 0.75 0.375 0 k
1435
+ Pc
1436
+ 1 1 0.5 0 k
1437
+ Pc
1438
+ 0 1 0.5 0 k
1439
+ Pc
1440
+ 0.125 0.25 0.125 0 k
1441
+ Pc
1442
+ 0.25 0.5 0.25 0 k
1443
+ Pc
1444
+ 0.375 0.75 0.375 0 k
1445
+ Pc
1446
+ 0.5 1 0.5 0 k
1447
+ Pc
1448
+ 0.125 0.25 0.25 0 k
1449
+ Pc
1450
+ 0.25 0.5 0.5 0 k
1451
+ Pc
1452
+ 0.375 0.75 0.75 0 k
1453
+ Pc
1454
+ 0.5 1 1 0 k
1455
+ Pc
1456
+ 0.75 0.75 0.375 0 k
1457
+ Pc
1458
+ 0.125 0.125 0.25 0 k
1459
+ Pc
1460
+ 0.25 0.25 0.5 0 k
1461
+ Pc
1462
+ 0.375 0.375 0.75 0 k
1463
+ Pc
1464
+ 0.5 0.5 1 0 k
1465
+ Pc
1466
+ 0.25 0.125 0.25 0 k
1467
+ Pc
1468
+ 0.5 0.25 0.5 0 k
1469
+ Pc
1470
+ 0.75 0.375 0.75 0 k
1471
+ Pc
1472
+ 1 0.5 1 0 k
1473
+ Pc
1474
+ 0 0.79 0.91 0 (TCL RED) 0 x
1475
+ Pc
1476
+ 0 0 0 0 k
1477
+ Pc
1478
+ Pc
1479
+ Pc
1480
+ Pc
1481
+ Pc
1482
+ Pc
1483
+ Pc
1484
+ Pc
1485
+ 1 0.5 0.5 0 k
1486
+ Pc
1487
+ 0 0 0 0 k
1488
+ Pc
1489
+ Pc
1490
+ Pc
1491
+ Pc
1492
+ Pc
1493
+ Pc
1494
+ Pc
1495
+ Pc
1496
+ 0 0.25 1 0 (Orange Yellow) 0 x
1497
+ Pc
1498
+ 0 0 0 0 k
1499
+ Pc
1500
+ Pc
1501
+ Pc
1502
+ Pc
1503
+ Pc
1504
+ Pc
1505
+ Pc
1506
+ Pc
1507
+ 0 1 0.5 0 k
1508
+ Pc
1509
+ 0 0 0 0 k
1510
+ Pc
1511
+ Pc
1512
+ Pc
1513
+ Pc
1514
+ Pc
1515
+ Pc
1516
+ Pc
1517
+ Pc
1518
+ 1 0 0.5 0 k
1519
+ Pc
1520
+ 0 0 0 0 k
1521
+ Pc
1522
+ Pc
1523
+ Pc
1524
+ Pc
1525
+ Pc
1526
+ Pc
1527
+ Pc
1528
+ Pc
1529
+ 0 0.45 1 0 (Orange) 0 x
1530
+ Pc
1531
+ 0 0 0 0 k
1532
+ Pc
1533
+ Pc
1534
+ Pc
1535
+ Pc
1536
+ Pc
1537
+ Pc
1538
+ Pc
1539
+ Pc
1540
+ 0.375 0.375 0.75 0 k
1541
+ Pc
1542
+ 0 0 0 0 k
1543
+ Pc
1544
+ Pc
1545
+ Pc
1546
+ Pc
1547
+ Pc
1548
+ Pc
1549
+ Pc
1550
+ Pc
1551
+ 0 0.79 0.91 0 (TCL RED) 0 x
1552
+ Pc
1553
+ 0 0 0 0 k
1554
+ Pc
1555
+ Pc
1556
+ Pc
1557
+ Pc
1558
+ Pc
1559
+ Pc
1560
+ Pc
1561
+ Pc
1562
+ 1 0.65 0 0 k
1563
+ Pc
1564
+ 0 0 0 0 k
1565
+ Pc
1566
+ Pc
1567
+ Pc
1568
+ Pc
1569
+ Pc
1570
+ Pc
1571
+ Pc
1572
+ Pc
1573
+ 0 0 1 0 k
1574
+ Pc
1575
+ PB
1576
+ %AI5_EndPalette
1577
+ %%EndSetup
1578
+ %AI5_BeginLayer
1579
+ 1 1 1 1 0 0 0 79 128 255 Lb
1580
+ (Layer 1) Ln
1581
+ 0 A
1582
+ u
1583
+ 1 Ap
1584
+ 0 O
1585
+ 0 0.79 0.91 0 (TCL RED) 0 x
1586
+ 800 Ar
1587
+ 0 J 0 j 1.25 w 4 M []0 d
1588
+ %AI3_Note:
1589
+ 0 D
1590
+ 294.5207 335.3041 m
1591
+ 368.2181 333.001 L
1592
+ 363.6121 423.9713 L
1593
+ 370.5213 507.1689 L
1594
+ 336.5513 505.4417 L
1595
+ 320.7179 511.775 L
1596
+ 251.3386 508.0325 L
1597
+ 254.7931 425.9866 L
1598
+ 251.3386 331.5616 L
1599
+ 294.5207 335.3041 L
1600
+ f
1601
+ u
1602
+ 0 Ap
1603
+ 1 0.65 0 0 k
1604
+ 1 w
1605
+ 318.1366 400.9627 m
1606
+ 311.8663 399.2526 l
1607
+ 315.2864 407.5177 l
1608
+ 318.7064 430.6032 l
1609
+ 314.4314 431.4581 l
1610
+ 319.5616 438.5832 l
1611
+ 325.9526 462.6014 l
1612
+ 314.7164 460.2436 l
1613
+ 320.6412 471.0911 326.9284 478.1557 v
1614
+ 318.7064 484.469 l
1615
+ 292.2183 472.8011 299.3434 434.8954 v
1616
+ 293.8679 435.8542 l
1617
+ 299.1189 396.1175 l
1618
+ 294.6797 394.9775 l
1619
+ 299.2277 385.6974 305.5963 381.2973 v
1620
+ 306.1744 380.8979 297.6162 412.3629 306.7363 443.7133 c
1621
+ 307.5914 441.7183 l
1622
+ 300.3238 408.3015 307.5914 381.2973 v
1623
+ 307.9261 380.656 311.5598 381.0836 v
1624
+ 318.1366 393.4813 318.1366 400.9627 v
1625
+ f
1626
+ u
1627
+ *u
1628
+ 1 g
1629
+ 271.4311 372.5074 m
1630
+ 272.7184 372.5074 L
1631
+ 272.7184 375.1913 L
1632
+ 273.2858 375.1913 273.8313 375.1913 274.3768 375.2786 c
1633
+ 274.3768 372.5074 L
1634
+ 276.2969 372.5074 L
1635
+ 276.2969 372.0056 L
1636
+ 274.3768 372.0056 L
1637
+ 274.3768 365.3286 L
1638
+ 274.3768 364.9359 274.3768 364.3467 275.2059 364.3467 c
1639
+ 275.7733 364.3467 276.0787 364.7395 276.4279 365.1541 c
1640
+ 276.777 364.9141 L
1641
+ 276.3624 364.0849 275.2932 363.583 274.4204 363.583 c
1642
+ 272.8494 363.583 272.6748 364.434 272.6748 365.4814 c
1643
+ 272.6748 372.0056 L
1644
+ 271.4311 372.0056 L
1645
+ 271.4311 372.5074 l
1646
+ f
1647
+ *U
1648
+ *u
1649
+ 290.5617 366.5724 m
1650
+ 290.0598 365.0232 289.187 363.6703 286.9178 363.583 c
1651
+ 283.5356 363.583 282.5101 366.3978 282.5101 367.9034 c
1652
+ 282.5101 371.7874 285.6304 372.7256 286.8741 372.7256 c
1653
+ 288.2924 372.7256 290.2999 372.071 290.2999 370.3909 c
1654
+ 290.2999 369.8018 289.9289 369.2344 289.318 369.2344 c
1655
+ 288.7288 369.2344 288.2924 369.6272 288.2924 370.26 c
1656
+ 288.2924 371.111 288.9907 371.2201 288.9907 371.4601 c
1657
+ 288.9907 372.0492 287.616 372.2892 287.136 372.2892 c
1658
+ 285.0412 372.2892 284.4957 370.7618 284.4957 367.9034 c
1659
+ 284.4957 366.5942 284.823 365.5905 284.9539 365.285 c
1660
+ 285.2812 364.5649 285.9577 364.1067 287.0923 364.0413 c
1661
+ 288.3579 363.9758 289.5798 365.0013 290.1035 366.5724 C
1662
+ 290.5617 366.5724 l
1663
+ f
1664
+ *U
1665
+ *u
1666
+ 296.6 363.8667 m
1667
+ 296.6 364.3686 L
1668
+ 298.2802 364.3686 L
1669
+ 298.2802 378.3989 L
1670
+ 296.6 378.3989 L
1671
+ 296.6 378.9007 L
1672
+ 297.5383 378.9007 L
1673
+ 298.3457 378.9007 299.1966 378.9444 299.9822 379.0971 c
1674
+ 299.9822 364.3686 L
1675
+ 301.6623 364.3686 L
1676
+ 301.6623 363.8667 L
1677
+ 296.6 363.8667 l
1678
+ f
1679
+ *U
1680
+ *u
1681
+ 317.4527 372.5074 m
1682
+ 318.7401 372.5074 L
1683
+ 318.7401 375.1913 L
1684
+ 319.3074 375.1913 319.8529 375.1913 320.3984 375.2786 c
1685
+ 320.3984 372.5074 L
1686
+ 322.3186 372.5074 L
1687
+ 322.3186 372.0056 L
1688
+ 320.3984 372.0056 L
1689
+ 320.3984 365.3286 L
1690
+ 320.3984 364.9359 320.3984 364.3467 321.2276 364.3467 c
1691
+ 321.7949 364.3467 322.1004 364.7395 322.4495 365.1541 c
1692
+ 322.7986 364.9141 L
1693
+ 322.384 364.0849 321.3148 363.583 320.442 363.583 c
1694
+ 318.871 363.583 318.6964 364.434 318.6964 365.4814 c
1695
+ 318.6964 372.0056 L
1696
+ 317.4527 372.0056 L
1697
+ 317.4527 372.5074 l
1698
+ f
1699
+ *U
1700
+ *u
1701
+ 333.7467 372.0056 m
1702
+ 333.7467 372.5074 L
1703
+ 337.3252 372.5074 L
1704
+ 337.3252 372.0056 L
1705
+ 335.9942 372.0056 L
1706
+ 332.983 369.3872 L
1707
+ 337.1288 364.3686 L
1708
+ 338.0453 364.3686 L
1709
+ 338.0453 363.8667 L
1710
+ 333.8995 363.8667 L
1711
+ 333.8995 364.3686 L
1712
+ 334.9905 364.3686 L
1713
+ 331.3465 368.798 L
1714
+ 335.0341 371.9401 L
1715
+ 335.0341 372.0056 L
1716
+ 333.7467 372.0056 l
1717
+ f
1718
+ 328.4881 363.8667 m
1719
+ 328.4881 364.3686 L
1720
+ 329.6227 364.3686 L
1721
+ 329.6227 378.3989 L
1722
+ 328.4881 378.3989 L
1723
+ 328.4881 378.9007 L
1724
+ 328.8809 378.9007 L
1725
+ 329.6882 378.9007 330.5392 378.9444 331.3247 379.0971 c
1726
+ 331.3247 364.3686 L
1727
+ 332.6339 364.3686 L
1728
+ 332.6339 363.8667 L
1729
+ 328.4881 363.8667 l
1730
+ f
1731
+ *U
1732
+ u
1733
+ 309.5341 446.5364 m
1734
+ 305.6878 429.3874 306.7947 401.5837 v
1735
+ 307.1266 393.2441 308.0387 385.5779 309.1527 378.9301 C
1736
+ 309.1587 378.9297 L
1737
+ 309.8832 373.0923 310.3679 370.9791 312.2568 363.9454 C
1738
+ 312.1466 359.4091 L
1739
+ 297.0216 407.7015 309.5341 446.5364 V
1740
+ f
1741
+ 318.8187 461.4058 m
1742
+ 322.2203 463.1 327.0966 463.7165 v
1743
+ 332.427 453.9463 319.3087 437.2655 v
1744
+ 327.1346 454.735 325.2889 460.2079 v
1745
+ 323.225 461.4903 318.8187 461.4058 v
1746
+ f
1747
+ 317.2065 432.0795 m
1748
+ 320.2613 431.3723 321.7279 432.5601 v
1749
+ 318.8383 421.2839 319.5958 415.0813 v
1750
+ 320.3533 408.8787 314.8881 404.9079 y
1751
+ 319.5435 410.7982 318.0802 415.5959 v
1752
+ 317.0657 418.9214 318.2006 427.4326 319.4809 430.1349 c
1753
+ 318.2853 430.3025 317.2065 432.0795 v
1754
+ f
1755
+ 314.1861 402.3703 m
1756
+ 319.2343 402.9744 319.7646 405.5244 v
1757
+ 320.3824 390.2725 313.3689 383.9873 v
1758
+ 318.7204 392.3347 317.8807 400.9697 v
1759
+ 314.1861 402.3703 l
1760
+ f
1761
+ 299.9864 396.0219 m
1762
+ 298.3586 394.1986 293.4739 398.2203 v
1763
+ 295.0301 387.9694 304.6978 383.2767 v
1764
+ 298.0444 388.2897 296.2519 393.7045 v
1765
+ 298.6029 394.3966 299.9864 396.0219 v
1766
+ f
1767
+ 298.4281 399.9096 m
1768
+ 291.8229 416.6749 293.2382 439.3286 v
1769
+ 294.7808 435.2261 299.738 433.7875 v
1770
+ 297.4026 433.3101 296.0372 433.517 v
1771
+ 292.5816 423.9535 298.4281 399.9096 v
1772
+ f
1773
+ 326.1736 477.812 m
1774
+ 323.6983 496.0028 308.2122 477.6066 v
1775
+ 295.8813 462.9582 297.3508 450.5217 298.1072 443.5831 c
1776
+ 298.3007 441.8079 295.8131 462.1138 309.3231 475.4768 c
1777
+ 322.8328 488.8398 325.8846 478.5879 326.1736 477.812 c
1778
+ f
1779
+ U
1780
+ 0 0 1 0 k
1781
+ 303.3623 493.3274 m
1782
+ 291.211 496.7978 287.3437 456.5222 v
1783
+ 284.3599 468.9535 292.0777 486.5353 v
1784
+ 299.7955 504.1172 303.3623 493.3274 y
1785
+ f
1786
+ 288.2873 496.2718 m
1787
+ 282.0897 486.9502 283.4958 477.0213 v
1788
+ 278.7953 495.712 288.2873 496.2718 v
1789
+ f
1790
+ 333.8987 470.1328 m
1791
+ 341.2276 472.8361 330.7334 445.5571 v
1792
+ 336.1654 453.5292 339.5844 466.0531 v
1793
+ 341.7789 474.0903 333.8987 470.1328 y
1794
+ f
1795
+ 345.752 472.2583 m
1796
+ 350.9334 467.5681 347.2615 461.3636 v
1797
+ 356.4779 471.0481 345.752 472.2583 v
1798
+ f
1799
+ U
1800
+ *u
1801
+ 273.1765 354.3318 m
1802
+ 273.1765 353.7507 273.1305 353.2908 272.5159 353.2908 c
1803
+ 271.8846 353.2908 271.8554 353.7674 271.8554 354.3318 c
1804
+ 271.8554 356.485 L
1805
+ 272.148 356.485 L
1806
+ 272.148 354.3486 L
1807
+ 272.148 353.8259 272.1773 353.5751 272.5159 353.5751 c
1808
+ 272.8504 353.5751 272.8839 353.8259 272.8839 354.3486 c
1809
+ 272.8839 356.485 L
1810
+ 273.1765 356.485 L
1811
+ 273.1765 354.3318 l
1812
+ f
1813
+ *U
1814
+ *u
1815
+ 277.1612 356.485 m
1816
+ 276.9062 356.485 L
1817
+ 276.9062 354.3862 l
1818
+ 276.9062 354.2482 276.9271 354.1061 276.9355 353.9681 C
1819
+ 276.9229 353.9681 l
1820
+ 276.8937 354.0768 276.8644 354.1855 276.8268 354.2942 C
1821
+ 276.1035 356.485 L
1822
+ 275.8484 356.485 L
1823
+ 275.8484 353.3326 L
1824
+ 276.1035 353.3326 L
1825
+ 276.1035 355.2474 l
1826
+ 276.1035 355.4523 276.0826 355.653 276.07 355.8579 C
1827
+ 276.0867 355.8579 l
1828
+ 276.1244 355.7241 276.1495 355.5819 276.1954 355.4523 C
1829
+ 276.9062 353.3326 L
1830
+ 277.1612 353.3326 l
1831
+ 277.1612 356.485 L
1832
+ f
1833
+ *U
1834
+ *u
1835
+ 280.1421 353.3326 m
1836
+ 279.8494 353.3326 L
1837
+ 279.8494 356.485 L
1838
+ 280.1421 356.485 L
1839
+ 280.1421 353.3326 l
1840
+ f
1841
+ *U
1842
+ *u
1843
+ 283.5141 353.3326 m
1844
+ 283.2549 353.3326 L
1845
+ 282.6194 356.485 L
1846
+ 282.9205 356.485 L
1847
+ 283.3344 354.1897 L
1848
+ 283.3511 354.1102 283.3678 353.9054 283.3845 353.7632 c
1849
+ 283.4013 353.7632 L
1850
+ 283.4138 353.9054 283.4305 354.1144 283.4431 354.1897 c
1851
+ 283.8528 356.485 L
1852
+ 284.1496 356.485 L
1853
+ 283.5141 353.3326 l
1854
+ f
1855
+ *U
1856
+ *u
1857
+ 287.6238 356.2174 m
1858
+ 286.9256 356.2174 L
1859
+ 286.9256 355.1053 L
1860
+ 287.6029 355.1053 L
1861
+ 287.6029 354.8377 L
1862
+ 286.9256 354.8377 L
1863
+ 286.9256 353.6002 L
1864
+ 287.6238 353.6002 L
1865
+ 287.6238 353.3326 L
1866
+ 286.6329 353.3326 L
1867
+ 286.6329 356.485 L
1868
+ 287.6238 356.485 L
1869
+ 287.6238 356.2174 l
1870
+ f
1871
+ *U
1872
+ *u
1873
+ 290.2278 353.3326 m
1874
+ 290.2278 356.485 L
1875
+ 290.5414 356.485 L
1876
+ 290.9804 356.485 291.4026 356.4515 291.4026 355.6823 c
1877
+ 291.4026 355.2809 291.3148 354.8879 290.8089 354.8712 c
1878
+ 291.5072 353.3326 L
1879
+ 291.1978 353.3326 L
1880
+ 290.5288 354.8753 L
1881
+ 290.5205 354.8753 L
1882
+ 290.5205 353.3326 L
1883
+ 290.2278 353.3326 l
1884
+ f
1885
+ 290.5205 355.1137 m
1886
+ 290.625 355.1137 L
1887
+ 291.0347 355.1137 291.1016 355.2558 291.1016 355.6697 c
1888
+ 291.1016 356.1672 290.9511 356.2174 290.579 356.2174 c
1889
+ 290.5205 356.2174 L
1890
+ 290.5205 355.1137 l
1891
+ f
1892
+ *U
1893
+ *u
1894
+ 295.0981 355.9875 m
1895
+ 294.9727 356.1296 294.8347 356.2425 294.634 356.2425 c
1896
+ 294.3414 356.2425 294.1783 356 294.1783 355.7324 c
1897
+ 294.1783 355.3645 294.4459 355.1931 294.7176 355.0091 c
1898
+ 294.9852 354.821 295.2528 354.6203 295.2528 354.1855 c
1899
+ 295.2528 353.7256 294.9559 353.2908 294.4626 353.2908 c
1900
+ 294.287 353.2908 294.1072 353.341 293.9651 353.4497 c
1901
+ 293.9651 353.8301 L
1902
+ 294.0989 353.688 294.2745 353.5751 294.4751 353.5751 c
1903
+ 294.7845 353.5751 294.9559 353.8468 294.9518 354.1311 c
1904
+ 294.9559 354.4991 294.6842 354.6621 294.4166 354.8503 c
1905
+ 294.149 355.0342 293.8773 355.2391 293.8773 355.6906 c
1906
+ 293.8773 356.1129 294.1365 356.5268 294.6006 356.5268 c
1907
+ 294.7887 356.5268 294.9476 356.4641 295.0981 356.3596 C
1908
+ 295.0981 355.9875 l
1909
+ f
1910
+ *U
1911
+ *u
1912
+ 299.0865 353.3326 m
1913
+ 298.773 353.3326 L
1914
+ 298.6559 353.9806 L
1915
+ 297.9869 353.9806 L
1916
+ 297.8741 353.3326 L
1917
+ 297.5605 353.3326 L
1918
+ 298.1793 356.485 L
1919
+ 298.4552 356.485 L
1920
+ 299.0865 353.3326 l
1921
+ f
1922
+ 298.6099 354.2357 m
1923
+ 298.4009 355.444 L
1924
+ 298.3632 355.6572 298.3465 355.8746 298.3214 356.0878 c
1925
+ 298.3047 356.0878 L
1926
+ 298.2754 355.8746 298.2545 355.6572 298.2211 355.444 c
1927
+ 298.0371 354.2357 L
1928
+ 298.6099 354.2357 l
1929
+ f
1930
+ *U
1931
+ *u
1932
+ 301.8124 353.6002 m
1933
+ 302.4981 353.6002 L
1934
+ 302.4981 353.3326 L
1935
+ 301.5198 353.3326 L
1936
+ 301.5198 356.485 L
1937
+ 301.8124 356.485 L
1938
+ 301.8124 353.6002 l
1939
+ f
1940
+ *U
1941
+ *u
1942
+ 309.0754 355.9875 m
1943
+ 308.95 356.1296 308.812 356.2425 308.6114 356.2425 c
1944
+ 308.3187 356.2425 308.1556 356 308.1556 355.7324 c
1945
+ 308.1556 355.3645 308.4232 355.1931 308.695 355.0091 c
1946
+ 308.9626 354.821 309.2301 354.6203 309.2301 354.1855 c
1947
+ 309.2301 353.7256 308.9333 353.2908 308.4399 353.2908 c
1948
+ 308.2643 353.2908 308.0846 353.341 307.9424 353.4497 c
1949
+ 307.9424 353.8301 L
1950
+ 308.0762 353.688 308.2518 353.5751 308.4525 353.5751 c
1951
+ 308.7619 353.5751 308.9333 353.8468 308.9291 354.1311 c
1952
+ 308.9333 354.4991 308.6615 354.6621 308.3939 354.8503 c
1953
+ 308.1264 355.0342 307.8546 355.2391 307.8546 355.6906 c
1954
+ 307.8546 356.1129 308.1138 356.5268 308.5779 356.5268 c
1955
+ 308.766 356.5268 308.9249 356.4641 309.0754 356.3596 C
1956
+ 309.0754 355.9875 l
1957
+ f
1958
+ *U
1959
+ *u
1960
+ 312.9468 353.7172 m
1961
+ 312.8339 353.6378 312.7001 353.5751 312.558 353.5751 c
1962
+ 311.9977 353.5751 311.9977 354.5492 311.9977 354.9172 c
1963
+ 311.9977 355.5025 312.0688 356.2425 312.5789 356.2425 c
1964
+ 312.7252 356.2425 312.8297 356.184 312.9468 356.1045 C
1965
+ 312.9468 356.4265 l
1966
+ 312.8506 356.4975 312.6918 356.5268 312.5747 356.5268 c
1967
+ 311.7134 356.5268 311.6967 355.306 311.6967 354.7959 c
1968
+ 311.6967 354.2566 311.8054 353.2908 312.5454 353.2908 c
1969
+ 312.6834 353.2908 312.8381 353.3451 312.9468 353.4204 c
1970
+ 312.9468 353.7172 L
1971
+ f
1972
+ *U
1973
+ *u
1974
+ 315.5053 353.3326 m
1975
+ 315.5053 356.485 L
1976
+ 315.8188 356.485 L
1977
+ 316.2578 356.485 316.6801 356.4515 316.6801 355.6823 c
1978
+ 316.6801 355.2809 316.5923 354.8879 316.0864 354.8712 c
1979
+ 316.7846 353.3326 L
1980
+ 316.4752 353.3326 L
1981
+ 315.8063 354.8753 L
1982
+ 315.7979 354.8753 L
1983
+ 315.7979 353.3326 L
1984
+ 315.5053 353.3326 l
1985
+ f
1986
+ 315.7979 355.1137 m
1987
+ 315.9025 355.1137 L
1988
+ 316.3122 355.1137 316.3791 355.2558 316.3791 355.6697 c
1989
+ 316.3791 356.1672 316.2286 356.2174 315.8565 356.2174 c
1990
+ 315.7979 356.2174 L
1991
+ 315.7979 355.1137 l
1992
+ f
1993
+ *U
1994
+ *u
1995
+ 319.5728 353.3326 m
1996
+ 319.2802 353.3326 L
1997
+ 319.2802 356.485 L
1998
+ 319.5728 356.485 L
1999
+ 319.5728 353.3326 l
2000
+ f
2001
+ *U
2002
+ *u
2003
+ 322.2551 353.3326 m
2004
+ 322.2551 356.485 L
2005
+ 322.5812 356.485 L
2006
+ 323.0327 356.485 323.4341 356.4432 323.4341 355.6655 c
2007
+ 323.4341 355.0551 323.2209 354.8419 322.623 354.8419 c
2008
+ 322.5477 354.8419 L
2009
+ 322.5477 353.3326 L
2010
+ 322.2551 353.3326 l
2011
+ f
2012
+ 322.5477 355.1095 m
2013
+ 322.6606 355.1095 L
2014
+ 323.0703 355.1095 323.1205 355.26 323.1331 355.6655 c
2015
+ 323.1331 356.1004 323.016 356.2174 322.6063 356.2174 c
2016
+ 322.5477 356.2174 L
2017
+ 322.5477 355.1095 l
2018
+ f
2019
+ *U
2020
+ *u
2021
+ 326.9539 356.485 m
2022
+ 325.7164 356.485 L
2023
+ 325.7164 356.2174 L
2024
+ 326.1888 356.2174 L
2025
+ 326.1888 353.3326 L
2026
+ 326.4815 353.3326 L
2027
+ 326.4815 356.2174 L
2028
+ 326.9539 356.2174 l
2029
+ 326.9539 356.485 L
2030
+ f
2031
+ *U
2032
+ *u
2033
+ 329.7077 353.3326 m
2034
+ 329.4151 353.3326 L
2035
+ 329.4151 356.485 L
2036
+ 329.7077 356.485 L
2037
+ 329.7077 353.3326 l
2038
+ f
2039
+ *U
2040
+ *u
2041
+ 333.7028 353.3326 m
2042
+ 333.4477 353.3326 L
2043
+ 332.737 355.4523 L
2044
+ 332.691 355.5819 332.6659 355.7241 332.6283 355.8579 c
2045
+ 332.6116 355.8579 L
2046
+ 332.6241 355.653 332.645 355.4523 332.645 355.2474 c
2047
+ 332.645 353.3326 L
2048
+ 332.39 353.3326 L
2049
+ 332.39 356.485 L
2050
+ 332.645 356.485 L
2051
+ 333.3683 354.2942 L
2052
+ 333.4059 354.1855 333.4352 354.0768 333.4645 353.9681 c
2053
+ 333.477 353.9681 L
2054
+ 333.4686 354.1061 333.4477 354.2482 333.4477 354.3862 c
2055
+ 333.4477 356.485 L
2056
+ 333.7028 356.485 L
2057
+ 333.7028 353.3326 l
2058
+ f
2059
+ *U
2060
+ *u
2061
+ 336.9846 354.9966 m
2062
+ 337.7037 354.9966 L
2063
+ 337.7037 354.4154 L
2064
+ 337.7037 353.9179 337.6787 353.2908 337.0264 353.2908 c
2065
+ 336.3617 353.2908 336.299 353.989 336.299 354.9841 c
2066
+ 336.299 355.7283 336.3868 356.5268 337.0557 356.5268 c
2067
+ 337.432 356.5268 337.6201 356.276 337.6996 355.9331 c
2068
+ 337.4111 355.8202 L
2069
+ 337.3776 356.0084 337.2982 356.2425 337.0682 356.2425 c
2070
+ 336.6334 356.2383 336.6 355.5652 336.6 355.0091 c
2071
+ 336.6 353.8427 336.7463 353.5751 337.0515 353.5751 c
2072
+ 337.3818 353.5751 337.4111 353.8176 337.4111 354.4907 c
2073
+ 337.4111 354.729 L
2074
+ 336.9846 354.729 L
2075
+ 336.9846 354.9966 l
2076
+ f
2077
+ *U
2078
+ U
2079
+ U
2080
+ 337.6667 -3924 m
2081
+ (N) *
2082
+ 337.6667 4716 m
2083
+ (N) *
2084
+ LB
2085
+ %AI5_EndLayer--
2086
+ %%PageTrailer
2087
+ gsave annotatepage grestore showpage
2088
+ %%Trailer
2089
+ Adobe_IllustratorA_AI5 /terminate get exec
2090
+ Adobe_level2_AI5 /terminate get exec
2091
+ %%EOF
my_container_sandbox/workspace/anaconda3/lib/tk8.6/images/logo100.gif ADDED