Permalink
Browse files

Packaged fileconveyor as an egg, in order to be compatible with Pytho…

…n tools like easy_install, pip or buildout. Added setup.py. Imports can now be done with fileconveyor namespace. In configuration file, transporters and processors names are full python module names (i.e. like fileconveyor.transporters.transporter_symlink_or_copy).
  • Loading branch information...
1 parent d1c55b8 commit d55649011577cdb90c882a72615e1e3d4fc31b75 @benoitbryon benoitbryon committed Aug 22, 2011
Showing with 66 additions and 26 deletions.
  1. +7 −0 .gitignore
  2. 0 {code → }/API.txt
  3. 0 {code → }/INSTALL.txt
  4. 0 {code → }/README.txt
  5. 0 {code → }/UNLICENSE
  6. 0 {code/dependencies → fileconveyor}/__init__.py
  7. +16 −18 {code → fileconveyor}/arbitrator.py
  8. 0 {code → fileconveyor}/config.py
  9. +7 −7 {code → fileconveyor}/config.sample.xml
  10. 0 {code → fileconveyor}/daemon_thread_runner.py
  11. 0 {code/dependencies/django/conf → fileconveyor/dependencies}/__init__.py
  12. 0 {code → fileconveyor}/dependencies/boto/__init__.py
  13. 0 {code → fileconveyor}/dependencies/boto/cloudfront/README.txt
  14. 0 {code → fileconveyor}/dependencies/boto/cloudfront/__init__.py
  15. 0 {code → fileconveyor}/dependencies/boto/cloudfront/distribution.py
  16. 0 {code → fileconveyor}/dependencies/boto/cloudfront/exception.py
  17. 0 {code → fileconveyor}/dependencies/boto/connection.py
  18. 0 {code → fileconveyor}/dependencies/boto/contrib/__init__.py
  19. 0 {code → fileconveyor}/dependencies/boto/contrib/m2helpers.py
  20. 0 {code → fileconveyor}/dependencies/boto/contrib/ymlmessage.py
  21. 0 {code → fileconveyor}/dependencies/boto/ec2/__init__.py
  22. 0 {code → fileconveyor}/dependencies/boto/ec2/address.py
  23. 0 {code → fileconveyor}/dependencies/boto/ec2/connection.py
  24. 0 {code → fileconveyor}/dependencies/boto/ec2/ec2object.py
  25. 0 {code → fileconveyor}/dependencies/boto/ec2/image.py
  26. 0 {code → fileconveyor}/dependencies/boto/ec2/instance.py
  27. 0 {code → fileconveyor}/dependencies/boto/ec2/keypair.py
  28. 0 {code → fileconveyor}/dependencies/boto/ec2/regioninfo.py
  29. 0 {code → fileconveyor}/dependencies/boto/ec2/securitygroup.py
  30. 0 {code → fileconveyor}/dependencies/boto/ec2/snapshot.py
  31. 0 {code → fileconveyor}/dependencies/boto/ec2/volume.py
  32. 0 {code → fileconveyor}/dependencies/boto/ec2/zone.py
  33. 0 {code → fileconveyor}/dependencies/boto/exception.py
  34. 0 {code → fileconveyor}/dependencies/boto/fps/__init__.py
  35. 0 {code → fileconveyor}/dependencies/boto/fps/connection.py
  36. 0 {code → fileconveyor}/dependencies/boto/handler.py
  37. 0 {code → fileconveyor}/dependencies/boto/mapreduce/__init__.py
  38. 0 {code → fileconveyor}/dependencies/boto/mapreduce/lqs.py
  39. 0 {code → fileconveyor}/dependencies/boto/mapreduce/partitiondb.py
  40. 0 {code → fileconveyor}/dependencies/boto/mapreduce/pdb_delete
  41. 0 {code → fileconveyor}/dependencies/boto/mapreduce/pdb_describe
  42. 0 {code → fileconveyor}/dependencies/boto/mapreduce/pdb_revert
  43. 0 {code → fileconveyor}/dependencies/boto/mapreduce/pdb_upload
  44. 0 {code → fileconveyor}/dependencies/boto/mapreduce/queuetools.py
  45. 0 {code → fileconveyor}/dependencies/boto/mashups/__init__.py
  46. 0 {code → fileconveyor}/dependencies/boto/mashups/interactive.py
  47. 0 {code → fileconveyor}/dependencies/boto/mashups/iobject.py
  48. 0 {code → fileconveyor}/dependencies/boto/mashups/order.py
  49. 0 {code → fileconveyor}/dependencies/boto/mashups/server.py
  50. 0 {code → fileconveyor}/dependencies/boto/mturk/__init__.py
  51. 0 {code → fileconveyor}/dependencies/boto/mturk/connection.py
  52. 0 {code → fileconveyor}/dependencies/boto/mturk/notification.py
  53. 0 {code → fileconveyor}/dependencies/boto/mturk/price.py
  54. 0 {code → fileconveyor}/dependencies/boto/mturk/qualification.py
  55. 0 {code → fileconveyor}/dependencies/boto/mturk/question.py
  56. 0 {code → fileconveyor}/dependencies/boto/mturk/test/all_tests.py
  57. 0 {code → fileconveyor}/dependencies/boto/mturk/test/cleanup_tests.py
  58. 0 {code → fileconveyor}/dependencies/boto/mturk/test/create_free_text_question_regex.doctest
  59. 0 {code → fileconveyor}/dependencies/boto/mturk/test/create_hit.doctest
  60. 0 {code → fileconveyor}/dependencies/boto/mturk/test/create_hit_binary.doctest
  61. 0 {code → fileconveyor}/dependencies/boto/mturk/test/create_hit_external.py
  62. 0 {code → fileconveyor}/dependencies/boto/mturk/test/create_hit_from_hit_type.doctest
  63. 0 {code → fileconveyor}/dependencies/boto/mturk/test/create_hit_with_qualifications.py
  64. 0 {code → fileconveyor}/dependencies/boto/mturk/test/reviewable_hits.doctest
  65. 0 {code → fileconveyor}/dependencies/boto/mturk/test/search_hits.doctest
  66. 0 {code → fileconveyor}/dependencies/boto/pyami/__init__.py
  67. BIN {code → fileconveyor}/dependencies/boto/pyami/__init__.pyc
  68. 0 {code → fileconveyor}/dependencies/boto/pyami/bootstrap.py
  69. 0 {code → fileconveyor}/dependencies/boto/pyami/config.py
  70. BIN {code → fileconveyor}/dependencies/boto/pyami/config.pyc
  71. 0 {code → fileconveyor}/dependencies/boto/pyami/copybot.cfg
  72. 0 {code → fileconveyor}/dependencies/boto/pyami/copybot.py
  73. 0 {code → fileconveyor}/dependencies/boto/pyami/helloworld.py
  74. 0 {code → fileconveyor}/dependencies/boto/pyami/installers/__init__.py
  75. 0 {code → fileconveyor}/dependencies/boto/pyami/installers/ubuntu/__init__.py
  76. 0 {code → fileconveyor}/dependencies/boto/pyami/installers/ubuntu/apache.py
  77. 0 {code → fileconveyor}/dependencies/boto/pyami/installers/ubuntu/installer.py
  78. 0 {code → fileconveyor}/dependencies/boto/pyami/installers/ubuntu/mysql.py
  79. 0 {code → fileconveyor}/dependencies/boto/pyami/installers/ubuntu/trac.py
  80. 0 {code → fileconveyor}/dependencies/boto/pyami/launch_ami.py
  81. 0 {code → fileconveyor}/dependencies/boto/pyami/scriptbase.py
  82. 0 {code → fileconveyor}/dependencies/boto/pyami/startup.py
  83. 0 {code → fileconveyor}/dependencies/boto/resultset.py
  84. 0 {code → fileconveyor}/dependencies/boto/s3/__init__.py
  85. 0 {code → fileconveyor}/dependencies/boto/s3/acl.py
  86. 0 {code → fileconveyor}/dependencies/boto/s3/bucket.py
  87. 0 {code → fileconveyor}/dependencies/boto/s3/bucketlistresultset.py
  88. 0 {code → fileconveyor}/dependencies/boto/s3/connection.py
  89. 0 {code → fileconveyor}/dependencies/boto/s3/key.py
  90. 0 {code → fileconveyor}/dependencies/boto/s3/prefix.py
  91. 0 {code → fileconveyor}/dependencies/boto/s3/user.py
  92. 0 {code → fileconveyor}/dependencies/boto/sdb/__init__.py
  93. 0 {code → fileconveyor}/dependencies/boto/sdb/connection.py
  94. 0 {code → fileconveyor}/dependencies/boto/sdb/db/__init__.py
  95. 0 {code → fileconveyor}/dependencies/boto/sdb/db/key.py
  96. 0 {code → fileconveyor}/dependencies/boto/sdb/db/manager/__init__.py
  97. 0 {code → fileconveyor}/dependencies/boto/sdb/db/manager/pgmanager.py
  98. 0 {code → fileconveyor}/dependencies/boto/sdb/db/manager/sdbmanager.py
  99. 0 {code → fileconveyor}/dependencies/boto/sdb/db/model.py
  100. 0 {code → fileconveyor}/dependencies/boto/sdb/db/property.py
  101. 0 {code → fileconveyor}/dependencies/boto/sdb/db/query.py
  102. 0 {code → fileconveyor}/dependencies/boto/sdb/db/test_db.py
  103. 0 {code → fileconveyor}/dependencies/boto/sdb/domain.py
  104. 0 {code → fileconveyor}/dependencies/boto/sdb/item.py
  105. 0 {code → fileconveyor}/dependencies/boto/sdb/persist/__init__.py
  106. 0 {code → fileconveyor}/dependencies/boto/sdb/persist/checker.py
  107. 0 {code → fileconveyor}/dependencies/boto/sdb/persist/object.py
  108. 0 {code → fileconveyor}/dependencies/boto/sdb/persist/property.py
  109. 0 {code → fileconveyor}/dependencies/boto/sdb/persist/test_persist.py
  110. 0 {code → fileconveyor}/dependencies/boto/sdb/queryresultset.py
  111. 0 {code → fileconveyor}/dependencies/boto/services/__init__.py
  112. 0 {code → fileconveyor}/dependencies/boto/services/bs.py
  113. 0 {code → fileconveyor}/dependencies/boto/services/message.py
  114. 0 {code → fileconveyor}/dependencies/boto/services/result.py
  115. 0 {code → fileconveyor}/dependencies/boto/services/service.py
  116. 0 {code → fileconveyor}/dependencies/boto/services/servicedef.py
  117. 0 {code → fileconveyor}/dependencies/boto/services/sonofmmm.cfg
  118. 0 {code → fileconveyor}/dependencies/boto/services/sonofmmm.py
  119. 0 {code → fileconveyor}/dependencies/boto/services/submit.py
  120. 0 {code → fileconveyor}/dependencies/boto/sqs/20070501/__init__.py
  121. 0 {code → fileconveyor}/dependencies/boto/sqs/20070501/attributes.py
  122. 0 {code → fileconveyor}/dependencies/boto/sqs/20070501/connection.py
  123. 0 {code → fileconveyor}/dependencies/boto/sqs/20070501/message.py
  124. 0 {code → fileconveyor}/dependencies/boto/sqs/20070501/queue.py
  125. 0 {code → fileconveyor}/dependencies/boto/sqs/20070501/readme.txt
  126. 0 {code → fileconveyor}/dependencies/boto/sqs/__init__.py
  127. 0 {code → fileconveyor}/dependencies/boto/sqs/attributes.py
  128. 0 {code → fileconveyor}/dependencies/boto/sqs/connection.py
  129. 0 {code → fileconveyor}/dependencies/boto/sqs/jsonmessage.py
  130. 0 {code → fileconveyor}/dependencies/boto/sqs/message.py
  131. 0 {code → fileconveyor}/dependencies/boto/sqs/queue.py
  132. 0 {code → fileconveyor}/dependencies/boto/tests/__init__.py
  133. 0 {code → fileconveyor}/dependencies/boto/tests/test.py
  134. 0 {code → fileconveyor}/dependencies/boto/tests/test_ec2connection.py
  135. 0 {code → fileconveyor}/dependencies/boto/tests/test_s3connection.py
  136. 0 {code → fileconveyor}/dependencies/boto/tests/test_sdbconnection.py
  137. 0 {code → fileconveyor}/dependencies/boto/tests/test_sqsconnection.py
  138. 0 {code → fileconveyor}/dependencies/boto/utils.py
  139. 0 {code → fileconveyor}/dependencies/cloudfiles/COPYING
  140. 0 {code → fileconveyor}/dependencies/cloudfiles/__init__.py
  141. 0 {code → fileconveyor}/dependencies/cloudfiles/authentication.py
  142. 0 {code → fileconveyor}/dependencies/cloudfiles/connection.py
  143. 0 {code → fileconveyor}/dependencies/cloudfiles/consts.py
  144. 0 {code → fileconveyor}/dependencies/cloudfiles/container.py
  145. 0 {code → fileconveyor}/dependencies/cloudfiles/errors.py
  146. 0 {code → fileconveyor}/dependencies/cloudfiles/fjson.py
  147. 0 {code → fileconveyor}/dependencies/cloudfiles/storage_object.py
  148. 0 {code → fileconveyor}/dependencies/cloudfiles/utils.py
  149. 0 {code → fileconveyor}/dependencies/django/__init__.py
  150. 0 {code/dependencies/django/core → fileconveyor/dependencies/django/conf}/__init__.py
  151. 0 {code → fileconveyor}/dependencies/django/conf/settings.py
  152. 0 {code/dependencies/django/utils → fileconveyor/dependencies/django/core}/__init__.py
  153. 0 {code → fileconveyor}/dependencies/django/core/exceptions.py
  154. 0 {code → fileconveyor}/dependencies/django/core/files/__init__.py
  155. 0 {code → fileconveyor}/dependencies/django/core/files/base.py
  156. 0 {code → fileconveyor}/dependencies/django/core/files/locks.py
  157. 0 {code → fileconveyor}/dependencies/django/core/files/move.py
  158. 0 {code → fileconveyor}/dependencies/django/core/files/storage.py
  159. 0 {code/dependencies/storages → fileconveyor/dependencies/django/utils}/__init__.py
  160. 0 {code → fileconveyor}/dependencies/django/utils/_os.py
  161. 0 {code → fileconveyor}/dependencies/django/utils/encoding.py
  162. 0 {code → fileconveyor}/dependencies/django/utils/functional.py
  163. 0 {code → fileconveyor}/dependencies/django/utils/text.py
  164. 0 {code → fileconveyor}/dependencies/django/utils/translation/__init__.py
  165. 0 {code → fileconveyor}/dependencies/django/utils/translation/trans_null.py
  166. 0 {code → fileconveyor}/dependencies/django/utils/translation/trans_real.py
  167. 0 {code → fileconveyor}/dependencies/django/utils/version.py
  168. 0 {code → fileconveyor}/dependencies/storages/DatabaseStorage.py
  169. 0 {code → fileconveyor}/dependencies/storages/FTPStorage.py
  170. 0 {code → fileconveyor}/dependencies/storages/ImageStorage.py
  171. 0 {code → fileconveyor}/dependencies/storages/MogileFSStorage.py
  172. 0 {code → fileconveyor}/dependencies/storages/OverwriteStorage.py
  173. 0 {code → fileconveyor}/dependencies/storages/S3BotoStorage.py
  174. 0 {code → fileconveyor}/dependencies/storages/S3Storage.py
  175. 0 {code → fileconveyor}/dependencies/storages/SFTPStorage.py
  176. 0 {code → fileconveyor}/dependencies/storages/SymlinkOrCopyStorage.py
  177. 0 {code/processors → fileconveyor/dependencies/storages}/__init__.py
  178. 0 {code → fileconveyor}/dependencies/storages/mosso.py
  179. 0 {code → fileconveyor}/filter.py
  180. 0 {code → fileconveyor}/filtertest.py
  181. 0 {code → fileconveyor}/fsmonitor.py
  182. 0 {code → fileconveyor}/fsmonitor_fsevents.py
  183. 0 {code → fileconveyor}/fsmonitor_inotify.py
  184. 0 {code → fileconveyor}/fsmonitor_polling.py
  185. 0 {code → fileconveyor}/pathscanner.py
  186. 0 {code → fileconveyor}/persistent_list.py
  187. 0 {code → fileconveyor}/persistent_list_test.py
  188. 0 {code → fileconveyor}/persistent_queue.py
  189. 0 {code → fileconveyor}/persistent_queue_test.py
  190. 0 {code/transporters → fileconveyor/processors}/__init__.py
  191. 0 {code → fileconveyor}/processors/filename.py
  192. 0 {code → fileconveyor}/processors/google_closure_compiler.py
  193. 0 {code → fileconveyor}/processors/image_optimizer.py
  194. 0 {code → fileconveyor}/processors/link_updater.py
  195. +1 −1 {code → fileconveyor}/processors/processor.py
  196. 0 {code → fileconveyor}/processors/processor_sample.py
  197. 0 {code → fileconveyor}/processors/unique_filename.py
  198. 0 {code → fileconveyor}/processors/yui_compressor.py
  199. 0 {code → fileconveyor}/settings.py
  200. 0 fileconveyor/transporters/__init__.py
  201. 0 {code → fileconveyor}/transporters/transporter.py
  202. 0 {code → fileconveyor}/transporters/transporter_cf.py
  203. 0 {code → fileconveyor}/transporters/transporter_ftp.py
  204. 0 {code → fileconveyor}/transporters/transporter_mosso.py
  205. 0 {code → fileconveyor}/transporters/transporter_s3.py
  206. 0 {code → fileconveyor}/transporters/transporter_sample.py
  207. 0 {code → fileconveyor}/transporters/transporter_sftp.py
  208. 0 {code → fileconveyor}/transporters/transporter_symlink_or_copy.py
  209. 0 {code → fileconveyor}/upgrade.py
  210. 0 {code → fileconveyor}/verify.py
  211. +35 −0 setup.py
View
@@ -0,0 +1,7 @@
+# Setuptools/Distribute's files
+*.egg-info
+dist
+build
+# Python's precompiled files
+*.pyc
+*.pyo
View
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -16,21 +16,19 @@
# and a full, yet extend, copy django-storages) at the beginning of sys.path,
# to prevent File Conveyor from using the code of a possible Django
# installation on this system.
-sys.path.insert(1, os.path.abspath(os.path.join(sys.path[0], 'dependencies')))
+FILE_CONVEYOR_PATH = os.path.abspath(os.path.dirname(__file__))
+sys.path.insert(1, os.path.abspath(os.path.join(FILE_CONVEYOR_PATH, 'dependencies')))
-sys.path.append(os.path.abspath(os.path.join(sys.path[0], 'processors')))
-sys.path.append(os.path.abspath(os.path.join(sys.path[0], 'transporters')))
-
-from settings import *
-from config import *
-from persistent_queue import *
-from persistent_list import *
-from fsmonitor import *
-from filter import *
-from processors.processor import *
-from transporters.transporter import *
-from daemon_thread_runner import *
+from fileconveyor.settings import *
+from fileconveyor.config import *
+from fileconveyor.persistent_queue import *
+from fileconveyor.persistent_list import *
+from fileconveyor.fsmonitor import *
+from fileconveyor.filter import *
+from fileconveyor.processors.processor import *
+from fileconveyor.transporters.transporter import *
+from fileconveyor.daemon_thread_runner import *
# Copied from django.utils.functional
@@ -130,7 +128,7 @@ def __init__(self, configfile="config.xml", restart=False):
for rule in self.config.rules[source]:
if not rule["processorChain"] is None:
for processor in rule["processorChain"]:
- (modulename, classname) = processor.split(".")
+ (modulename, classname) = processor.rsplit(".", 1)
try:
module = __import__(modulename, globals(), locals(), [classname])
processor_class = getattr(module, classname)
@@ -147,7 +145,7 @@ def __init__(self, configfile="config.xml", restart=False):
transporters_not_found = 0
for server in self.config.servers.keys():
transporter_name = self.config.servers[server]["transporter"]
- modulename = "transporters.transporter_" + transporter_name
+ modulename = transporter_name
try:
module = __import__(modulename, globals(), locals(), ["TRANSPORTER_CLASS"], -1)
classname = module.TRANSPORTER_CLASS
@@ -469,7 +467,7 @@ def __process_filter_queue(self):
per_server = False
for processor_classname in rule["processorChain"]:
# Get a reference to this processor class.
- (modulename, classname) = processor_classname.split(".")
+ (modulename, classname) = processor_classname.rsplit(".", 1)
module = __import__(modulename, globals(), locals(), [classname])
processor_class = getattr(module, classname)
if getattr(processor_class, 'different_per_server', False) == True:
@@ -859,7 +857,7 @@ def __create_transporter(self, server):
settings = self.config.servers[server]["settings"]
# Determine which class to import.
- transporter_modulename = "transporters.transporter_" + transporter_name
+ transporter_modulename = transporter_name
_temp = __import__(transporter_modulename, globals(), locals(), ["TRANSPORTER_CLASS"], -1)
transporter_classname = _temp.TRANSPORTER_CLASS
@@ -1038,7 +1036,7 @@ def clean_up_working_dir(self):
def run_file_conveyor(restart=False):
try:
- arbitrator = Arbitrator(os.path.join(sys.path[0], "config.xml"), restart)
+ arbitrator = Arbitrator(os.path.join(FILE_CONVEYOR_PATH, "config.xml"), restart)
except ArbitratorInitError, e:
print e.__class__.__name__, e
except ArbitratorError, e:
File renamed without changes.
@@ -8,11 +8,11 @@
<!-- Servers -->
<servers>
- <server name="origin pull cdn" transporter="symlink_or_copy">
+ <server name="origin pull cdn" transporter="fileconveyor.transporters.transporter_symlink_or_copy">
<location>/htdocs/static.example.com</location>
<url>http://localhost/static.example.com/</url>
</server>
- <server name="ftp push cdn" transporter="ftp" maxConnections="5">
+ <server name="ftp push cdn" transporter="fileconveyor.transporters.transporter_ftp" maxConnections="5">
<host>localhost</host>
<username>daemontest</username>
<password>daemontest</password>
@@ -28,11 +28,11 @@
<extensions>ico:js:css:gif:png:jpg:jpeg:svg:swf</extensions>
</filter>
<processorChain>
- <processor name="image_optimizer.KeepFilename" />
- <processor name="yui_compressor.YUICompressor" />
- <processor name="google_closure_compiler.GoogleClosureCompiler" />
- <processor name="link_updater.CSSURLUpdater" />
- <processor name="unique_filename.Mtime" />
+ <processor name="fileconveyor.processors.image_optimizer.KeepFilename" />
+ <processor name="fileconveyor.processors.yui_compressor.YUICompressor" />
+ <processor name="fileconveyor.processors.google_closure_compiler.GoogleClosureCompiler" />
+ <processor name="fileconveyor.processors.link_updater.CSSURLUpdater" />
+ <processor name="fileconveyor.processors.unique_filename.Mtime" />
</processorChain>
<destinations>
<destination server="origin pull cdn" path="static" />
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -154,7 +154,7 @@ def run(self):
processor_classname = self.processors.pop(0)
# Get a reference to that class.
- (modulename, classname) = processor_classname.split(".")
+ (modulename, classname) = processor_classname.rsplit(".", 1)
module = __import__(modulename, globals(), locals(), [classname])
processor_class = getattr(module, classname)
File renamed without changes.
No changes.
File renamed without changes.
File renamed without changes.
View
@@ -0,0 +1,35 @@
+# coding=utf-8
+import os.path
+from setuptools import setup, find_packages
+
+
+def read_relative_file(filename):
+ """Returns contents of the given file.
+ Filename argument must be relative to this module.
+ """
+ with open(os.path.join(os.path.dirname(__file__), filename)) as f:
+ return f.read()
+
+
+setup(
+ name='fileconveyor',
+ version='0.1-dev',
+ url='http://fileconveyor.org',
+ download_url='https://github.com/wimleers/fileconveyor',
+ author='Wim Leers',
+ license='Unlicense',
+ description="Daemon to detect, process and sync files to CDNs.",
+ long_description=read_relative_file('README.txt'),
+ platforms='Any',
+ classifiers = [
+ 'Development Status :: 4 - Beta',
+ 'License :: Public Domain',
+ 'Operating System :: OS Independent',
+ ],
+ packages=find_packages(),
+ include_package_data = True,
+ install_requires=[
+ 'setuptools',
+ 'cssutils',
+ ],
+)

0 comments on commit d556490

Please sign in to comment.