Compare commits

..

1 Commits

Author SHA1 Message Date
Luke Faraone
2a67775c27 Disable use_socket manually for CUSTOMER13
This was causing tracebacks during message sending

(imported from commit 9dde67f07934fe7a5aef7036340eebb7c6f6a97a)
2014-02-13 22:53:47 -05:00
552 changed files with 20955 additions and 20763 deletions

10
.gitignore vendored
View File

@@ -7,13 +7,12 @@
/prod-static
/errors/*
*.sw[po]
*.DS_Store
.DS_Store
event_queues.pickle
stats/
zerver/fixtures/available-migrations
zerver/fixtures/migration-status
zerver/fixtures/test_data1.json
zerver/tests/frontend/test_credentials.js
.kdev4
zulip.kdev4
memcached_prefix
@@ -27,10 +26,3 @@ manage.log
.kateproject.d/
.kateproject
*.kate-swp
event_queues.json
.vagrant
/zproject/dev-secrets.conf
static/third/gemoji/
static/third/zxcvbn/
tools/emoji_dump/bitmaps/
tools/emoji_dump/*.ttx

203
LICENSE
View File

@@ -1,202 +1,5 @@
Copyright <20> 2012-2013 Zulip, Inc.
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
This software is licensed under the Zulip Enterprise License Agreement.
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Zulip can be reached at support@zulip.com.

201
README.md
View File

@@ -1,201 +0,0 @@
Zulip
=====
Zulip is a powerful, open source group chat application. Written in
Python and using the Django framework, Zulip supports both private
messaging and group chats via conversation streams.
Zulip also supports fast search, drag-and-drop file uploads, image
previews, group private messages, audible notifications,
missed-message emails, desktop apps, and much more.
Further information on the Zulip project and its features can be found
at https://www.zulip.org
Contributing to Zulip
=====================
Zulip welcomes all forms of contributions!
Before a pull request can be merged, you need to to sign the [Dropbox
Contributor License Agreement](https://opensource.dropbox.com/cla/).
Please run the tests (tools/test-all) before submitting your pull
request and read our [commit message style
guidelines](http://zulip.readthedocs.org/en/latest/code-style.html#commit-messages).
Zulip has a growing collection of developer documentation including
detailed documentation on coding style available on [Read The
Docs](https://zulip.readthedocs.org/).
Zulip also has a [development discussion mailing list](https://groups.google.com/forum/#!forum/zulip-devel)
Feel free to send any questions or suggestions of areas where you'd
love to see more documentation to the list!
We recommend sending proposals for large features or refactorings to
the zulip-devel list for discussion and advice before getting too deep
into implementation.
Please report any security issues you discover to support@zulip.com.
Running Zulip in production
===========================
This is documented in https://zulip.org/server.html and README.prod.md.
Installing the Zulip Development environment
============================================
Using Vagrant
-------------
This is the recommended approach, and is tested on OS X 10.10 as well as Ubuntu 14.04.
* If your host is OS X, download VirtualBox from
<http://download.virtualbox.org/virtualbox/4.3.30/VirtualBox-4.3.30-101610-OSX.dmg>
and install it.
* If your host is Ubuntu 14.04:
`sudo apt-get install vagrant lxc lxc-templates cgroup-lite redir && vagrant plugin install vagrant-lxc`
Once that's done, simply change to your zulip directory and run
`vagrant up` in your terminal. That will install the development
server inside a Vagrant guest.
Once that finishes, you can run the development server as follows:
```
vagrant ssh -- -L9991:localhost:9991
# Now inside the container
cd /srv/zulip
source /srv/zulip-venv/bin/activate
./tools/run-dev.py --interface=''
```
You can now visit <http://localhost:9991/> in your browser. To get
shell access to the virtual machine running the server, use `vagrant ssh`.
(A small note on tools/run-dev.py: the `--interface=''` option will make
the development server listen on all network interfaces. While this
is correct for the Vagrant guest sitting behind a NAT, you probably
don't want to use that option when using run-dev.py in other environments).
The run-dev.py console output will show any errors your Zulip
development server encounters. It runs on top of Django's "manage.py
runserver" tool, which will automatically restart the Zulip server
whenever you save changes to Python code.
By hand
-------
Install the following non-Python dependencies:
* libffi-dev — needed for some Python extensions
* postgresql 9.1 or later — our database (also install development headers)
* memcached (and headers)
* rabbitmq-server
* libldap2-dev
* python-dev
* redis-server — rate limiting
* tsearch-extras — better text search
On Debian or Ubuntu systems:
```
sudo apt-get install libffi-dev memcached rabbitmq-server libldap2-dev redis-server postgresql-server-dev-all libmemcached-dev
# If on 12.04 or wheezy:
sudo apt-get install postgresql-9.1
wget https://dl.dropboxusercontent.com/u/283158365/zuliposs/postgresql-9.1-tsearch-extras_0.1.2_amd64.deb
sudo dpkg -i postgresql-9.1-tsearch-extras_0.1.2_amd64.deb
# If on 14.04:
sudo apt-get install postgresql-9.3
wget https://dl.dropboxusercontent.com/u/283158365/zuliposs/postgresql-9.3-tsearch-extras_0.1.2_amd64.deb
sudo dpkg -i postgresql-9.3-tsearch-extras_0.1.2_amd64.deb
# If on 15.04 or jessie:
sudo apt-get install postgresql-9.4
wget https://dl.dropboxusercontent.com/u/283158365/zuliposs/postgresql-9.4-tsearch-extras_0.1_amd64.deb
sudo dpkg -i postgresql-9.4-tsearch-extras_0.1_amd64.deb
# Then, all versions:
pip install -r requirements.txt
./scripts/setup/configure-rabbitmq
./tools/postgres-init-db
./tools/do-destroy-rebuild-database
./tools/emoji_dump/build_emoji
```
To start the development server:
```
./tools/run-dev.py
```
… and hit http://localhost:9991/.
Running the test suite
======================
One-time setup of test databases:
```
./tools/postgres-init-test-db
./tools/do-destroy-rebuild-test-database
```
Run all tests:
```
./tools/test-all
```
This runs the linter plus all of our test suites; they can all be run
separately (just read `tools/test-all` to see them). You can also run
individual tests, e.g.:
```
./tools/test-backend zerver.test_bugdown.BugdownTest.test_inline_youtube
./tools/test-js-with-casper 10-navigation.js
```
Possible testing issues
=======================
The Casper tests are flaky on the Virtualbox environment (probably due
to some performance-sensitive races). Until this issue is debugged,
you may need to rerun them to get them to pass.
When running the test suite, if you get an error like this:
```
sqlalchemy.exc.ProgrammingError: (ProgrammingError) function ts_match_locs_array(unknown, text, tsquery) does not exist
LINE 2: ...ECT message_id, flags, subject, rendered_content, ts_match_l...
^
```
… then you need to install tsearch-extras, described above. Afterwards, re-run the `init*-db` and the `do-destroy-rebuild*-database` scripts.
License
=======
Copyright 2011-2015 Dropbox, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
The software includes some works released by third parties under other
free and open source licenses. Those works are redistributed under the
license terms under which the works were received. For more details,
see the ``THIRDPARTY`` file included with this distribution.

View File

@@ -1,264 +0,0 @@
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: Zulip
Upstream-Contact: Zulip Development Discussion <zulip-devel@googlegroups.com>
Source: https://zulip.org/
Comment:
Unless otherwise noted, the Zulip software is distributed under the Apache
License, Version 2.0. The software includes some works released by third
parties under other free and open source licenses. Those works are
redistributed under the license terms under which the works were received.
.
While Dropbox has sought to provide complete and accurate licensing
information for each FOSS package, Dropbox does not represent or warrant
that the licensing information provided herein is correct or error-free.
Recipients of the Zulip software should investigate the identified FOSS
packages to confirm the accuracy of the licensing information provided.
Recipients are also encouraged to notify Dropbox of any inaccurate
information or errors found in these notices.
Files: *
Copyright: 2011-2015 Dropbox, Inc.
License: Apache-2
Files: api/*
Copyright: 2012-2014 Dropbox, Inc
License: Expat
Files: api/integrations/perforce/git_p4.py
Copyright: 2007 Simon Hausmann <simon@lst.de>,
2007 Trolltech ASA
License: Expat
Comment: https://raw.github.com/git/git/34022ba/git-p4.py
Files: bots/jabber_mirror_backend.py
Copyright: 2013 Permabit, Inc., 2013-2014 Dropbox, Inc.
License: Expat
Files: confirmation/*
Copyright: 2008, Jarek Zgoda <jarek.zgoda@gmail.com>
License: BSD-3-Clause
Files: node_modules/handlebars/*
Copyright: 2011 Yehuda Katz
License: Expat
Files: puppet/apt/*
Copyright: 2011, Evolving Web Inc.
License: Expat
Files: puppet/common/*
Copyright: 2007, David Schmitt
License: BSD-3-Clause
Comment: https://github.com/DavidS/puppet-common
Distribution includes a file `lib/puppet/parser/functions/ip_to_cron.rb` which
we removed due to unclear license
Files: puppet/stdlib/*
Copyright: 2011, Krzysztof Wilczynski
2011, Puppet Labs Inc
License: Apache-2.0
File: puppet/zulip_internal/files/mediawiki/Auth_remoteuser.php
Copyright: 2006 Otheus Shelling
2007 Rusty Burchfield
2009 James Kinsman
2010 Daniel Thomas
2010 Ian Ward Comfort
License: GPL-2.0
Comment: Not linked.
Files: puppet/zulip_internal/files/nagios_plugins/check_debian_packages
Copyright: 2005 Francesc Guasch
License: GPL-2.0
Comment: Not linked.
Files: puppet/zulip_internal/files/nagios_plugins/check_postgres.pl
Copyright: 2007-2015 Greg Sabino Mullane
License: BSD-2-Clause
Files: puppet/zulip_internal/files/nagios_plugins/check_website_response.sh
Copyright: 2011 Chris Freeman
License: GPL-2.0
Files: puppet/zulip_internal/files/trac/cgi-bin/
Copyright: 2003-2009 Edgewall Software
2003-2004 Jonas Borgström <jonas@edgewall.com>
License: BSD-3-Clause
Files: puppet/zulip_internal/files/pagerduty_nagios.pl
Copyright: 2011, PagerDuty, Inc.
License: BSD-3-Clause
Files: puppet/zulip_internal/files/zulip-ec2-configure-interfaces
Copyright: 2013, Dropbox, Inc.
License: Expat
Files: static/audio/zulip.*
Copyright: 2011 Vidsyn
License: CC-0-1.0
Files: static/styles/thirdparty-fonts.css
Copyright: 2012-2013 Dave Gandy
License: Expat
Files: static/third/fontawesome/*
Copyright: 2012-2013 Dave Gandy
License: SIL-OFL-1.1
Files: static/third/bootstrap/bootstrap-btn.css
Copyright: 2011-2014 Twitter, Inc
License: Expat
Files: static/third/bootstrap/css/bootstrap-responsive.css static/third/bootstrap/css/bootstrap.css
Copyright: 2012 Twitter, Inc
License: Apache-2.0
Comment: The software has been modified.
Files: static/third/bootstrap/js/bootstrap.js
Copyright: 2012 Twitter, Inc
License: Apache-2.0
Comment: The software has been modified.
Files: static/third/bootstrap-notify/*
Copyright: 2013 Nijiko Yonskai
2012 Goodybag, Inc.
2012 Twitter, Inc
License: Apache-2.0
Comment: The software has been modified.
Files: static/third/gemoji/images/emoji/unicode/* tools/emoji_dump/*.ttf
Copyright: Google, Inc.
License: Apache-2.0
Comment: These are actually Noto Emoji, not gemoji.
Files: static/third/handlebars/handlebars.runtime.js
Copyright: 2011 Yehuda Katz
License: Expat
Files: static/third/html5-formdata/formdata.js
Copyright: 2010 François de Metz
License: Expat
Comment: See https://github.com/francois2metz/html5-formdata
Files: src/zulip/static/third/jquery/*
Copyright: 2011, John Resig
2011, The Dojo Foundation
License: Expat
Files: static/third/jquery-autosize/jquery.autosize.js
Copyright: 2013 Jack Moore
License: Expat
Files: static/third/jquery-caret/*
Copyright: 2010 C.F., Wong
License: Expat
Files: static/third/jquery-filedrop/jquery.filedrop.js
Copyright: Resopollution
License: Expat
Files: static/third/jquery-form/jquery.form.js
Copyright: M. Alsup
License: Expat or GPL-2.0
Files: static/third/jquery-idle/jquery.idle.js
Copyright: 2011-2013 Henrique Boaventura
License: Expat
Comment: The software has been modified.
Files: static/third/jquery-mousewheel/jquery.mousewheel.js
Copyright: 2011 Brandon Aaron
License: Expat
Files: static/third/jquery-perfect-scrollbar/*
Copyright: 2012 HyeonJe Jun
License: Expat
Files: static/third/jquery-throttle-debounce/*
Copyright: 2010 "Cowboy" Ben Alman
License: Expat or GPL
Files: static/third/jquery-validate/*
Copyright: 2006 - 2011 Jörn Zaefferer
License: Expat
Files: src/zulip/static/third/lazyload/*
Copyright: 2011 Ryan Grove
License: Expat
Files: static/third/marked/*
Copyright: 2011-2013, Christopher Jeffrey
License: Expat
Files: static/third/sockjs/sockjs-0.3.4.js
Copyright: 2011-2012 VMware, Inc.
2012 Douglas Crockford
License: Expat and public-domain
Files: static/third/sorttable/sorttable.js
Copyright: 2007 Stuart Langridge
License: X11
Files: static/third/sourcesans/*
Copyright: 2010, 2012, 2014 Adobe Systems Incorporated
License: SIL-OFL-1.1
Files: static/third/spectrum/*
Copyright: 2013 Brian Grinstead
License: Expat
Files: static/third/spin/spin.js
Copyright: 2011-2013 Felix Gnass
License: Expat
Files: static/third/underscore/underscore.js
Copyright: 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
License: Expat
Comment: https://github.com/jashkenas/underscore/blob/master/LICENSE
Files: static/third/winchan/*
Copyright: 2012 Lloyd Hilaiel
License: Expat
Comment: https://github.com/mozilla/winchan
Files: static/third/xdate/*
Copyright: 2010 C. F., Wong
License: Expat
Files: static/third/zocial/*
Copyright: Sam Collins
License: Expat
Files: tools/inject-messages/othello
Copyright: Shakespeare
License: public-domain
Files: tools/jslint/jslint.js
Copyright: 2002 Douglas Crockford
License: XXX-good-not-evil
Files: tools/python-proxy
Copyright: 2009 F.bio Domingues
License: Expat
Files: tools/review
Copyright: 2010 Ksplice, Inc.
License: Apache-2.0
Files: zerver/lib/bugdown/codehilite.py zerver/lib/bugdown/fenced_code.py
Copyright: 2006-2008 Waylan Limberg
License: BSD-3-Clause
Comment: https://pypi.python.org/pypi/Markdown
Files: zerver/lib/ccache.py
Copyright: 2013 David Benjamin and Alan Huang
License: Expat
Files: zerver/tests/frontend/casperjs/*
Copyright: 2011-2012 Nicolas Perriault
Joyent, Inc. and other Node contributors
License: Expat
Files: zerver/tests/frontend/casperjs/modules/vendors/*
Copyright: 2011, Jeremy Ashkenas
License: Expat

34
Vagrantfile vendored
View File

@@ -1,34 +0,0 @@
# -*- mode: ruby -*-
VAGRANTFILE_API_VERSION = "2"
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
# For LXC. VirtualBox hosts use a different box, described below.
config.vm.box = "fgrehm/trusty64-lxc"
# The Zulip development environment runs on 9991 on the guest.
config.vm.network "forwarded_port", guest: 9991, host: 9991, host_ip: "127.0.0.1"
config.vm.synced_folder ".", "/vagrant", disabled: true
config.vm.synced_folder ".", "/srv/zulip"
config.vm.provider "virtualbox" do |vb, override|
override.vm.box = "ubuntu/trusty64"
# 2GiB seemed reasonable here. The VM OOMs with only 1024MiB.
vb.memory = 2048
end
$provision_script = <<SCRIPT
set -x
set -e
sudo apt-get update
sudo apt-get install -y python-pbs
python /srv/zulip/provision.py
SCRIPT
config.vm.provision "shell",
# We want provision.py to be run with the permissions of the vagrant user.
privileged: false,
inline: $provision_script
end

View File

@@ -17,10 +17,6 @@ python manage.py client_activity
python manage.py client_activity zulip.com
python manage.py client_activity jesstess@zulip.com"""
def add_arguments(self, parser):
parser.add_argument('arg', metavar='<arg>', type=str, nargs='?', default=None,
help="realm or user to estimate client activity for")
def compute_activity(self, user_activity_objects):
# Report data from the past week.
#
@@ -53,22 +49,21 @@ python manage.py client_activity jesstess@zulip.com"""
def handle(self, *args, **options):
if options['arg'] is None:
if len(args) == 0:
# Report global activity.
self.compute_activity(UserActivity.objects.all())
else:
arg = options['arg']
elif len(args) == 1:
try:
# Report activity for a user.
user_profile = get_user_profile_by_email(arg)
user_profile = get_user_profile_by_email(args[0])
self.compute_activity(UserActivity.objects.filter(
user_profile=user_profile))
except UserProfile.DoesNotExist:
try:
# Report activity for a realm.
realm = get_realm(arg)
realm = get_realm(args[0])
self.compute_activity(UserActivity.objects.filter(
user_profile__realm=realm))
except Realm.DoesNotExist:
print "Unknown user or domain %s" % (arg,)
print "Unknown user or domain %s" % (args[0],)
exit(1)

View File

@@ -16,10 +16,6 @@ human_messages = Message.objects.filter(sending_client__name__in=HUMAN_CLIENT_LI
class Command(BaseCommand):
help = "Generate statistics on realm activity."
def add_arguments(self, parser):
parser.add_argument('realms', metavar='<realm>', type=str, nargs='*',
help="realm to generate statistics for")
def active_users(self, realm):
# Has been active (on the website, for now) in the last 7 days.
activity_cutoff = datetime.datetime.now(tz=pytz.utc) - datetime.timedelta(days=7)
@@ -68,9 +64,9 @@ class Command(BaseCommand):
print "%.2f%% of" % (fraction * 100,), text
def handle(self, *args, **options):
if options['realms']:
if args:
try:
realms = [Realm.objects.get(domain=domain) for domain in options['realms']]
realms = [Realm.objects.get(domain=domain) for domain in args]
except Realm.DoesNotExist, e:
print e
exit(1)

View File

@@ -7,14 +7,10 @@ from zerver.models import Realm, Stream, Message, Subscription, Recipient
class Command(BaseCommand):
help = "Generate statistics on the streams for a realm."
def add_arguments(self, parser):
parser.add_argument('realms', metavar='<realm>', type=str, nargs='*',
help="realm to generate statistics for")
def handle(self, *args, **options):
if options['realms']:
if args:
try:
realms = [Realm.objects.get(domain=domain) for domain in options['realms']]
realms = [Realm.objects.get(domain=domain) for domain in args]
except Realm.DoesNotExist, e:
print e
exit(1)

View File

@@ -9,19 +9,15 @@ from zerver.models import UserProfile, Realm, Stream, Message
class Command(BaseCommand):
help = "Generate statistics on user activity."
def add_arguments(self, parser):
parser.add_argument('realms', metavar='<realm>', type=str, nargs='*',
help="realm to generate statistics for")
def messages_sent_by(self, user, week):
start = datetime.datetime.now(tz=pytz.utc) - datetime.timedelta(days=(week + 1)*7)
end = datetime.datetime.now(tz=pytz.utc) - datetime.timedelta(days=week*7)
return Message.objects.filter(sender=user, pub_date__gt=start, pub_date__lte=end).count()
def handle(self, *args, **options):
if options['realms']:
if args:
try:
realms = [Realm.objects.get(domain=domain) for domain in options['realms']]
realms = [Realm.objects.get(domain=domain) for domain in args]
except Realm.DoesNotExist, e:
print e
exit(1)

View File

@@ -172,7 +172,9 @@ def realm_summary_table(realm_minutes):
GROUP BY realm_id
) at_risk_counts
ON at_risk_counts.realm_id = realm.id
WHERE EXISTS (
WHERE
realm.domain not in ('customer4.invalid', 'wdaher.com')
AND EXISTS (
SELECT *
FROM zerver_useractivity ua
JOIN zerver_userprofile up
@@ -224,6 +226,11 @@ def realm_summary_table(realm_minutes):
# Count active sites
def meets_goal(row):
# The wdaher.com realm doesn't count toward company goals for
# obvious reasons, and customer4.invalid is essentially a dup
# for users.customer4.invalid.
if row['domain'] in ['customer4.invalid', 'wdaher.com']:
return False
return row['active_user_count'] >= 5
num_active_sites = len(filter(meets_goal, rows))

View File

@@ -30,12 +30,15 @@ file is as follows:
[api]
key=<api key from the web interface>
email=<your email address>
site=<your Zulip server's URI>
If you are using Zulip Enterprise, you should also add
site=<your Zulip Enterprise server's URI>
Alternatively, you may explicitly use "--user" and "--api-key" in our
examples, which is especially useful if you are running several bots
which share a home directory. There is also a "--site" option for
setting the Zulip server on the command line.
setting the Zulip Enterprise server on the command line.
You can obtain your Zulip API key, create bots, and manage bots all
from your Zulip [settings page](https://zulip.com/#settings).

View File

@@ -29,7 +29,7 @@ usage = """list-subscriptions --user=<bot's email address> --api-key=<bot's api
Prints out a list of the user's subscriptions.
Example: list-subscriptions --user=username@example.com --api-key=a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5
Example: list-subscriptions --user=tabbott@zulip.com --api-key=a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5
You can omit --user and --api-key arguments if you have a properly set up ~/.zuliprc
"""

View File

@@ -1,51 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright © 2012 Zulip, Inc.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
import sys
import os
import optparse
usage = """print-events --user=<bot's email address> --api-key=<bot's api key> [options]
Prints out certain events received by the indicated bot or user matching the filter below.
Example: print-events --user=username@example.com --api-key=a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5
You can omit --user and --api-key arguments if you have a properly set up ~/.zuliprc
"""
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
import zulip
parser = optparse.OptionParser(usage=usage)
parser.add_option_group(zulip.generate_option_group(parser))
(options, args) = parser.parse_args()
client = zulip.init_from_options(options)
def print_event(event):
print event
# This is a blocking call, and will continuously poll for new events
# Note also the filter here is messages to the stream Denmark; if you
# don't specify event_types it'll print all events.
client.call_on_each_event(print_event, event_types=["message"], narrow=[["stream", "Denmark"]])

View File

@@ -29,7 +29,7 @@ usage = """print-messages --user=<bot's email address> --api-key=<bot's api key>
Prints out each message received by the indicated bot or user.
Example: print-messages --user=username@example.com --api-key=a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5
Example: print-messages --user=tabbott@zulip.com --api-key=a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5
You can omit --user and --api-key arguments if you have a properly set up ~/.zuliprc
"""

View File

@@ -29,7 +29,7 @@ usage = """print-next-message --user=<bot's email address> --api-key=<bot's api
Prints out the next message received by the user.
Example: print-next-messages --user=username@example.com --api-key=a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5
Example: print-next-messages --user=tabbott@zulip.com --api-key=a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5
You can omit --user and --api-key arguments if you have a properly set up ~/.zuliprc
"""

View File

@@ -29,8 +29,8 @@ usage = """subscribe --user=<bot's email address> --api-key=<bot's api key> [opt
Ensures the user is subscribed to the listed streams.
Examples: subscribe --user=username@example.com --api-key=a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5 --streams=foo
subscribe --user=username@example.com --api-key=a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5 --streams='foo bar'
Examples: subscribe --user=tabbott@zulip.com --api-key=a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5 --streams=foo
subscribe --user=tabbott@zulip.com --api-key=a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5 --streams='foo bar'
You can omit --user and --api-key arguments if you have a properly set up ~/.zuliprc
"""

View File

@@ -29,8 +29,8 @@ usage = """unsubscribe --user=<bot's email address> --api-key=<bot's api key> [
Ensures the user is not subscribed to the listed streams.
Examples: unsubscribe --user=username@example.com --api-key=a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5 --streams=foo
unsubscribe --user=username@example.com --api-key=a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5 --streams='foo bar'
Examples: unsubscribe --user=tabbott@zulip.com --api-key=a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5 --streams=foo
unsubscribe --user=tabbott@zulip.com --api-key=a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5 --streams='foo bar'
You can omit --user and --api-key arguments if you have a properly set up ~/.zuliprc
"""

View File

@@ -38,7 +38,7 @@ ZULIP_STREAM_NAME = "asana"
### OPTIONAL CONFIGURATION ###
# Set to None for logging to stdout when testing, and to a file for
# logging in production.
# logging when deployed.
#LOG_FILE = "/var/tmp/zulip_asana.log"
LOG_FILE = None
@@ -49,7 +49,7 @@ RESUME_FILE = "/var/tmp/zulip_asana.state"
# When initially started, how many hours of messages to include.
ASANA_INITIAL_HISTORY_HOURS = 1
# Set this to your Zulip API server URI
# If you're using Zulip Enterprise, set this to your Zulip Enterprise server
ZULIP_SITE = "https://api.zulip.com"
# If properly installed, the Zulip API should be in your import

19
api/integrations/asana/zulip_asana_mirror Executable file → Normal file
View File

@@ -22,17 +22,11 @@
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
# The "zulip_asana_mirror" script is run continuously, possibly on a work computer
# or preferably on a server.
#
# When restarted, it will attempt to pick up where it left off.
#
# python-dateutil is a dependency for this script.
import base64
from datetime import datetime, timedelta
import dateutil.parser
import dateutil.tz
import json
import logging
import os
@@ -40,15 +34,6 @@ import time
import urllib2
import sys
try:
import dateutil.parser
import dateutil.tz
except ImportError, e:
print >>sys.stderr, e
print >>sys.stderr, "Please install the python-dateutil package."
exit(1)
sys.path.insert(0, os.path.dirname(__file__))
import zulip_asana_config as config
VERSION = "0.9"

View File

@@ -41,7 +41,7 @@ ZULIP_STREAM_NAME = "basecamp"
## path, but if not, set a custom path below
ZULIP_API_PATH = None
# Set this to your Zulip API server URI
# If you're using Zulip Enterprise, set this to your Zulip Enterprise server
ZULIP_SITE = "https://api.zulip.com"
# If you wish to log to a file rather than stdout/stderr,

View File

@@ -50,7 +50,7 @@ ZULIP_TICKETS_STREAM_NAME = "tickets"
# path, but if not, set a custom path below
ZULIP_API_PATH = None
# Set this to your Zulip API server URI
# If you're using Zulip Enterprise, set this to your Zulip Enterprise server
ZULIP_SITE = "https://api.zulip.com"
# If you wish to log to a file rather than stdout/stderr,

View File

@@ -22,12 +22,12 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
# The "zulip_codebase_mirror" script is run continuously, possibly on a work
# computer or preferably on a server.
# The "codebase-mirror.py" script is run continuously, possibly on a work computer
# or preferably on a server.
#
# When restarted, it will attempt to pick up where it left off.
#
# python-dateutil is a dependency for this script.
# You may need to install the python-requests library, as well as python-dateutil
import requests
import logging
@@ -37,13 +37,7 @@ import os
from datetime import datetime, timedelta
try:
import dateutil.parser
except ImportError, e:
print >>sys.stderr, e
print >>sys.stderr, "Please install the python-dateutil package."
exit(1)
import dateutil.parser
sys.path.insert(0, os.path.dirname(__file__))
import zulip_codebase_config as config

View File

@@ -61,5 +61,5 @@ def format_commit_message(author, subject, commit_id):
## path, but if not, set a custom path below
ZULIP_API_PATH = None
# Set this to your Zulip server's API URI
# If you're using Zulip Enterprise, set this to your Zulip Enterprise server
ZULIP_SITE = "https://api.zulip.com"

View File

@@ -136,7 +136,7 @@ def strip_tags(html):
def compute_entry_hash(entry):
entry_time = entry.get("published", entry.get("updated"))
entry_id = entry.get("id", entry.get("link"))
return hashlib.md5(entry_id + str(entry_time)).hexdigest()
return hashlib.md5(entry_id + entry_time).hexdigest()
def elide_subject(subject):
MAX_TOPIC_LENGTH = 60
@@ -184,7 +184,7 @@ for feed_url in feed_urls:
entry_hash = compute_entry_hash(entry)
# An entry has either been published or updated.
entry_time = entry.get("published_parsed", entry.get("updated_parsed"))
if entry_time is not None and (time.time() - calendar.timegm(entry_time)) > OLDNESS_THRESHOLD * 60 * 60 * 24:
if (time.time() - calendar.timegm(entry_time)) > OLDNESS_THRESHOLD * 60 * 60 * 24:
# As a safeguard against misbehaving feeds, don't try to process
# entries older than some threshold.
continue

View File

@@ -53,5 +53,5 @@ def commit_notice_destination(path, commit):
## path, but if not, set a custom path below
ZULIP_API_PATH = None
# Set this to your Zulip server's API URI
# If you're using Zulip Enterprise, set this to your Zulip Enterprise server
ZULIP_SITE = "https://api.zulip.com"

View File

@@ -47,5 +47,5 @@ TRAC_NOTIFY_FIELDS = ["description", "summary", "resolution", "comment", "owner"
## path, but if not, set a custom path below
ZULIP_API_PATH = None
# Set this to your Zulip API server URI
# If you're using Zulip Enterprise, set this to your Zulip Enterprise server
ZULIP_SITE = "https://api.zulip.com"

View File

@@ -126,9 +126,9 @@ except ConfigParser.NoOptionError:
user_id = options.twitter_id
client = zulip.Client(
email=options.zulip_email,
api_key=options.zulip_api_key,
site=options.zulip_site,
email=options.email,
api_key=options.api_key,
site=options.site,
client="ZulipTwitter/" + VERSION,
verbose=True)

View File

@@ -29,8 +29,6 @@ import sys
import os
import optparse
import platform
import urllib
import random
from distutils.version import LooseVersion
from ConfigParser import SafeConfigParser
@@ -39,8 +37,6 @@ import logging
__version__ = "0.2.4"
logger = logging.getLogger(__name__)
# Check that we have a recent enough version
# Older versions don't provide the 'json' attribute on responses.
assert(LooseVersion(requests.__version__) >= LooseVersion('0.12.1'))
@@ -49,91 +45,39 @@ requests_json_is_function = callable(requests.Response.json)
API_VERSTRING = "v1/"
class CountingBackoff(object):
def __init__(self, maximum_retries=10, timeout_success_equivalent=None):
self.number_of_retries = 0
self.maximum_retries = maximum_retries
self.timeout_success_equivalent = timeout_success_equivalent
self.last_attempt_time = 0
def keep_going(self):
self._check_success_timeout()
return self.number_of_retries < self.maximum_retries
def succeed(self):
self.number_of_retries = 0
self.last_attempt_time = time.time()
def fail(self):
self._check_success_timeout()
self.number_of_retries = min(self.number_of_retries + 1,
self.maximum_retries)
self.last_attempt_time = time.time()
def _check_success_timeout(self):
if (self.timeout_success_equivalent is not None
and self.last_attempt_time != 0
and time.time() - self.last_attempt_time > self.timeout_success_equivalent):
self.number_of_retries = 0
class RandomExponentialBackoff(CountingBackoff):
def fail(self):
super(RandomExponentialBackoff, self).fail()
# Exponential growth with ratio sqrt(2); compute random delay
# between x and 2x where x is growing exponentially
delay_scale = int(2 ** (self.number_of_retries / 2.0 - 1)) + 1
delay = delay_scale + random.randint(1, delay_scale)
message = "Sleeping for %ss [max %s] before retrying." % (delay, delay_scale * 2)
try:
logger.warning(message)
except NameError:
print message
time.sleep(delay)
def _default_client():
return "ZulipPython/" + __version__
def generate_option_group(parser, prefix=''):
group = optparse.OptionGroup(parser, 'Zulip API configuration')
group.add_option('--%ssite' % (prefix,),
dest="zulip_site",
help="Zulip server URI",
def generate_option_group(parser):
group = optparse.OptionGroup(parser, 'API configuration')
group.add_option('--site',
help="Zulip Enterprise server URI (if using Zulip Enterprise)",
default=None)
group.add_option('--%sapi-key' % (prefix,),
dest="zulip_api_key",
group.add_option('--api-key',
action='store')
group.add_option('--%suser' % (prefix,),
dest='zulip_email',
group.add_option('--user',
dest='email',
help='Email address of the calling bot or user.')
group.add_option('--%sconfig-file' % (prefix,),
group.add_option('--config-file',
action='store',
dest="zulip_config_file",
help='Location of an ini file containing the\nabove information. (default ~/.zuliprc)')
group.add_option('-v', '--verbose',
action='store_true',
help='Provide detailed output.')
group.add_option('--%sclient' % (prefix,),
group.add_option('--client',
action='store',
default=None,
dest="zulip_client",
help=optparse.SUPPRESS_HELP)
return group
def init_from_options(options, client=None):
if options.zulip_client is not None:
client = options.zulip_client
if options.client is not None:
client = options.client
elif client is None:
client = _default_client()
return Client(email=options.zulip_email, api_key=options.zulip_api_key,
config_file=options.zulip_config_file, verbose=options.verbose,
site=options.zulip_site, client=client)
def get_default_config_filename():
config_file = os.path.join(os.environ["HOME"], ".zuliprc")
if (not os.path.exists(config_file) and
os.path.exists(os.path.join(os.environ["HOME"], ".humbugrc"))):
raise RuntimeError("The Zulip API configuration file is now ~/.zuliprc; please run:\n\n mv ~/.humbugrc ~/.zuliprc\n")
return config_file
return Client(email=options.email, api_key=options.api_key,
config_file=options.config_file, verbose=options.verbose,
site=options.site, client=client)
class Client(object):
def __init__(self, email=None, api_key=None, config_file=None,
@@ -143,7 +87,10 @@ class Client(object):
client = _default_client()
if None in (api_key, email):
if config_file is None:
config_file = get_default_config_filename()
config_file = os.path.join(os.environ["HOME"], ".zuliprc")
if (not os.path.exists(config_file) and
os.path.exists(os.path.join(os.environ["HOME"], ".humbugrc"))):
raise RuntimeError("The Zulip API configuration file is now ~/.zuliprc; please run:\n\n mv ~/.humbugrc ~/.zuliprc\n")
if not os.path.exists(config_file):
raise RuntimeError("api_key or email not specified and %s does not exist"
% (config_file,))
@@ -176,15 +123,8 @@ class Client(object):
self.client_name = client
def get_user_agent(self):
vendor = ''
vendor_version = ''
try:
vendor = platform.system()
vendor_version = platform.release()
except IOError:
# If the calling process is handling SIGCHLD, platform.system() can
# fail with an IOError. See http://bugs.python.org/issue9127
pass
vendor = platform.system()
vendor_version = platform.release()
if vendor == "Linux":
vendor, vendor_version, dummy = platform.linux_distribution()
@@ -301,16 +241,12 @@ class Client(object):
@classmethod
def _register(cls, name, url=None, make_request=(lambda request={}: request),
method="POST", computed_url=None, **query_kwargs):
method="POST", **query_kwargs):
if url is None:
url = name
def call(self, *args, **kwargs):
request = make_request(*args, **kwargs)
if computed_url is not None:
req_url = computed_url(request)
else:
req_url = url
return self.do_api_query(request, API_VERSTRING + req_url, method=method, **query_kwargs)
return self.do_api_query(request, API_VERSTRING + url, method=method, **query_kwargs)
call.func_name = name
setattr(cls, name, call)
@@ -416,7 +352,6 @@ Client._register('update_message', method='PATCH', url='messages', make_request=
Client._register('get_messages', method='GET', url='messages/latest', longpolling=True)
Client._register('get_events', url='events', method='GET', longpolling=True, make_request=(lambda **kwargs: kwargs))
Client._register('register', make_request=_mk_events)
Client._register('export', method='GET', url='export')
Client._register('deregister', url="events", method="DELETE", make_request=_mk_deregister)
Client._register('get_profile', method='GET', url='users/me')
Client._register('get_streams', method='GET', url='streams', make_request=_kwargs_to_dict)
@@ -424,8 +359,5 @@ Client._register('get_members', method='GET', url='users')
Client._register('list_subscriptions', method='GET', url='users/me/subscriptions')
Client._register('add_subscriptions', url='users/me/subscriptions', make_request=_mk_subs)
Client._register('remove_subscriptions', method='PATCH', url='users/me/subscriptions', make_request=_mk_rm_subs)
Client._register('get_subscribers', method='GET',
computed_url=lambda request: 'streams/%s/members' % (urllib.quote(request['stream'], safe=''),),
make_request=_kwargs_to_dict)
Client._register('render_message', method='GET', url='messages/render')
Client._register('create_user', method='POST', url='users')

View File

@@ -1,202 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@@ -1,13 +0,0 @@
This directory contains images adapted from the Noto project. For more detail
about Noto, please refer to:
https://code.google.com/p/noto/
These images were generated from the git repository at
<https://android.googlesource.com/platform/external/noto-fonts> as of
90372d894b5d9c9f2a111315d2eb3b8de1979ee4
and
<https://android.googlesource.com/platform/frameworks/base> at
07912f876c8639f811b06831465c14c4a3b17663.

View File

@@ -11,5 +11,5 @@ ZULIP_DIR=/home/zulip/deployments/current
STATE_DIR=/var/lib/nagios_state
STATE_FILE=$STATE_DIR/check-rabbitmq-consumers-$queue
"$ZULIP_DIR/bots/check-rabbitmq-consumers" "--queue=$queue" &> "${STATE_FILE}-tmp";
mv "${STATE_FILE}-tmp" "$STATE_FILE"
$ZULIP_DIR/bots/check-rabbitmq-consumers --queue=$queue &> ${STATE_FILE}-tmp;
mv ${STATE_FILE}-tmp $STATE_FILE

View File

@@ -6,14 +6,8 @@ import time
import os
import subprocess
WARN_THRESHOLD_DEFAULT = 10
WARN_THRESHOLD = {
'missedmessage_emails': 45,
}
CRIT_THRESHOLD_DEFAULT = 50
CRIT_THRESHOLD = {
'missedmessage_emails': 70,
}
WARN_THRESHOLD = 10
CRIT_THRESHOLD = 50
states = {
0: "OK",
@@ -39,10 +33,10 @@ for line in output.split("\n"):
queue = m.group(1)
count = int(m.group(2))
this_status = 0
if count > CRIT_THRESHOLD.get(queue, CRIT_THRESHOLD_DEFAULT):
if count > CRIT_THRESHOLD:
this_status = 2
warn_queues.append(queue)
elif count > WARN_THRESHOLD.get(queue, WARN_THRESHOLD_DEFAULT):
elif count > WARN_THRESHOLD:
this_status = max(status, 1)
warn_queues.append(queue)
@@ -56,7 +50,7 @@ now_struct = time.gmtime(now)
# While we are sending digest emails, at 11am each weekday, the mail queues can
# get backed up; don't alert on those.
if not set(warn_queues) - set(("missedmessage_emails", "digest_emails")) and \
now_struct.tm_hour == 15 and now_struct.tm_min < 25:
now_struct.tm_hour == 16 and now_struct.tm_min < 15:
status = 0
print("%s|%s|%s|processing digests, not alerting on elevated mail queues" % (
now, status, states[status]))

View File

@@ -47,7 +47,7 @@ parser.add_option_group(zulip.generate_option_group(parser))
(options, args) = parser.parse_args()
if not (options.zulip_email and options.calendar):
if not (options.user and options.calendar):
parser.error('You must specify --user and --calendar')
try:

View File

@@ -12,11 +12,9 @@ from irc.client import ip_numstr_to_quad, ip_quad_to_numstr
import zulip
import optparse
IRC_DOMAIN = "irc.example.com"
def zulip_sender(sender_string):
nick = sender_string.split("!")[0]
return nick + "@" + IRC_DOMAIN
return nick + "@irc.zulip.com"
class IRCBot(irc.bot.SingleServerIRCBot):
def __init__(self, channel, nickname, server, port=6667):
@@ -49,14 +47,14 @@ class IRCBot(irc.bot.SingleServerIRCBot):
def on_privmsg(self, c, e):
content = e.arguments[0]
sender = zulip_sender(e.source)
if sender.endswith("_zulip@" + IRC_DOMAIN):
if sender.endswith("_zulip@irc.zulip.com"):
return
# Forward the PM to Zulip
print zulip_client.send_message({
"sender": sender,
"type": "private",
"to": "username@example.com",
"to": "tabbott@zulip.com",
"content": content,
})
@@ -64,7 +62,7 @@ class IRCBot(irc.bot.SingleServerIRCBot):
content = e.arguments[0]
stream = e.target
sender = zulip_sender(e.source)
if sender.endswith("_zulip@" + IRC_DOMAIN):
if sender.endswith("_zulip@irc.zulip.com"):
return
# Forward the stream message to Zulip
@@ -96,8 +94,8 @@ usage = """python irc-mirror.py --server=IRC_SERVER --channel=<CHANNEL> --nick-p
Example:
python irc-mirror.py --irc-server=127.0.0.1 --channel='#test' --nick-prefix=username
--site=https://zulip.example.com --user=irc-bot@example.com
python irc-mirror.py --irc-server=127.0.0.1 --channel='#test' --nick-prefix=tabbott
--site=https://staging.zulip.com --user=irc-bot@zulip.com
--api-key=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Note that "_zulip" will be automatically appended to the IRC nick provided

View File

@@ -1,59 +0,0 @@
#!/usr/bin/env python
# Copyright (C) 2014 Zulip, Inc.
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation files
# (the "Software"), to deal in the Software without restriction,
# including without limitation the rights to use, copy, modify, merge,
# publish, distribute, sublicense, and/or sell copies of the Software,
# and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
import sys
import subprocess
import os
import traceback
import signal
from zulip import RandomExponentialBackoff
def die(signal, frame):
# We actually want to exit, so run os._exit (so as not to be caught and restarted)
os._exit(1)
signal.signal(signal.SIGINT, die)
args = [os.path.join(os.path.dirname(sys.argv[0]), "jabber_mirror_backend.py")]
args.extend(sys.argv[1:])
backoff = RandomExponentialBackoff(timeout_success_equivalent=300)
while backoff.keep_going():
print "Starting Jabber mirroring bot"
try:
ret = subprocess.call(args)
except:
traceback.print_exc()
else:
if ret == 2:
# Don't try again on initial configuration errors
sys.exit(ret)
backoff.fail()
print ""
print ""
print "ERROR: The Jabber mirroring bot is unable to continue mirroring Jabber."
print "Please contact support@zulip.com if you need assistance."
print ""
sys.exit(1)

View File

@@ -1,445 +0,0 @@
#!/usr/bin/python
#
# Copyright (C) 2013 Permabit, Inc.
# Copyright (C) 2013--2014 Zulip, Inc.
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation files
# (the "Software"), to deal in the Software without restriction,
# including without limitation the rights to use, copy, modify, merge,
# publish, distribute, sublicense, and/or sell copies of the Software,
# and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
# The following is a table showing which kinds of messages are handled by the
# mirror in each mode:
#
# Message origin/type --> | Jabber | Zulip
# Mode/sender-, +-----+----+--------+----
# V | MUC | PM | stream | PM
# --------------+-------------+-----+----+--------+----
# | other sender| | x | |
# personal mode +-------------+-----+----+--------+----
# | self sender | | x | x | x
# ------------- +-------------+-----+----+--------+----
# | other sender| x | | |
# public mode +-------------+-----+----+--------+----
# | self sender | | | |
import logging
import threading
import optparse
from sleekxmpp import ClientXMPP, InvalidJID, JID
from sleekxmpp.exceptions import IqError, IqTimeout
from ConfigParser import SafeConfigParser
import os, sys, zulip, getpass
import re
__version__ = "1.1"
def room_to_stream(room):
return room + "/xmpp"
def stream_to_room(stream):
return stream.lower().rpartition("/xmpp")[0]
def jid_to_zulip(jid):
suffix = ''
if not jid.username.endswith("-bot"):
suffix = options.zulip_email_suffix
return "%s%s@%s" % (jid.username, suffix, options.zulip_domain)
def zulip_to_jid(email, jabber_domain):
jid = JID(email, domain=jabber_domain)
if (options.zulip_email_suffix
and options.zulip_email_suffix in jid.username
and not jid.username.endswith("-bot")):
jid.username = jid.username.rpartition(options.zulip_email_suffix)[0]
return jid
class JabberToZulipBot(ClientXMPP):
def __init__(self, jid, password, rooms):
if jid.resource:
self.nick = jid.resource
else:
self.nick = jid.username
jid.resource = "zulip"
ClientXMPP.__init__(self, jid, password)
self.rooms = set()
self.rooms_to_join = rooms
self.add_event_handler("session_start", self.session_start)
self.add_event_handler("message", self.message)
self.zulip = None
self.use_ipv6 = False
self.register_plugin('xep_0045') # Jabber chatrooms
self.register_plugin('xep_0199') # XMPP Ping
def set_zulip_client(self, client):
self.zulip = client
def session_start(self, event):
self.get_roster()
self.send_presence()
for room in self.rooms_to_join:
self.join_muc(room)
def join_muc(self, room):
if room in self.rooms:
return
logging.debug("Joining " + room)
self.rooms.add(room)
muc_jid = JID(local=room, domain=options.conference_domain)
xep0045 = self.plugin['xep_0045']
try:
xep0045.joinMUC(muc_jid, self.nick, wait=True)
except InvalidJID:
logging.error("Could not join room: " + str(muc_jid))
return
# Configure the room. Really, we should only do this if the room is
# newly created.
form = None
try:
form = xep0045.getRoomConfig(muc_jid)
except ValueError:
pass
if form:
xep0045.configureRoom(muc_jid, form)
else:
logging.error("Could not configure room: " + str(muc_jid))
def leave_muc(self, room):
if room not in self.rooms:
return
logging.debug("Leaving " + room)
self.rooms.remove(room)
muc_jid = JID(local=room, domain=options.conference_domain)
self.plugin['xep_0045'].leaveMUC(muc_jid, self.nick)
def message(self, msg):
try:
if msg["type"] == "groupchat":
return self.group(msg)
elif msg["type"] == "chat":
return self.private(msg)
else:
logging.warning("Got unexpected message type")
logging.warning(msg)
except Exception:
logging.exception("Error forwarding Jabber => Zulip")
def private(self, msg):
if options.mode == 'public' or msg['thread'] == u'\u1FFFE':
return
sender = jid_to_zulip(msg["from"])
recipient = jid_to_zulip(msg["to"])
zulip_message = dict(
sender = sender,
type = "private",
to = recipient,
content = msg["body"],
)
ret = self.zulip.client.send_message(zulip_message)
if ret.get("result") != "success":
logging.error(ret)
def group(self, msg):
if options.mode == 'personal' or msg["thread"] == u'\u1FFFE':
return
subject = msg["subject"]
if len(subject) == 0:
subject = "(no topic)"
stream = room_to_stream(msg['from'].local)
sender_nick = msg.get_mucnick()
if not sender_nick:
# Messages from the room itself have no nickname. We should not try
# to mirror these
return
jid = self.nickname_to_jid(msg.get_mucroom(), sender_nick)
sender = jid_to_zulip(jid)
zulip_message = dict(
forged = "yes",
sender = sender,
type = "stream",
subject = subject,
to = stream,
content = msg["body"],
)
ret = self.zulip.client.send_message(zulip_message)
if ret.get("result") != "success":
logging.error(ret)
def nickname_to_jid(self, room, nick):
jid = self.plugin['xep_0045'].getJidProperty(room, nick, "jid")
if (jid is None or jid == ''):
return JID(local=nick.replace(' ', ''), domain=self.boundjid.domain)
else:
return jid
class ZulipToJabberBot(object):
def __init__(self, zulip_client):
self.client = zulip_client
self.jabber = None
def set_jabber_client(self, client):
self.jabber = client
def process_event(self, event):
if event['type'] == 'message':
message = event["message"]
if message['sender_email'] != self.client.email:
return
try:
if message['type'] == 'stream':
self.stream_message(message)
elif message['type'] == 'private':
self.private_message(message)
except:
logging.exception("Exception forwarding Zulip => Jabber")
elif event['type'] == 'subscription':
self.process_subscription(event)
elif event['type'] == 'stream':
self.process_stream(event)
def stream_message(self, msg):
stream = msg['display_recipient']
if not stream.endswith("/xmpp"):
return
room = stream_to_room(stream)
jabber_recipient = JID(local=room, domain=options.conference_domain)
outgoing = self.jabber.make_message(
mto = jabber_recipient,
mbody = msg['content'],
mtype = 'groupchat')
outgoing['thread'] = u'\u1FFFE'
outgoing.send()
def private_message(self, msg):
for recipient in msg['display_recipient']:
if recipient["email"] == self.client.email:
continue
if not recipient["is_mirror_dummy"]:
continue
recip_email = recipient['email']
jabber_recipient = zulip_to_jid(recip_email, self.jabber.boundjid.domain)
outgoing = self.jabber.make_message(
mto = jabber_recipient,
mbody = msg['content'],
mtype = 'chat')
outgoing['thread'] = u'\u1FFFE'
outgoing.send()
def process_subscription(self, event):
if event['op'] == 'add':
streams = [s['name'].lower() for s in event['subscriptions']]
streams = [s for s in streams if s.endswith("/xmpp")]
for stream in streams:
self.jabber.join_muc(stream_to_room(stream))
if event['op'] == 'remove':
streams = [s['name'].lower() for s in event['subscriptions']]
streams = [s for s in streams if s.endswith("/xmpp")]
for stream in streams:
self.jabber.leave_muc(stream_to_room(stream))
def process_stream(self, event):
if event['op'] == 'occupy':
streams = [s['name'].lower() for s in event['streams']]
streams = [s for s in streams if s.endswith("/xmpp")]
for stream in streams:
self.jabber.join_muc(stream_to_room(stream))
if event['op'] == 'vacate':
streams = [s['name'].lower() for s in event['streams']]
streams = [s for s in streams if s.endswith("/xmpp")]
for stream in streams:
self.jabber.leave_muc(stream_to_room(stream))
def get_rooms(zulip):
def get_stream_infos(key, method):
ret = method()
if ret.get("result") != "success":
logging.error(ret)
sys.exit("Could not get initial list of Zulip %s" % (key,))
return ret[key]
if options.mode == 'public':
stream_infos = get_stream_infos("streams", zulip.client.get_streams)
else:
stream_infos = get_stream_infos("subscriptions", zulip.client.list_subscriptions)
rooms = []
for stream_info in stream_infos:
stream = stream_info['name']
if stream.endswith("/xmpp"):
rooms.append(stream_to_room(stream))
return rooms
def config_error(msg):
sys.stderr.write("%s\n" % (msg,))
sys.exit(2)
if __name__ == '__main__':
parser = optparse.OptionParser(epilog=
'''Most general and Jabber configuration options may also be specified in the
zulip configuration file under the jabber_mirror section (exceptions are noted
in their help sections). Keys have the same name as options with hyphens
replaced with underscores. Zulip configuration options go in the api section,
as normal.'''.replace("\n", " ")
)
parser.add_option('--mode',
default=None,
action='store',
help= \
'''Which mode to run in. Valid options are "personal" and "public". In
"personal" mode, the mirror uses an individual users' credentials and mirrors
all messages they send on Zulip to Jabber and all private Jabber messages to
Zulip. In "public" mode, the mirror uses the credentials for a dedicated mirror
user and mirrors messages sent to Jabber rooms to Zulip. Defaults to
"personal"'''.replace("\n", " "))
parser.add_option('--zulip-email-suffix',
default=None,
action='store',
help= \
'''Add the specified suffix to the local part of email addresses constructed
from JIDs and nicks before sending requests to the Zulip server, and remove the
suffix before sending requests to the Jabber server. For example, specifying
"+foo" will cause messages that are sent to the "bar" room by nickname "qux" to
be mirrored to the "bar/xmpp" stream in Zulip by user "qux+foo@example.com". This
option does not affect login credentials.'''.replace("\n", " "))
parser.add_option('-d', '--debug',
help='set logging to DEBUG. Can not be set via config file.',
action='store_const',
dest='log_level',
const=logging.DEBUG,
default=logging.INFO)
jabber_group = optparse.OptionGroup(parser, "Jabber configuration")
jabber_group.add_option('--jid',
default=None,
action='store',
help="Your Jabber JID. If a resource is specified, "
+ "it will be used as the nickname when joining MUCs. "
+ "Specifying the nickname is mostly useful if you want "
+ "to run the public mirror from a regular user instead of "
+ "from a dedicated account.")
jabber_group.add_option('--jabber-password',
default=None,
action='store',
help="Your Jabber password")
jabber_group.add_option('--conference-domain',
default=None,
action='store',
help="Your Jabber conference domain (E.g. conference.jabber.example.com). "
+ "If not specifed, \"conference.\" will be prepended to your JID's domain.")
jabber_group.add_option('--no-use-tls',
default=None,
action='store_true')
jabber_group.add_option('--jabber-server-address',
default=None,
action='store',
help="The hostname of your Jabber server. This is only needed if "
"your server is missing SRV records")
jabber_group.add_option('--jabber-server-port',
default='5222',
action='store',
help="The port of your Jabber server. This is only needed if "
"your server is missing SRV records")
parser.add_option_group(jabber_group)
parser.add_option_group(zulip.generate_option_group(parser, "zulip-"))
(options, args) = parser.parse_args()
logging.basicConfig(level=options.log_level,
format='%(levelname)-8s %(message)s')
if options.zulip_config_file is None:
config_file = zulip.get_default_config_filename()
else:
config_file = options.zulip_config_file
config = SafeConfigParser()
try:
with file(config_file, 'r') as f:
config.readfp(f, config_file)
except IOError:
pass
for option in ("jid", "jabber_password", "conference_domain", "mode", "zulip_email_suffix", "jabber_server_address", "jabber_server_port"):
if (getattr(options, option) is None
and config.has_option("jabber_mirror", option)):
setattr(options, option, config.get("jabber_mirror", option))
for option in ("no_use_tls",):
if getattr(options, option) is None:
if config.has_option("jabber_mirror", option):
setattr(options, option, config.getboolean("jabber_mirror", option))
else:
setattr(options, option, False)
if options.mode is None:
options.mode = "personal"
if options.zulip_email_suffix is None:
options.zulip_email_suffix = ''
if options.mode not in ('public', 'personal'):
config_error("Bad value for --mode: must be one of 'public' or 'personal'")
if None in (options.jid, options.jabber_password):
config_error("You must specify your Jabber JID and Jabber password either "
+ "in the Zulip configuration file or on the commandline")
zulip = ZulipToJabberBot(zulip.init_from_options(options, "JabberMirror/" + __version__))
# This won't work for open realms that don't have a consistent domain
options.zulip_domain = zulip.client.email.partition('@')[-1]
try:
jid = JID(options.jid)
except InvalidJID as e:
config_error("Bad JID: %s: %s" % (options.jid, e.message))
if options.conference_domain is None:
options.conference_domain = "conference.%s" % (jid.domain,)
xmpp = JabberToZulipBot(jid, options.jabber_password, get_rooms(zulip))
address = None
if options.jabber_server_address:
address = (options.jabber_server_address, options.jabber_server_port)
if not xmpp.connect(use_tls=not options.no_use_tls, address=address):
sys.exit("Unable to connect to Jabber server")
xmpp.set_zulip_client(zulip)
zulip.set_jabber_client(xmpp)
xmpp.process(block=False)
if options.mode == 'public':
event_types = ['stream']
else:
event_types = ['message', 'subscription']
try:
logging.info("Connecting to Zulip.")
zulip.client.call_on_each_event(zulip.process_event,
event_types=event_types)
except BaseException as e:
logging.exception("Exception in main loop")
xmpp.abort()
sys.exit(1)

View File

@@ -28,6 +28,7 @@ import traceback
import signal
from zephyr_mirror_backend import parse_args
from zephyr_mirror_backend import RandomExponentialBackoff
def die(signal, frame):
# We actually want to exit, so run os._exit (so as not to be caught and restarted)
@@ -37,9 +38,6 @@ signal.signal(signal.SIGINT, die)
(options, args) = parse_args()
sys.path[:0] = [os.path.join(options.root_path, 'api')]
from zulip import RandomExponentialBackoff
args = [os.path.join(options.root_path, "user_root", "zephyr_mirror_backend.py")]
args.extend(sys.argv[1:])
@@ -62,7 +60,7 @@ if options.forward_class_messages and not options.noshard:
pass
sys.exit(0)
backoff = RandomExponentialBackoff(timeout_success_equivalent=300)
backoff = RandomExponentialBackoff()
while backoff.keep_going():
print "Starting zephyr mirroring bot"
try:

View File

@@ -37,8 +37,39 @@ import signal
import logging
import hashlib
import tempfile
import random
import select
class CountingBackoff(object):
def __init__(self, maximum_retries=10):
self.number_of_retries = 0
self.maximum_retries = maximum_retries
def keep_going(self):
return self.number_of_retries < self.maximum_retries
def succeed(self):
self.number_of_retries = 0
def fail(self):
self.number_of_retries = min(self.number_of_retries + 1,
self.maximum_retries)
class RandomExponentialBackoff(CountingBackoff):
def fail(self):
self.number_of_retries = min(self.number_of_retries + 1,
self.maximum_retries)
# Exponential growth with ratio sqrt(2); compute random delay
# between x and 2x where x is growing exponentially
delay_scale = int(2 ** (self.number_of_retries / 2.0 - 1)) + 1
delay = delay_scale + random.randint(1, delay_scale)
message = "Sleeping for %ss [max %s] before retrying." % (delay, delay_scale * 2)
try:
logger.warning(message)
except NameError:
print message
time.sleep(delay)
DEFAULT_SITE = "https://api.zulip.com"
class States:
@@ -370,7 +401,7 @@ def process_notice(notice, log):
if is_personal:
if body.startswith("CC:"):
is_huddle = True
# Map "CC: user1 user2" => "user1@mit.edu, user2@mit.edu"
# Map "CC: sipbtest espuser" => "starnine@mit.edu,espuser@mit.edu"
huddle_recipients = [to_zulip_username(x.strip()) for x in
body.split("\n")[0][4:].split()]
if notice.sender not in huddle_recipients:
@@ -447,7 +478,7 @@ def quit_failed_initialization(message):
sys.exit(1)
def zephyr_init_autoretry():
backoff = zulip.RandomExponentialBackoff()
backoff = RandomExponentialBackoff()
while backoff.keep_going():
try:
# zephyr.init() tries to clear old subscriptions, and thus
@@ -462,7 +493,7 @@ def zephyr_init_autoretry():
quit_failed_initialization("Could not initialize Zephyr library, quitting!")
def zephyr_load_session_autoretry(session_path):
backoff = zulip.RandomExponentialBackoff()
backoff = RandomExponentialBackoff()
while backoff.keep_going():
try:
session = file(session_path, "r").read()
@@ -477,7 +508,7 @@ def zephyr_load_session_autoretry(session_path):
quit_failed_initialization("Could not load saved Zephyr session, quitting!")
def zephyr_subscribe_autoretry(sub):
backoff = zulip.RandomExponentialBackoff()
backoff = RandomExponentialBackoff()
while backoff.keep_going():
try:
zephyr.Subscriptions().add(sub)
@@ -598,9 +629,7 @@ Feedback button or at support@zulip.com."""
wrapped_content = "\n".join("\n".join(wrapper.wrap(line))
for line in message["content"].replace("@", "@@").split("\n"))
zwrite_args = ["zwrite", "-n", "-s", message["sender_full_name"],
"-F", "Zephyr error: See http://zephyr.1ts.org/wiki/df",
"-x", "UTF-8"]
zwrite_args = ["zwrite", "-n", "-s", message["sender_full_name"], "-F", "Zephyr error: See http://zephyr.1ts.org/wiki/df"]
# Hack to make ctl's fake username setup work :)
if message['type'] == "stream" and zulip_account_email == "ctl@mit.edu":
@@ -734,7 +763,7 @@ def maybe_forward_to_zephyr(message):
logger.exception("Error forwarding message:")
def zulip_to_zephyr(options):
# Sync messages from zulip to zephyr
# Sync messages from zephyr to zulip
logger.info("Starting syncing messages.")
while True:
try:

View File

@@ -1,5 +1,5 @@
[program:zmirror-USERNAME]
command=python /home/zulip/zulip/bots/zephyr_mirror_backend.py --root-path=/home/zulip/zulip --user=USERNAME --log-path=/home/zulip/logs/mirror-log-%(program_name)s --use-sessions --session-path=/home/zulip/zephyr_sessions/%(program_name)s --api-key-file=/home/zulip/api-keys/%(program_name)s --ignore-expired-tickets --nagios-path=/home/zulip/mirror_status/%(program_name)s --nagios-class=zulip-mirror-nagios
command=python /home/zulip/zulip/bots/zephyr_mirror_backend.py --root-path=/home/zulip/zulip/bots --user=USERNAME --log-path=/home/zulip/logs/mirror-log-%(program_name)s --use-sessions --session-path=/home/zulip/zephyr_sessions/%(program_name)s --api-key-file=/home/zulip/api-keys/%(program_name)s --ignore-expired-tickets --nagios-path=/home/zulip/mirror_status/%(program_name)s --nagios-class=zulip-mirror-nagios
priority=200 ; the relative start priority (default 999)
autostart=true ; start at supervisord start (default: true)
autorestart=true ; whether/when to restart (default: unexpected)

View File

@@ -39,4 +39,4 @@ def format_commit_message(author, subject, commit_id):
return '!avatar(%s) [%s](https://git.zulip.net/eng/zulip/commit/%s)\n' % (author, subject, commit_id)
ZULIP_API_PATH = "/home/zulip/zulip/api"
ZULIP_SITE = "https://zulip.com"
ZULIP_SITE = "https://staging.zulip.com"

View File

@@ -11,4 +11,4 @@ TRAC_BASE_TICKET_URL = "https://trac.zulip.net/ticket"
TRAC_NOTIFY_FIELDS = ["description", "summary", "resolution", "comment", "owner"]
ZULIP_API_PATH = "/home/zulip/zulip/api"
ZULIP_SITE = "https://zulip.com"
ZULIP_SITE = "https://staging.zulip.com"

View File

@@ -4,4 +4,4 @@
[api]
email = nagios-bot@zulip.com
key = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
site = https://zulip.com
site = https://staging.zulip.com

View File

@@ -1,29 +1,45 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(migrations.Migration):
class Migration(SchemaMigration):
dependencies = [
('contenttypes', '0001_initial'),
]
def forwards(self, orm):
# Adding model 'Confirmation'
db.create_table('confirmation_confirmation', (
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('content_type', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['contenttypes.ContentType'])),
('object_id', self.gf('django.db.models.fields.PositiveIntegerField')()),
('date_sent', self.gf('django.db.models.fields.DateTimeField')()),
('confirmation_key', self.gf('django.db.models.fields.CharField')(max_length=40)),
))
db.send_create_signal('confirmation', ['Confirmation'])
operations = [
migrations.CreateModel(
name='Confirmation',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('object_id', models.PositiveIntegerField()),
('date_sent', models.DateTimeField(verbose_name='sent')),
('confirmation_key', models.CharField(max_length=40, verbose_name='activation key')),
('content_type', models.ForeignKey(to='contenttypes.ContentType')),
],
options={
'verbose_name': 'confirmation email',
'verbose_name_plural': 'confirmation emails',
},
bases=(models.Model,),
),
]
def backwards(self, orm):
# Deleting model 'Confirmation'
db.delete_table('confirmation_confirmation')
models = {
'confirmation.confirmation': {
'Meta': {'object_name': 'Confirmation'},
'confirmation_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
'date_sent': ('django.db.models.fields.DateTimeField', [], {}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'object_id': ('django.db.models.fields.PositiveIntegerField', [], {})
},
'contenttypes.contenttype': {
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
}
}
complete_apps = ['confirmation']

View File

@@ -34,10 +34,9 @@ def generate_key():
return generate_random_token(40)
def generate_activation_url(key):
return u'%s%s%s' % (settings.EXTERNAL_URI_SCHEME,
settings.EXTERNAL_HOST,
reverse('confirmation.views.confirm',
kwargs={'confirmation_key': key}))
current_site = Site.objects.get_current()
return u'https://%s%s' % (current_site.domain,
reverse('confirmation.views.confirm', kwargs={'confirmation_key': key}))
class ConfirmationManager(models.Manager):
@@ -49,7 +48,7 @@ class ConfirmationManager(models.Manager):
except self.model.DoesNotExist:
return False
obj = confirmation.content_object
status_field = get_status_field(obj._meta.app_label, obj._meta.model_name)
status_field = get_status_field(obj._meta.app_label, obj._meta.module_name)
setattr(obj, status_field, getattr(settings, 'STATUS_ACTIVE', 1))
obj.save()
return obj
@@ -75,7 +74,7 @@ class ConfirmationManager(models.Manager):
if additional_context is not None:
context.update(additional_context)
templates = [
'confirmation/%s_confirmation_email_subject.txt' % obj._meta.model_name,
'confirmation/%s_confirmation_email_subject.txt' % obj._meta.module_name,
'confirmation/confirmation_email_subject.txt',
]
if subject_template_path:
@@ -84,7 +83,7 @@ class ConfirmationManager(models.Manager):
template = loader.select_template(templates)
subject = template.render(context).strip().replace(u'\n', u' ') # no newlines, please
templates = [
'confirmation/%s_confirmation_email_body.txt' % obj._meta.model_name,
'confirmation/%s_confirmation_email_body.txt' % obj._meta.module_name,
'confirmation/confirmation_email_body.txt',
]
if body_template_path:

View File

@@ -31,13 +31,13 @@ def confirm(request, confirmation_key):
'key': confirmation_key,
'full_name': request.GET.get("full_name", None),
'support_email': settings.ZULIP_ADMINISTRATOR,
'voyager': settings.VOYAGER
'enterprise': settings.ENTERPRISE
}
templates = [
'confirmation/confirm.html',
]
if obj:
# if we have an object, we can use specific template
templates.insert(0, 'confirmation/confirm_%s.html' % obj._meta.model_name)
templates.insert(0, 'confirmation/confirm_%s.html' % obj._meta.module_name)
return render_to_response(templates, ctx,
context_instance=RequestContext(request))

View File

@@ -2,8 +2,20 @@ from django.conf.urls import patterns, url
from django.views.generic import TemplateView, RedirectView
urlpatterns = patterns('',
# Job postings
url(r'^jobs/$', TemplateView.as_view(template_name='corporate/jobs/index.html')),
url(r'^jobs/lead-designer/$', TemplateView.as_view(template_name='corporate/jobs/lead-designer.html')),
# Zephyr/MIT
url(r'^zephyr/$', TemplateView.as_view(template_name='corporate/zephyr.html')),
url(r'^mit/$', TemplateView.as_view(template_name='corporate/mit.html')),
url(r'^zephyr-mirror/$', TemplateView.as_view(template_name='corporate/zephyr-mirror.html')),
# Marketing
url(r'^compare/$', TemplateView.as_view(template_name='corporate/compare.html')),
# signup form
url(r'^signup/$', TemplateView.as_view(template_name='corporate/signup.html'),
name='signup'),
# TODO: The beta signup view should probably be moved to corporate.
url(r'^signup/sign-me-up$', 'zerver.views.beta_signup_submission', name='beta-signup-submission'),
)

1
docs/.gitignore vendored
View File

@@ -1 +0,0 @@
_build

View File

@@ -1,192 +0,0 @@
# Makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
PAPER =
BUILDDIR = _build
# User-friendly check for sphinx-build
ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
endif
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
# the i18n builder cannot share the environment and doctrees with the others
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest coverage gettext
help:
@echo "Please use \`make <target>' where <target> is one of"
@echo " html to make standalone HTML files"
@echo " dirhtml to make HTML files named index.html in directories"
@echo " singlehtml to make a single large HTML file"
@echo " pickle to make pickle files"
@echo " json to make JSON files"
@echo " htmlhelp to make HTML files and a HTML help project"
@echo " qthelp to make HTML files and a qthelp project"
@echo " applehelp to make an Apple Help Book"
@echo " devhelp to make HTML files and a Devhelp project"
@echo " epub to make an epub"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
@echo " latexpdf to make LaTeX files and run them through pdflatex"
@echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
@echo " text to make text files"
@echo " man to make manual pages"
@echo " texinfo to make Texinfo files"
@echo " info to make Texinfo files and run them through makeinfo"
@echo " gettext to make PO message catalogs"
@echo " changes to make an overview of all changed/added/deprecated items"
@echo " xml to make Docutils-native XML files"
@echo " pseudoxml to make pseudoxml-XML files for display purposes"
@echo " linkcheck to check all external links for integrity"
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
@echo " coverage to run coverage check of the documentation (if enabled)"
clean:
rm -rf $(BUILDDIR)/*
html:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
dirhtml:
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
singlehtml:
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
@echo
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
pickle:
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
@echo
@echo "Build finished; now you can process the pickle files."
json:
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
@echo
@echo "Build finished; now you can process the JSON files."
htmlhelp:
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in $(BUILDDIR)/htmlhelp."
qthelp:
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/zulip-contributor-docs.qhcp"
@echo "To view the help file:"
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/zulip-contributor-docs.qhc"
applehelp:
$(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp
@echo
@echo "Build finished. The help book is in $(BUILDDIR)/applehelp."
@echo "N.B. You won't be able to view it unless you put it in" \
"~/Library/Documentation/Help or install it in your application" \
"bundle."
devhelp:
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
@echo
@echo "Build finished."
@echo "To view the help file:"
@echo "# mkdir -p $$HOME/.local/share/devhelp/zulip-contributor-docs"
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/zulip-contributor-docs"
@echo "# devhelp"
epub:
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
@echo
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
latex:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
@echo "Run \`make' in that directory to run these through (pdf)latex" \
"(use \`make latexpdf' here to do that automatically)."
latexpdf:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through pdflatex..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
latexpdfja:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through platex and dvipdfmx..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
text:
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
@echo
@echo "Build finished. The text files are in $(BUILDDIR)/text."
man:
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
@echo
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
texinfo:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
@echo "Run \`make' in that directory to run these through makeinfo" \
"(use \`make info' here to do that automatically)."
info:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo "Running Texinfo files through makeinfo..."
make -C $(BUILDDIR)/texinfo info
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
gettext:
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
@echo
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
changes:
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
@echo
@echo "The overview file is in $(BUILDDIR)/changes."
linkcheck:
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in $(BUILDDIR)/linkcheck/output.txt."
doctest:
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
@echo "Testing of doctests in the sources finished, look at the " \
"results in $(BUILDDIR)/doctest/output.txt."
coverage:
$(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage
@echo "Testing of coverage in the sources finished, look at the " \
"results in $(BUILDDIR)/coverage/python.txt."
xml:
$(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
@echo
@echo "Build finished. The XML files are in $(BUILDDIR)/xml."
pseudoxml:
$(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
@echo
@echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."

View File

@@ -1,23 +0,0 @@
These docs are written in rST, and are included on the zulip.org website
as well as on each development installation. Many of these docs
have been ported from the internal docs of Zulip Inc.,
and may need to be updated for use in the open source project.
To generate HTML docs locally from rST:
* `pip install sphinx`
* In this directory, `make html`. Output appears in a `_build/html` subdirectory.
To create rST from MediaWiki input:
* Use `pandoc -r mediawiki -w rst` on MediaWiki source.
* Use unescape.py to remove any leftover HTML entities (often inside <pre>
tags and the like).
We can use pandoc to translate mediawiki into reStructuredText, but some things need fixing up:
* Add page titles.
* Review pages for formatting (especially inline code chunks) and content.
* Fix wiki links?
* Add pages to the table of contents (`index.rst`).

View File

@@ -1,10 +0,0 @@
/* override table width restrictions */
.wy-table-responsive table td, .wy-table-responsive table th {
/* !important prevents the common CSS stylesheets from
overriding this as on RTD they are loaded after this stylesheet */
white-space: normal !important;
}
.wy-table-responsive {
overflow: visible !important;
}

View File

@@ -1,484 +0,0 @@
==========================
Code style and conventions
==========================
Be consistent!
==============
Look at the surrounding code, or a similar part of the project, and
try to do the same thing. If you think the other code has actively bad
style, fix it (in a separate commit).
When in doubt, send an email to zulip-devel@googlegroups.com with your
question.
Lint tools
==========
You can run them all at once with
::
./tools/lint-all
You can set this up as a local Git commit hook with
::
``tools/setup-git-repo``
The Vagrant setup process runs this for you.
``lint-all`` runs many lint checks in parallel, including
- Javascript (`JSLint <http://www.jslint.com/>`__)
``tools/jslint/check-all.js`` contains a pretty fine-grained set of
JSLint options, rule exceptions, and allowed global variables. If you
add a new global, you'll need to add it to the list.
- Python (`Pyflakes <http://pypi.python.org/pypi/pyflakes>`__)
- templates
- Puppet configuration
- custom checks (e.g. trailing whitespace and spaces-not-tabs)
Secrets
=======
Please don't put any passwords, secret access keys, etc. inline in the
code. Instead, use the ``get_secret`` function in
``zproject/settings.py`` to read secrets from ``/etc/zulip/secrets.conf``.
Dangerous constructs
====================
Misuse of database queries
--------------------------
Look out for Django code like this::
[Foo.objects.get(id=bar.x.id)
for bar in Bar.objects.filter(...)
if  bar.baz < 7]
This will make one database query for each ``Bar``, which is slow in
production (but not in local testing!). Instead of a list comprehension,
write a single query using Django's `QuerySet
API <https://docs.djangoproject.com/en/dev/ref/models/querysets/>`__.
If you can't rewrite it as a single query, that's a sign that something
is wrong with the database schema. So don't defer this optimization when
performing schema changes, or else you may later find that it's
impossible.
UserProfile.objects.get() / Client.objects.get / etc.
-----------------------------------------------------
In our Django code, never do direct
``UserProfile.objects.get(email=foo)`` database queries. Instead always
use ``get_user_profile_by_{email,id}``. There are 3 reasons for this:
#. It's guaranteed to correctly do a case-inexact lookup
#. It fetches the user object from memcached, which is faster
#. It always fetches a UserProfile object which has been queried using
.selected\_related(), and thus will perform well when one later
accesses related models like the Realm.
Similarly we have ``get_client`` and ``get_stream`` functions to fetch
those commonly accessed objects via memcached.
Using Django model objects as keys in sets/dicts
------------------------------------------------
Don't use Django model objects as keys in sets/dictionaries -- you will
get unexpected behavior when dealing with objects obtained from
different database queries:
For example,
``UserProfile.objects.only("id").get(id=17) in set([UserProfile.objects.get(id=17)])``
is False
You should work with the IDs instead.
user\_profile.save()
--------------------
You should always pass the update\_fields keyword argument to .save()
when modifying an existing Django model object. By default, .save() will
overwrite every value in the column, which results in lots of race
conditions where unrelated changes made by one thread can be
accidentally overwritten by another thread that fetched its UserProfile
object before the first thread wrote out its change.
Using raw saves to update important model objects
-------------------------------------------------
In most cases, we already have a function in zephyr/lib/actions.py with
a name like do\_activate\_user that will correctly handle lookups,
caching, and notifying running browsers via the event system about your
change. So please check whether such a function exists before writing
new code to modify a model object, since your new code has a good chance
of getting at least one of these things wrong.
``x.attr('zid')`` vs. ``rows.id(x)``
------------------------------------
Our message row DOM elements have a custom attribute ``zid`` which
contains the numerical message ID. **Don't access this directly as**
``x.attr('zid')`` ! The result will be a string and comparisons (e.g.
with ``<=``) will give the wrong result, occasionally, just enough to
make a bug that's impossible to track down.
You should instead use the ``id`` function from the ``rows`` module, as
in ``rows.id(x)``. This returns a number. Even in cases where you do
want a string, use the ``id`` function, as it will simplify future code
changes. In most contexts in JavaScript where a string is needed, you
can pass a number without any explicit conversion.
Javascript var
--------------
Always declare Javascript variables using ``var``::
var x = ...;
In a function, ``var`` is necessary or else ``x`` will be a global
variable. For variables declared at global scope, this has no effect,
but we do it for consistency.
Javascript has function scope only, not block scope. This means that a
``var`` declaration inside a ``for`` or ``if`` acts the same as a
``var`` declaration at the beginning of the surrounding ``function``. To
avoid confusion, declare all variables at the top of a function.
Javascript ``for (i in myArray)``
---------------------------------
Don't use it:
`[1] <http://stackoverflow.com/questions/500504/javascript-for-in-with-arrays>`__,
`[2] <http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml#for-in_loop>`__,
`[3] <http://www.jslint.com/lint.html#forin>`__
jQuery global state
-------------------
Don't mess with jQuery global state once the app has loaded. Code like
this is very dangerous::
$.ajaxSetup({ async: false });
$.get(...);
$.ajaxSetup({ async: true });
jQuery and the browser are free to run other code while the request is
pending, which could perform other Ajax requests with the altered
settings.
Instead, switch to the more general |ajax|_ function, which can take options
like ``async``.
.. |ajax| replace:: ``$.ajax``
.. _ajax: http://api.jquery.com/jQuery.ajax
State and logs files
--------------------
Do not write state and logs files inside the current working directory
in the production environment. This will not how you expect, because the
current working directory for the app changes every time we do a deploy.
Instead, hardcode a path in settings.py -- see SERVER\_LOG\_PATH in
settings.py for an example.
JS array/object manipulation
============================
For generic functions that operate on arrays or JavaScript objects, you
should generally use `Underscore <http://underscorejs.org/>`__. We used
to use jQuery's utility functions, but the Underscore equivalents are
more consistent, better-behaved and offer more choices.
A quick conversion table::
   $.each  _.each (parameters to the callback reversed)
   $.inArray  _.indexOf (parameters reversed)
   $.grep  _.filter
   $.map  _.map
   $.extend  _.extend
There's a subtle difference in the case of ``_.extend``; it will replace
attributes with undefined, whereas jQuery won't::
   $.extend({foo: 2}, {foo: undefined});  // yields {foo: 2}, BUT...
   _.extend({foo: 2}, {foo: undefined});  // yields {foo: undefined}!
Also, ``_.each`` does not let you break out of the iteration early by
returning false, the way jQuery's version does. If you're doing this,
you probably want ``_.find``, ``_.every``, or ``_.any``, rather than
'each'.
Some Underscore functions have multiple names. You should always use the
canonical name (given in large print in the Underscore documentation),
with the exception of ``_.any``, which we prefer over the less clear
'some'.
More arbitrary style things
===========================
General
-------
Indentation is four space characters for Python, JS, CSS, and shell
scripts. Indentation is two space characters for HTML templates.
We never use tabs anywhere in source code we write, but we have some
third-party files which contain tabs.
Keep third-party static files under the directory
``zephyr/static/third/``, with one subdirectory per third-party project.
We don't have an absolute hard limit on line length, but we should avoid
extremely long lines. A general guideline is: refactor stuff to get it
under 85 characters, unless that makes the code a lot uglier, in which
case it's fine to go up to 120 or so.
Whitespace guidelines:
- Put one space (or more for alignment) around binary arithmetic and
equality operators.
- Put one space around each part of the ternary operator.
- Put one space between keywords like ``if`` and ``while`` and their
associated open paren.
- Put one space between the closing paren for ``if`` and ``while``-like
constructs and the opening curly brace. Put the curly brace on the
same line unless doing otherwise improves readability.
- Put no space before or after the open paren for function calls and no
space before the close paren for function calls.
- For the comma operator and colon operator in languages where it is
used for inline dictionaries, put no space before it and at least one
space after. Only use more than one space for alignment.
Javascript
----------
Don't use ``==`` and ``!=`` because these operators perform type
coercions, which can mask bugs. Always use ``===`` and ``!==``.
End every statement with a semicolon.
``if`` statements with no braces are allowed, if the body is simple and
its extent is abundantly clear from context and formatting.
Anonymous functions should have spaces before and after the argument
list::
var x = function (foo, bar) { // ...
When calling a function with an anonymous function as an argument, use
this style::
$.get('foo', function (data) {
    var x = ...;
    // ...
});
The inner function body is indented one level from the outer function
call. The closing brace for the inner function and the closing
parenthesis for the outer call are together on the same line. This style
isn't necessarily appropriate for calls with multiple anonymous
functions or other arguments following them.
Use
::
$(function () { ...
rather than
::
$(document).ready(function () { ...
and combine adjacent on-ready functions, if they are logically related.
The best way to build complicated DOM elements is a Mustache template
like ``zephyr/static/templates/message.handlebars``. For simpler things
you can use jQuery DOM building APIs like so::
var new_tr = $('<tr />').attr('id', zephyr.id);
Passing a HTML string to jQuery is fine for simple hardcoded things::
foo.append('<p id="selected">foo</p>');
but avoid programmatically building complicated strings.
We used to favor attaching behaviors in templates like so::
<p onclick="select_zephyr({{id}})">
but there are some reasons to prefer attaching events using jQuery code:
- Potential huge performance gains by using delegated events where
possible
- When calling a function from an ``onclick`` attribute, ``this`` is
not bound to the element like you might think
- jQuery does event normalization
Either way, avoid complicated JavaScript code inside HTML attributes;
call a helper function instead.
HTML / CSS
----------
Don't use the ``style=`` attribute. Instead, define logical classes and
put your styles in ``zulip.css``.
Don't use the tag name in a selector unless you have to. In other words,
use ``.foo`` instead of ``span.foo``. We shouldn't have to care if the
tag type changes in the future.
Don't use inline event handlers (``onclick=``, etc. attributes).
Instead, attach a jQuery event handler
(``$('#foo').on('click', function () {...})``) when the DOM is ready
(inside a ``$(function () {...})`` block).
Use this format when you have the same block applying to multiple CSS
styles (separate lines for each selector)::
selector1,
selector2 {
};
Python
------
- Scripts should start with ``#!/usr/bin/env python`` and not
``#!/usr/bin/python``. See commit ``437d4aee`` for an explanation of
why. Don't put such a line on a Python file unless it's meaningful to
run it as a script. (Some libraries can also be run as scripts, e.g.
to run a test suite.)
- The first import in a file should be
``from __future__ import absolute_import``, per `PEP
328 <http://docs.python.org/2/whatsnew/2.5.html#pep-328-absolute-and-relative-imports>`__
- Put all imports together at the top of the file, absent a compelling
reason to do otherwise.
- Unpacking sequences doesn't require list brackets::
[x, y] = xs    # unnecessary
x, y = xs      # better
- For string formatting, use ``x % (y,)`` rather than ``x % y``, to
avoid ambiguity if ``y`` happens to be a tuple.
- When selecting by id, don't use ``foo.pk`` when you mean ``foo.id``.
E.g.
::
recipient = Recipient(type_id=huddle.pk, type=Recipient.HUDDLE)
should be written as
::
recipient = Recipient(type_id=huddle.id, type=Recipient.HUDDLE)
in case we ever change the primary keys.
Version Control
===============
Commit Discipline
-----------------
We follow the Git project's own commit discipline practice of "Each
commit is a minimal coherent idea".
Coherency requirements for any commit:
- It should pass tests (so test updates needed by a change should be in
the same commit as the original change, not a separate "fix the tests
that were broken by the last commit" commit).
- It should be safe to deploy individually, or comment in detail in the
commit message as to why it isn't (maybe with a [manual] tag). So
implementing a new API endpoint in one commit and then adding the
security checks in a future commit should be avoided -- the security
checks should be there from the beginning.
- Error handling should generally be included along with the code that
might trigger the error.
- TODO comments should be in the commit that introduces the
issue or functionality with further work required.
When you should be minimal:
- Significant refactorings should be done in a separate commit from
functional changes.
- Moving code from one file to another should be done in a separate
commits from functional changes or even refactoring within a file.
- 2 different refactorings should be done in different commits.
- 2 different features should be done in different commits.
- If you find yourself writing a commit message that reads like a list
of somewhat dissimilar things that you did, you probably should have
just done 2 commits.
When not to be overly minimal:
- For completely new features, you don't necessarily need to split out
new commits for each little subfeature of the new feature. E.g. if
you're writing a new tool from scratch, it's fine to have the initial
tool have plenty of options/features without doing separate commits
for each one. That said, reviewing a 2000-line giant blob of new
code isn't fun, so please be thoughtful about submitting things in
reviewable units.
- Don't bother to split back end commits from front end commits, even
though the backend can often be coherent on its own.
Other considerations:
- Overly fine commits are easily squashed, but not vice versa, so err
toward small commits, and the code reviewer can advise on squashing.
It can take some practice to get used to writing your commits this
way. For example, often you'll start adding a feature, and discover
you need to a refactoring partway through writing the feature. When
that happens, we recommend stashing your partial feature, do the
refactoring, commit it, and then finish implementing your feature.
Commit Messages
---------------
- The first line of commit messages should be written in the imperative
and be kept relatively short while concisely explaining what the
commit does. For example:
Bad::
bugfix
gather_subscriptions was broken
Good::
Prevent gather_subscriptions from throwing an exception when given bad input.
- Please use a complete sentence, ending with a period.
- The rest of the commit message should be written in full prose and
explain why and how the change was made. If the commit makes
performance improvements, you should generally include some rough
benchmarks showing that it actually improves the performance.
- In your commit message, you should describe any manual testing you
did in addition to running the automated tests, and any aspects of
the commit that you think are questionable and you'd like special
attention applied to.
Tests
-----
All significant new features should come with tests.
Third party code
----------------
When adding new third-party packages to our codebase, please include
"[third]" at the beginning of the commit message. You don't necessarily
need to do this when patching third-party code that's already in tree.

View File

@@ -1,295 +0,0 @@
# -*- coding: utf-8 -*-
#
# zulip-contributor-docs documentation build configuration file, created by
# sphinx-quickstart on Mon Aug 17 16:24:04 2015.
#
# This file is execfile()d with the current directory set to its
# containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
import sys
import os
import shlex
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#sys.path.insert(0, os.path.abspath('.'))
# -- General configuration ------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = []
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:
# source_suffix = ['.rst', '.md']
source_suffix = '.rst'
# The encoding of source files.
#source_encoding = 'utf-8-sig'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = u'Zulip'
copyright = u'2015, The Zulip Team'
author = u'The Zulip Team'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = '0.1'
# The full version, including alpha/beta/rc tags.
release = '0.1'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
#today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ['_build']
# The reST default role (used for this markup: `text`) to use for all
# documents.
#default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []
# If true, keep warnings as "system message" paragraphs in the built documents.
#keep_warnings = False
# If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos = False
# -- Options for HTML output ----------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
# Read The Docs can't import sphinx_rtd_theme, so don't import it there.
on_rtd = os.environ.get('READTHEDOCS', None) == 'True'
if not on_rtd:
import sphinx_rtd_theme
html_theme = 'sphinx_rtd_theme'
html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
#html_theme_path = []
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
#html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
#html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#html_logo = None
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# Add any extra paths that contain custom files (such as robots.txt or
# .htaccess) here, relative to this directory. These files are copied
# directly to the root of the documentation.
#html_extra_path = []
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}
# If false, no module index is generated.
#html_domain_indices = True
# If false, no index is generated.
#html_use_index = True
# If true, the index is split into individual pages for each letter.
#html_split_index = False
# If true, links to the reST sources are added to the pages.
#html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
#html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
#html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = None
# Language to be used for generating the HTML full-text search index.
# Sphinx supports the following languages:
# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja'
# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr'
#html_search_language = 'en'
# A dictionary with options for the search language support, empty by default.
# Now only 'ja' uses this config value
#html_search_options = {'type': 'default'}
# The name of a javascript file (relative to the configuration directory) that
# implements a search results scorer. If empty, the default will be used.
#html_search_scorer = 'scorer.js'
# Output file base name for HTML help builder.
htmlhelp_basename = 'zulip-contributor-docsdoc'
def setup(app):
# overrides for wide tables in RTD theme
app.add_stylesheet('theme_overrides.css') # path relative to _static
# -- Options for LaTeX output ---------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#'preamble': '',
# Latex figure (float) alignment
#'figure_align': 'htbp',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
(master_doc, 'zulip-contributor-docs.tex', u'Zulip Documentation',
u'The Zulip Team', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False
# If true, show page references after internal links.
#latex_show_pagerefs = False
# If true, show URL addresses after external links.
#latex_show_urls = False
# Documents to append as an appendix to all manuals.
#latex_appendices = []
# If false, no module index is generated.
#latex_domain_indices = True
# -- Options for manual page output ---------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
(master_doc, 'zulip-contributor-docs', u'Zulip Documentation',
[author], 1)
]
# If true, show URL addresses after external links.
#man_show_urls = False
# -- Options for Texinfo output -------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
(master_doc, 'zulip-contributor-docs', u'Zulip Documentation',
author, 'zulip-contributor-docs', 'Documentation for contributing to Zulip.',
'Miscellaneous'),
]
# Documents to append as an appendix to all manuals.
#texinfo_appendices = []
# If false, no module index is generated.
#texinfo_domain_indices = True
# How to display URL addresses: 'footnote', 'no', or 'inline'.
#texinfo_show_urls = 'footnote'
# If true, do not generate a @detailmenu in the "Top" node's menu.
#texinfo_no_detailmenu = False

View File

@@ -1,95 +0,0 @@
===================
Directory structure
===================
This page documents the Zulip directory structure and how to decide where to
put a file.
Scripts
=======
+--------------------+-----------------------------------------------------------------------------------+
| ``scripts/`` | Scripts that production deployments might run manually (e.g. ``restart-server``) |
+--------------------+-----------------------------------------------------------------------------------+
| ``bin/`` | Scripts that are needed on production deployments but humans should never run |
+--------------------+-----------------------------------------------------------------------------------+
| ``scripts/setup/`` | Tools that production deployments will only run once, during installation |
+--------------------+-----------------------------------------------------------------------------------+
| ``tools/`` | Development tools |
+--------------------+-----------------------------------------------------------------------------------+
Bots
====
+------------------------+----------------------------------------------------------------------+
| ``api/integrations`` | Bots distributed as part of the Zulip API bundle. |
+------------------------+----------------------------------------------------------------------+
| ``bots/`` | Previously Zulip internal bots. These usually need a bit of work. |
+------------------------+----------------------------------------------------------------------+
Management commands
===================
+-------------------------------------+------------------------------------------------------------------------------------------------------------------------------------+
| ``zerver/management/commands/`` | Management commands one might run at a production deployment site (e.g. scripts to change a value or deactivate a user properly) |
+-------------------------------------+------------------------------------------------------------------------------------------------------------------------------------+
Views
=====
+--------------------------------+-----------------------------------------+
| ``zerver/tornadoviews.py`` | Tornado views |
+--------------------------------+-----------------------------------------+
| ``zerver/views/webhooks.py`` | Webhook views |
+--------------------------------+-----------------------------------------+
| ``zerver/views/messages.py`` | message-related views |
+--------------------------------+-----------------------------------------+
| ``zerver/views/__init__.py`` | other Django views |
+--------------------------------+-----------------------------------------+
Static assets
=============
+---------------+---------------------------------------------------------------------------------------------------------------+
| ``assets/`` | For assets not to be served to the web (e.g. the system to generate our favicons) |
+---------------+---------------------------------------------------------------------------------------------------------------+
| ``static/`` | For things we do want to both serve to the web and distribute to production deployments (e.g. the webpages) |
+---------------+---------------------------------------------------------------------------------------------------------------+
Puppet
======
+--------------------+----------------------------------------------------------------------------------+
| ``puppet/zulip`` | For configuration for production deployments |
+--------------------+----------------------------------------------------------------------------------+
Templates
=========
+--------------------------+--------------------------------------------------------+
| ``templates/zerver`` | For templates related to zerver views |
+--------------------------+--------------------------------------------------------+
| ``static/templates`` | Handlebars templates for the frontend |
+--------------------------+--------------------------------------------------------+
Tests
=====
+------------------------+-----------------------------------+
| ``zerver/test*.py`` | Backend tests | |
+------------------------+-----------------------------------+
| ``zerver/tests/frontend/node`` | Node Frontend unit tests |
+------------------------+-----------------------------------+
| ``zerver/tests/frontend/tests`` | Casper frontend tests |
+------------------------+-----------------------------------+
Documentation
=============
+-------------+-----------------------------------------------+
| ``docs/`` | Source for this documentation |
+-------------+-----------------------------------------------+
You can consult the repository's .gitattributes file to see exactly
which components are excluded from production releases (release
tarballs are generated using tools/build-release-tarball).

View File

@@ -1,9 +0,0 @@
#!/usr/bin/env python3
# Remove HTML entity escaping left over from MediaWiki->rST conversion.
import html
import sys
for line in sys.stdin:
print(html.unescape(line), end='')

View File

@@ -1,25 +0,0 @@
.. zulip documentation master file, created by
sphinx-quickstart on Mon Aug 17 16:24:04 2015.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Welcome to Zulip documentation!
===============================
Contents:
.. toctree::
:maxdepth: 2
new-feature-tutorial
code-style
directory-structure
testing
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`

View File

@@ -1,85 +0,0 @@
====================
New Feature Tutorial
====================
.. attention::
This tutorial is an unfinished work -- contributions welcome!
The changes needed to add a new feature will vary, of course. We give an
example here that illustrates some of the common steps needed. We describe
the process of adding a new setting for admins that restricts inviting new
users to admins only.
Backend Changes
===============
Adding a field to the database
------------------------------
The server accesses the underlying database in `zerver/models.py`. Add
a new field in the appropriate class, `realm_invite_by_admins_only`
in the `Realm` class in this case.
Once you do so, you need to create the migration and run it; the
process is documented at:
https://docs.djangoproject.com/en/1.8/topics/migrations/
Once you've run the migration, to test your changes, you'll want to
restart memcached on your development server (``/etc/init.d/memcached restart``) and
then restart ``run-dev.py`` to avoid interacting with cached objects.
Backend changes
---------------
You should add code in `zerver/lib/actions.py` to interact with the database,
that actually updates the relevant field. In this case, `do_set_realm_invite_by_admins_only`
is a function that actually updates the field in the database, and sends
an event announcing that this change has been made.
You then need update the `fetch_initial_state_data` and `apply_events` functions
in `zerver/lib/actions.py` to update the state based on the event you just created.
In this case, we add a line
::
state['realm_invite_by_admins_only'] = user_profile.realm.invite_by_admins_only`
to the `fetch_initial_state_data` function. The `apply_events` function
doesn't need to be updated since
::
elif event['type'] == 'realm':
field = 'realm_' + event['property']
state[field] = event['value']
already took care of our event.
Then update `zerver/views/__init__.py` to actually call your function.
In the dictionary which sets the javascript `page_params` dictionary,
add a value for your feature.
::
realm_invite_by_admins_only = register_ret['realm_invite_by_admins_only']
Perhaps your new option controls some other backend rendering: in our case
we test for this option in the `home` method for adding a variable to the response.
The functions in this file control the generation of various pages served
(along with the Django templates).
Our new feature also shows up in the administration tab (as a checkbox),
so we need to update the `update_realm` function.
Finally, add tests for your backend changes; at the very least you
should add a test of your event data flowing through the system in
``test_events.py``.
Frontend changes
----------------
You need to change various things on the front end. In this case, the relevant files
are `static/js/server_events.js`, `static/js/admin.js`, `static/styles/zulip.css
and `static/templates/admin_tab.handlebars`.

View File

@@ -1 +0,0 @@
# Empty requirements.txt to avoid readthedocs installing all our dependencies.

View File

@@ -1,251 +0,0 @@
=======
Testing
=======
Running tests
=============
To run everything, just use ``./tools/test-all``. This runs lint checks,
web frontend / whole-system blackbox tests, and backend Django tests.
If you want to run individual parts, see the various commands inside
that script.
Schema and initial data changes
-------------------------------
If you change the database schema or change the initial test data, you
have have to regenerate the pristine test database by running
``tools/do-destroy-rebuild-test-database``.
Wiping the test databases
-------------------------
You should first try running: ``tools/do-destroy-rebuild-test-database``
If that fails you should try to do:
::
sudo -u postgres psql
> DROP DATABASE zulip_test;
> DROP DATABASE zulip_test_template;
and then run ``tools/do-destroy-rebuild-test-database``
Recreating the postgres cluster
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. warning::
**This is irreversible, so do it with care, and never do this anywhere
in production.**
If your postgres cluster (collection of databases) gets totally trashed
permissions-wise, and you can't otherwise repair it, you can recreate
it. On Ubuntu:
::
sudo pg_dropcluster --stop 9.1 main
sudo pg_createcluster --locale=en_US.utf8 --start 9.1 main
Backend Django tests
--------------------
These live in ``zerver/tests.py`` and ``zerver/test_*.py``. Run them
with ``tools/test-backend``.
Web frontend black-box tests
----------------------------
These live in ``zerver/tests/frontend/tests/``. This is a "black box"
test; we load the frontend in a real (headless) browser, from a real dev
server, and simulate UI interactions like sending messages, narrowing,
etc.
Since this is interacting with a real dev server, it can catch backend
bugs as well.
You can run this with ``./zerver/tests/frontend/run``. You will need
`PhantomJS <http://phantomjs.org/>`__ 1.7.0 or later.
Debugging Casper.JS
~~~~~~~~~~~~~~~~~~~
Casper.js (via PhantomJS) has support for remote debugging. However, it
is not perfect. Here are some steps for using it and gotchas you might
want to know.
To turn on remote debugging, pass ``--remote-debug`` to the
``./zerver/frontend/tests/run`` script. This will run the tests with
port ``7777`` open for remote debugging. You can now connect to
``localhost:7777`` in a Webkit browser. Somewhat recent versions of
Chrome or Safari might be required.
- When connecting to the remote debugger, you will see a list of pages,
probably 2. One page called ``about:blank`` is the headless page in
which the CasperJS test itself is actually running in. This is where
your test code is.
- The other page, probably ``localhost:9981``, is the Zulip page that
the test is testing---that is, the page running our app that our test
is exercising.
Since the tests are now running, you can open the ``about:blank`` page,
switch to the Scripts tab, and open the running ``0x-foo.js`` test. If
you set a breakpoint and it is hit, the inspector will pause and you can
do your normal JS debugging. You can also put breakpoints in the Zulip
webpage itself if you wish to inspect the state of the Zulip frontend.
Web frontend unit tests
-----------------------
As an alternative to the black-box whole-app testing, you can unit test
individual JavaScript files that use the module pattern. For example, to
test the ``foobar.js`` file, you would first add the following to the
bottom of ``foobar.js``:
::
if (typeof module !== 'undefined') {
module.exports = foobar;
}
This makes ``foobar.js`` follow the CommonJS module pattern, so it can
be required in Node.js, which runs our tests.
Now create ``zerver/tests/frontend/node/foobar.js``. At the top, require
the `Node.js assert module <http://nodejs.org/api/assert.html>`__, and
the module you're testing, like so:
::
var assert = require('assert');
var foobar = require('js/foobar.js');
(If the module you're testing depends on other modules, or modifies
global state, you need to also read `the next section`__.)
__ handling-dependencies_
Define and call some tests using the `assert
module <http://nodejs.org/api/assert.html>`__. Note that for "equal"
asserts, the *actual* value comes first, the *expected* value second.
::
(function test_somefeature() {
assert.strictEqual(foobar.somefeature('baz'), 'quux');
assert.throws(foobar.somefeature('Invalid Input'));
}());
The test runner (index.js) automatically runs all .js files in the
zerver/tests/frontend/node directory.
.. _handling-dependencies:
Handling dependencies in tests
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The following scheme helps avoid tests leaking globals between each
other.
First, if you can avoid globals, do it, and the code that is directly
under test can simply be handled like this:
::
var search = require('js/search_suggestion.js');
For deeper dependencies, you want to categorize each module as follows:
- Exercise the module's real code for deeper, more realistic testing?
- Stub out the module's interface for more control, speed, and
isolation?
- Do some combination of the above?
For all the modules where you want to run actual code, add a statement
like the following to the top of your test file:
::
add_dependencies({
_: 'third/underscore/underscore.js',
util: 'js/util.js',
Dict: 'js/dict.js',
Handlebars: 'handlebars',
Filter: 'js/filter.js',
typeahead_helper: 'js/typeahead_helper.js',
stream_data: 'js/stream_data.js',
narrow: 'js/narrow.js'
});
For modules that you want to completely stub out, please use a pattern
like this:
::
set_global('page_params', {
email: 'bob@zulip.com'
});
// then maybe further down
global.page_params.email = 'alice@zulip.com';
Finally, there's the hybrid situation, where you want to borrow some of
a module's real functionality but stub out other pieces. Obviously, this
is a pretty strong smell that the other module might be lacking in
cohesion, but that code might be outside your jurisdiction. The pattern
here is this:
::
// Use real versions of parse/unparse
var narrow = require('js/narrow.js');
set_global('narrow', {
parse: narrow.parse,
unparse: narrow.unparse
});
// But later, I want to stub the stream without having to call super-expensive
// real code like narrow.activate().
global.narrow.stream = function () {
return 'office';
};
Coverage reports
~~~~~~~~~~~~~~~~
You can automatically generate coverage reports for the JavaScript unit
tests. To do so, install istanbul:
::
sudo npm install -g istanbul
And run test-js-with-node with the 'cover' parameter:
::
tools/test-js-with-node cover
Then open ``coverage/lcov-report/js/index.html`` in your browser.
Modules we don't test *at all* aren't listed in the report, so this
tends to overstate how good our overall coverage is, but it's accurate
for individual files. You can also click a filename to see the specific
statements and branches not tested. 100% branch coverage isn't
necessarily possible, but getting to at least 80% branch coverage is a
good goal.
Manual testing (local app + web browser)
========================================
Setting up the manual testing database
--------------------------------------
::
./tools/do-destroy-rebuild-database
Will populate your local database with all the usual accounts plus some
test messages involving Shakespeare characters.

0
humbug/__init__.py Normal file
View File

1
humbug/backends.py Symbolic link
View File

@@ -0,0 +1 @@
../zproject/backends.py

View File

@@ -1,169 +0,0 @@
import os
import sys
import logging
import platform
try:
import sh
except ImportError:
import pbs as sh
SUPPORTED_PLATFORMS = {
"Ubuntu": [
"trusty",
],
}
APT_DEPENDENCIES = {
"trusty": [
"closure-compiler",
"libffi-dev",
"memcached",
"rabbitmq-server",
"libldap2-dev",
"redis-server",
"postgresql-server-dev-all",
"libmemcached-dev",
"postgresql-9.3",
"python-dev",
"hunspell-en-us",
"nodejs",
"python-virtualenv",
"supervisor",
"git",
"npm",
"node-jquery",
"yui-compressor",
"puppet", # Used by lint-all
]
}
# TODO: backport node-{cssstyle,htmlparser2,nwmatcher} to trusty,
# so we can eliminate npm (above) and this section.
NPM_DEPENDENCIES = {
"trusty": [
"cssstyle",
"htmlparser2",
"nwmatcher",
]
}
VENV_PATH="/srv/zulip-venv"
ZULIP_PATH="/srv/zulip"
# tsearch-extras is an extension to postgres's built-in full-text search.
# TODO: use a real APT repository
TSEARCH_URL_BASE = "https://dl.dropboxusercontent.com/u/283158365/zuliposs/"
TSEARCH_PACKAGE_NAME = {
"trusty": "postgresql-9.3-tsearch-extras"
}
TSEARCH_VERSION = "0.1.2"
# TODO: this path is platform-specific!
TSEARCH_STOPWORDS_PATH = "/usr/share/postgresql/9.3/tsearch_data/"
REPO_STOPWORDS_PATH = os.path.join(
ZULIP_PATH,
"puppet",
"zulip",
"files",
"postgresql",
"zulip_english.stop",
)
LOUD = dict(_out=sys.stdout, _err=sys.stderr)
def main():
log = logging.getLogger("zulip-provisioner")
# TODO: support other architectures
if platform.architecture()[0] == '64bit':
arch = 'amd64'
else:
log.critical("Only amd64 is supported.")
vendor, version, codename = platform.dist()
if not (vendor in SUPPORTED_PLATFORMS and codename in SUPPORTED_PLATFORMS[vendor]):
log.critical("Unsupported platform: {} {}".format(vendor, codename))
with sh.sudo:
sh.apt_get.update(**LOUD)
sh.apt_get.install(*APT_DEPENDENCIES["trusty"], assume_yes=True, **LOUD)
temp_deb_path = sh.mktemp("package_XXXXXX.deb", tmpdir=True)
sh.wget(
"{}/{}_{}_{}.deb".format(
TSEARCH_URL_BASE,
TSEARCH_PACKAGE_NAME["trusty"],
TSEARCH_VERSION,
arch,
),
output_document=temp_deb_path,
**LOUD
)
with sh.sudo:
sh.dpkg("--install", temp_deb_path, **LOUD)
with sh.sudo:
PHANTOMJS_PATH = "/srv/phantomjs"
PHANTOMJS_TARBALL = os.path.join(PHANTOMJS_PATH, "phantomjs-1.9.8-linux-x86_64.tar.bz2")
sh.mkdir("-p", PHANTOMJS_PATH, **LOUD)
sh.wget("https://bitbucket.org/ariya/phantomjs/downloads/phantomjs-1.9.8-linux-x86_64.tar.bz2",
output_document=PHANTOMJS_TARBALL, **LOUD)
sh.tar("xj", directory=PHANTOMJS_PATH, file=PHANTOMJS_TARBALL, **LOUD)
sh.ln("-sf", os.path.join(PHANTOMJS_PATH, "phantomjs-1.9.8-linux-x86_64", "bin", "phantomjs"),
"/usr/local/bin/phantomjs", **LOUD)
with sh.sudo:
sh.rm("-rf", VENV_PATH, **LOUD)
sh.mkdir("-p", VENV_PATH, **LOUD)
sh.chown("{}:{}".format(os.getuid(), os.getgid()), VENV_PATH, **LOUD)
sh.virtualenv(VENV_PATH, **LOUD)
# Add the ./tools and ./scripts/setup directories inside the repository root to
# the system path; we'll reference them later.
orig_path = os.environ["PATH"]
os.environ["PATH"] = os.pathsep.join((
os.path.join(ZULIP_PATH, "tools"),
os.path.join(ZULIP_PATH, "scripts", "setup"),
orig_path
))
# Put Python virtualenv activation in our .bash_profile.
with open(os.path.expanduser('~/.bash_profile'), 'w+') as bash_profile:
bash_profile.writelines([
"source .bashrc\n",
"source %s\n" % (os.path.join(VENV_PATH, "bin", "activate"),),
])
# Switch current Python context to the virtualenv.
activate_this = os.path.join(VENV_PATH, "bin", "activate_this.py")
execfile(activate_this, dict(__file__=activate_this))
sh.pip.install(requirement=os.path.join(ZULIP_PATH, "requirements.txt"), **LOUD)
with sh.sudo:
sh.cp(REPO_STOPWORDS_PATH, TSEARCH_STOPWORDS_PATH, **LOUD)
# Add additional node packages for test-js-with-node.
with sh.sudo:
sh.npm.install(*NPM_DEPENDENCIES["trusty"], g=True, prefix="/usr", **LOUD)
# Management commands expect to be run from the root of the project.
os.chdir(ZULIP_PATH)
os.system("tools/download-zxcvbn")
os.system("tools/emoji_dump/build_emoji")
os.system("generate_secrets.py -d")
sh.configure_rabbitmq(**LOUD)
sh.postgres_init_db(**LOUD)
sh.do_destroy_rebuild_database(**LOUD)
sh.postgres_init_test_db(**LOUD)
sh.do_destroy_rebuild_test_database(**LOUD)
if __name__ == "__main__":
sys.exit(main())

View File

@@ -32,8 +32,8 @@ Listen 127.0.0.1:8888
# You shouldn't need to edit anything below this line.
SSLEngine On
SSLCertificateFile /etc/ssl/certs/zulip.combined-chain.crt
SSLCertificateKeyFile /etc/ssl/private/zulip.key
SSLCertificateFile /etc/ssl/certs/zulip-enterprise.combined-chain.crt
SSLCertificateKeyFile /etc/ssl/private/zulip-enterprise.key
WSGIScriptAlias / /home/zulip/deployments/current/zproject/wsgi.py
WSGIDaemonProcess zulip threads=5 user=zulip python-path=/home/zulip/deployments/current/

View File

@@ -54,7 +54,5 @@
#@student - maxlogins 4
zulip soft nofile 40000
zulip hard nofile 50000
root soft nofile 40000
root hard nofile 50000
# End of file

View File

@@ -36,10 +36,6 @@ http {
default upgrade;
'' close;
}
# These are the official ciphers as of 2014-10-14
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:EECDH+RC4:RSA+RC4:!MD5;
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;

View File

@@ -9,8 +9,10 @@ server {
listen 443;
ssl on;
ssl_certificate /etc/ssl/certs/zulip.combined-chain.crt;
ssl_certificate_key /etc/ssl/private/zulip.key;
ssl_certificate /etc/ssl/certs/zulip-enterprise.combined-chain.crt;
ssl_certificate_key /etc/ssl/private/zulip-enterprise.key;
add_header X-Frame-Options DENY;
location /user_uploads {
add_header X-Content-Type-Options nosniff;

View File

@@ -14,36 +14,13 @@ location /static/ {
}
# Send longpoll requests to Tornado
location ~ /json/get_events|/json/events {
location ~ /json/get_events|/json/events|/api/v1/events {
proxy_pass http://tornado;
include /etc/nginx/zulip-include/proxy_longpolling;
proxy_set_header X-Real-IP $remote_addr;
}
# Send longpoll requests to Tornado
location /api/v1/events {
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Headers Authorization;
add_header Access-Control-Allow-Methods 'GET, POST';
if ($request_method = 'OPTIONS') {
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Headers Authorization;
add_header Access-Control-Allow-Methods 'GET, POST';
add_header 'Content-Type' 'text/plain charset=UTF-8';
add_header 'Content-Length' 0;
return 204;
}
proxy_pass http://tornado;
include /etc/nginx/zulip-include/proxy_longpolling;
proxy_set_header X-Real-IP $remote_addr;
}
# Send sockjs requests to Tornado
location /sockjs {
proxy_pass http://tornado;
@@ -61,19 +38,4 @@ location / {
fastcgi_next_upstream off;
}
location /api/ {
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Headers Authorization;
add_header Access-Control-Allow-Methods 'GET, POST';
include fastcgi_params;
fastcgi_pass django;
fastcgi_split_path_info ^()(.*)$;
# Second number set to `getconf PAGESIZE`
fastcgi_buffers 1024 4k;
fastcgi_max_temp_file_size 0;
fastcgi_next_upstream off;
}
include /etc/nginx/zulip-include/app.d/*.conf;

View File

@@ -1,2 +1 @@
/.*\+.*@.*/ zulip@localhost
/^mm.*/ zulip@localhost

View File

@@ -38,15 +38,15 @@
# The default values of these variables are driven from the -D command-line
# option or PGDATA environment variable, represented here as ConfigDir.
data_directory = '/var/lib/postgresql/9.3/main' # use data in another directory
data_directory = '/var/lib/postgresql/9.1/main' # use data in another directory
# (change requires restart)
hba_file = '/etc/postgresql/9.3/main/pg_hba.conf' # host-based authentication file
hba_file = '/etc/postgresql/9.1/main/pg_hba.conf' # host-based authentication file
# (change requires restart)
ident_file = '/etc/postgresql/9.3/main/pg_ident.conf' # ident configuration file
ident_file = '/etc/postgresql/9.1/main/pg_ident.conf' # ident configuration file
# (change requires restart)
# If external_pid_file is not explicitly set, no extra PID file is written.
external_pid_file = '/var/run/postgresql/9.3-main.pid' # write an extra PID file
external_pid_file = '/var/run/postgresql/9.1-main.pid' # write an extra PID file
# (change requires restart)
@@ -65,7 +65,7 @@ port = 5432 # (change requires restart)
# Note: Increasing max_connections costs ~400 bytes of shared memory per
# connection slot, plus lock space (see max_locks_per_transaction).
#superuser_reserved_connections = 3 # (change requires restart)
unix_socket_directories = '/var/run/postgresql' # (change requires restart)
unix_socket_directory = '/var/run/postgresql' # (change requires restart)
#unix_socket_group = '' # (change requires restart)
#unix_socket_permissions = 0777 # begin with 0 to use octal notation
# (change requires restart)
@@ -77,7 +77,7 @@ unix_socket_directories = '/var/run/postgresql' # (change requires restart)
# - Security and Authentication -
#authentication_timeout = 1min # 1s-600s
#ssl = true # (change requires restart)
ssl = true # (change requires restart)
#ssl_ciphers = 'ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH' # allowed SSL ciphers
# (change requires restart)
#ssl_renegotiation_limit = 512MB # amount of data between renegotiations
@@ -106,7 +106,7 @@ unix_socket_directories = '/var/run/postgresql' # (change requires restart)
# - Memory -
shared_buffers = 128MB # min 128kB
# shared_buffers = 24MB # min 128kB
# (change requires restart)
#temp_buffers = 8MB # min 800kB
#max_prepared_transactions = 0 # zero disables the feature

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/python
import psycopg2
import psycopg2.extensions
import select

View File

@@ -0,0 +1,22 @@
[main]
server = puppet.zulip.com
environment = production
confdir = /etc/puppet
logdir=/var/log/puppet
vardir=/var/lib/puppet
ssldir=/var/lib/puppet/ssl
rundir=/var/run/puppet
factpath=$vardir/lib/facter
templatedir=$confdir/templates
prerun_command=/etc/puppet/etckeeper-commit-pre
postrun_command=/etc/puppet/etckeeper-commit-post
modulepath = /root/zulip/puppet:/etc/puppet/modules:/usr/share/puppet/modules
[master]
environment = production
manifest = $confdir/environments/$environment/manifests/site.pp
modulepath = $confdir/environments/$environment/modules
[agent]
report = true
show_diff = true
environment = production

View File

@@ -1,6 +1,6 @@
# Redis configuration file example
# Note on units: when memory size is needed, it is possible to specify
# Note on units: when memory size is needed, it is possible to specifiy
# it in the usual form of 1k 5GB 4M and so forth:
#
# 1k => 1000 bytes
@@ -12,26 +12,6 @@
#
# units are case insensitive so 1GB 1Gb 1gB are all the same.
################################## INCLUDES ###################################
# Include one or more other config files here. This is useful if you
# have a standard template that goes to all Redis server but also need
# to customize a few per-server settings. Include files can include
# other files, so use this wisely.
#
# Notice option "include" won't be rewritten by command "CONFIG REWRITE"
# from admin or Redis Sentinel. Since Redis always uses the last processed
# line as value of a configuration directive, you'd better put includes
# at the beginning of this file to avoid overwriting config change at runtime.
#
# If instead you are interested in using includes to override configuration
# options, it is better to use include as the last line.
#
# include /path/to/local.conf
# include /path/to/other.conf
################################ GENERAL #####################################
# By default Redis does not run as a daemon. Use 'yes' if you need it.
# Note that Redis will write a pid file in /var/run/redis.pid when daemonized.
daemonize yes
@@ -44,14 +24,9 @@ pidfile /var/run/redis/redis-server.pid
# If port 0 is specified Redis will not listen on a TCP socket.
port 6379
# By default Redis listens for connections from all the network interfaces
# available on the server. It is possible to listen to just one or multiple
# interfaces using the "bind" configuration directive, followed by one or
# more IP addresses.
# If you want you can bind a single interface, if the bind option is not
# specified all the interfaces will listen for incoming connections.
#
# Examples:
#
# bind 192.168.1.100 10.0.0.1
bind 127.0.0.1
# Specify the path for the unix socket that will be used to listen for
@@ -64,31 +39,15 @@ bind 127.0.0.1
# Close the connection after a client is idle for N seconds (0 to disable)
timeout 0
# TCP keepalive.
#
# If non-zero, use SO_KEEPALIVE to send TCP ACKs to clients in absence
# of communication. This is useful for two reasons:
#
# 1) Detect dead peers.
# 2) Take the connection alive from the point of view of network
# equipment in the middle.
#
# On Linux, the specified value (in seconds) is the period used to send ACKs.
# Note that to close the connection the double of the time is needed.
# On other kernels the period depends on the kernel configuration.
#
# A reasonable value for this option is 60 seconds.
tcp-keepalive 0
# Specify the server verbosity level.
# This can be one of:
# Set server verbosity to 'debug'
# it can be one of:
# debug (a lot of information, useful for development/testing)
# verbose (many rarely useful info, but not a mess like the debug level)
# notice (moderately verbose, what you want in production probably)
# warning (only very important / critical messages are logged)
loglevel notice
# Specify the log file name. Also the empty string can be used to force
# Specify the log file name. Also 'stdout' can be used to force
# Redis to log on the standard output. Note that if you use standard
# output for logging but daemonize, logs will be sent to /dev/null
logfile /var/log/redis/redis-server.log
@@ -100,7 +59,7 @@ logfile /var/log/redis/redis-server.log
# Specify the syslog identity.
# syslog-ident redis
# Specify the syslog facility. Must be USER or between LOCAL0-LOCAL7.
# Specify the syslog facility. Must be USER or between LOCAL0-LOCAL7.
# syslog-facility local0
# Set the number of databases. The default database is DB 0, you can select
@@ -108,7 +67,7 @@ logfile /var/log/redis/redis-server.log
# dbid is a number between 0 and 'databases'-1
databases 16
################################ SNAPSHOTTING ################################
################################ SNAPSHOTTING #################################
#
# Save the DB on disk:
#
@@ -123,31 +82,10 @@ databases 16
# after 60 sec if at least 10000 keys changed
#
# Note: you can disable saving at all commenting all the "save" lines.
#
# It is also possible to remove all the previously configured save
# points by adding a save directive with a single empty string argument
# like in the following example:
#
# save ""
save 900 1
save 300 10
save 60 10000
# By default Redis will stop accepting writes if RDB snapshots are enabled
# (at least one save point) and the latest background save failed.
# This will make the user aware (in a hard way) that data is not persisting
# on disk properly, otherwise chances are that no one will notice and some
# disaster will happen.
#
# If the background saving process will start working again Redis will
# automatically allow writes again.
#
# However if you have setup your proper monitoring of the Redis server
# and persistence, you may want to disable this feature so that Redis will
# continue to work as usual even if there are problems with disk,
# permissions, and so forth.
stop-writes-on-bgsave-error yes
# save 900 1
# save 300 10
# save 60 10000
# Compress string objects using LZF when dump .rdb databases?
# For default that's set to 'yes' as it's almost always a win.
@@ -155,15 +93,6 @@ stop-writes-on-bgsave-error yes
# the dataset will likely be bigger if you have compressible values or keys.
rdbcompression yes
# Since version 5 of RDB a CRC64 checksum is placed at the end of the file.
# This makes the format more resistant to corruption but there is a performance
# hit to pay (around 10%) when saving and loading RDB files, so you can disable it
# for maximum performances.
#
# RDB files created with checksum disabled have a checksum of zero that will
# tell the loading code to skip the check.
rdbchecksum yes
# The filename where to dump the DB
dbfilename dump.rdb
@@ -171,9 +100,9 @@ dbfilename dump.rdb
#
# The DB will be written inside this directory, with the filename specified
# above using the 'dbfilename' configuration directive.
#
# The Append Only File will also be created inside this directory.
#
#
# Also the Append Only File will be created inside this directory.
#
# Note that you must specify a directory here, not a file name.
dir /var/lib/redis
@@ -193,46 +122,27 @@ dir /var/lib/redis
#
# masterauth <master-password>
# When a slave loses its connection with the master, or when the replication
# When a slave lost the connection with the master, or when the replication
# is still in progress, the slave can act in two different ways:
#
# 1) if slave-serve-stale-data is set to 'yes' (the default) the slave will
# still reply to client requests, possibly with out of date data, or the
# still reply to client requests, possibly with out of data data, or the
# data set may just be empty if this is the first synchronization.
#
# 2) if slave-serve-stale-data is set to 'no' the slave will reply with
# 2) if slave-serve-stale data is set to 'no' the slave will reply with
# an error "SYNC with master in progress" to all the kind of commands
# but to INFO and SLAVEOF.
#
slave-serve-stale-data yes
# You can configure a slave instance to accept writes or not. Writing against
# a slave instance may be useful to store some ephemeral data (because data
# written on a slave will be easily deleted after resync with the master) but
# may also cause problems if clients are writing to it because of a
# misconfiguration.
#
# Since Redis 2.6 by default slaves are read-only.
#
# Note: read only slaves are not designed to be exposed to untrusted clients
# on the internet. It's just a protection layer against misuse of the instance.
# Still a read only slave exports by default all the administrative commands
# such as CONFIG, DEBUG, and so forth. To a limited extent you can improve
# security of read only slaves using 'rename-command' to shadow all the
# administrative / dangerous commands.
slave-read-only yes
# Slaves send PINGs to server in a predefined interval. It's possible to change
# this interval with the repl_ping_slave_period option. The default value is 10
# seconds.
#
# repl-ping-slave-period 10
# The following option sets the replication timeout for:
#
# 1) Bulk transfer I/O during SYNC, from the point of view of slave.
# 2) Master timeout from the point of view of slaves (data, pings).
# 3) Slave timeout from the point of view of masters (REPLCONF ACK pings).
# The following option sets a timeout for both Bulk transfer I/O timeout and
# master data or ping response timeout. The default value is 60 seconds.
#
# It is important to make sure that this value is greater than the value
# specified for repl-ping-slave-period otherwise a timeout will be detected
@@ -240,80 +150,6 @@ slave-read-only yes
#
# repl-timeout 60
# Disable TCP_NODELAY on the slave socket after SYNC?
#
# If you select "yes" Redis will use a smaller number of TCP packets and
# less bandwidth to send data to slaves. But this can add a delay for
# the data to appear on the slave side, up to 40 milliseconds with
# Linux kernels using a default configuration.
#
# If you select "no" the delay for data to appear on the slave side will
# be reduced but more bandwidth will be used for replication.
#
# By default we optimize for low latency, but in very high traffic conditions
# or when the master and slaves are many hops away, turning this to "yes" may
# be a good idea.
repl-disable-tcp-nodelay no
# Set the replication backlog size. The backlog is a buffer that accumulates
# slave data when slaves are disconnected for some time, so that when a slave
# wants to reconnect again, often a full resync is not needed, but a partial
# resync is enough, just passing the portion of data the slave missed while
# disconnected.
#
# The biggest the replication backlog, the longer the time the slave can be
# disconnected and later be able to perform a partial resynchronization.
#
# The backlog is only allocated once there is at least a slave connected.
#
# repl-backlog-size 1mb
# After a master has no longer connected slaves for some time, the backlog
# will be freed. The following option configures the amount of seconds that
# need to elapse, starting from the time the last slave disconnected, for
# the backlog buffer to be freed.
#
# A value of 0 means to never release the backlog.
#
# repl-backlog-ttl 3600
# The slave priority is an integer number published by Redis in the INFO output.
# It is used by Redis Sentinel in order to select a slave to promote into a
# master if the master is no longer working correctly.
#
# A slave with a low priority number is considered better for promotion, so
# for instance if there are three slaves with priority 10, 100, 25 Sentinel will
# pick the one with priority 10, that is the lowest.
#
# However a special priority of 0 marks the slave as not able to perform the
# role of master, so a slave with priority of 0 will never be selected by
# Redis Sentinel for promotion.
#
# By default the priority is 100.
slave-priority 100
# It is possible for a master to stop accepting writes if there are less than
# N slaves connected, having a lag less or equal than M seconds.
#
# The N slaves need to be in "online" state.
#
# The lag in seconds, that must be <= the specified value, is calculated from
# the last ping received from the slave, that is usually sent every second.
#
# This option does not GUARANTEES that N replicas will accept the write, but
# will limit the window of exposure for lost writes in case not enough slaves
# are available, to the specified number of seconds.
#
# For example to require at least 3 slaves with a lag <= 10 seconds use:
#
# min-slaves-to-write 3
# min-slaves-max-lag 10
#
# Setting one or the other to 0 disables the feature.
#
# By default min-slaves-to-write is set to 0 (feature disabled) and
# min-slaves-max-lag is set to 10.
################################## SECURITY ###################################
# Require clients to issue AUTH <PASSWORD> before processing any other
@@ -322,7 +158,7 @@ slave-priority 100
#
# This should stay commented out for backward compatibility and because most
# people do not need auth (e.g. they run their own servers).
#
#
# Warning: since Redis is pretty fast an outside user can try up to
# 150k passwords per second against a good box. This means that you should
# use a very strong password otherwise it will be very easy to break.
@@ -331,39 +167,33 @@ slave-priority 100
# Command renaming.
#
# It is possible to change the name of dangerous commands in a shared
# It is possilbe to change the name of dangerous commands in a shared
# environment. For instance the CONFIG command may be renamed into something
# hard to guess so that it will still be available for internal-use tools
# but not available for general clients.
# of hard to guess so that it will be still available for internal-use
# tools but not available for general clients.
#
# Example:
#
# rename-command CONFIG b840fc02d524045429941cc15f59e41cb7be6c52
#
# It is also possible to completely kill a command by renaming it into
# It is also possilbe to completely kill a command renaming it into
# an empty string:
#
# rename-command CONFIG ""
#
# Please note that changing the name of commands that are logged into the
# AOF file or transmitted to slaves may cause problems.
################################### LIMITS ####################################
# Set the max number of connected clients at the same time. By default
# this limit is set to 10000 clients, however if the Redis server is not
# able to configure the process file limit to allow for the specified limit
# the max number of allowed clients is set to the current file limit
# minus 32 (as Redis reserves a few file descriptors for internal uses).
#
# Set the max number of connected clients at the same time. By default there
# is no limit, and it's up to the number of file descriptors the Redis process
# is able to open. The special value '0' means no limits.
# Once the limit is reached Redis will close all the new connections sending
# an error 'max number of clients reached'.
#
# maxclients 10000
# maxclients 128
# Don't use more memory than the specified amount of bytes.
# When the memory limit is reached Redis will try to remove keys
# according to the eviction policy selected (see maxmemory-policy).
# accordingly to the eviction policy selected (see maxmemmory-policy).
#
# If Redis can't remove keys according to the policy, or if the policy is
# set to 'noeviction', Redis will start to reply with errors to commands
@@ -371,7 +201,7 @@ slave-priority 100
# to reply to read-only commands like GET.
#
# This option is usually useful when using Redis as an LRU cache, or to set
# a hard memory limit for an instance (using the 'noeviction' policy).
# an hard memory limit for an instance (using the 'noeviction' policy).
#
# WARNING: If you have slaves attached to an instance with maxmemory on,
# the size of the output buffers needed to feed the slaves are subtracted
@@ -387,16 +217,16 @@ slave-priority 100
# maxmemory <bytes>
# MAXMEMORY POLICY: how Redis will select what to remove when maxmemory
# is reached. You can select among five behaviors:
#
# is reached? You can select among five behavior:
#
# volatile-lru -> remove the key with an expire set using an LRU algorithm
# allkeys-lru -> remove any key accordingly to the LRU algorithm
# volatile-random -> remove a random key with an expire set
# allkeys-random -> remove a random key, any key
# allkeys->random -> remove a random key, any key
# volatile-ttl -> remove the key with the nearest expire time (minor TTL)
# noeviction -> don't expire at all, just return an error on write operations
#
# Note: with any of the above policies, Redis will return an error on write
#
# Note: with all the kind of policies, Redis will return an error on write
# operations, when there are not suitable keys for eviction.
#
# At the date of writing this commands are: set setnx setex append
@@ -419,51 +249,45 @@ slave-priority 100
############################## APPEND ONLY MODE ###############################
# By default Redis asynchronously dumps the dataset on disk. This mode is
# good enough in many applications, but an issue with the Redis process or
# a power outage may result into a few minutes of writes lost (depending on
# the configured save points).
# By default Redis asynchronously dumps the dataset on disk. If you can live
# with the idea that the latest records will be lost if something like a crash
# happens this is the preferred way to run Redis. If instead you care a lot
# about your data and don't want to that a single record can get lost you should
# enable the append only mode: when this mode is enabled Redis will append
# every write operation received in the file appendonly.aof. This file will
# be read on startup in order to rebuild the full dataset in memory.
#
# The Append Only File is an alternative persistence mode that provides
# much better durability. For instance using the default data fsync policy
# (see later in the config file) Redis can lose just one second of writes in a
# dramatic event like a server power outage, or a single write if something
# wrong with the Redis process itself happens, but the operating system is
# still running correctly.
# Note that you can have both the async dumps and the append only file if you
# like (you have to comment the "save" statements above to disable the dumps).
# Still if append only mode is enabled Redis will load the data from the
# log file at startup ignoring the dump.rdb file.
#
# AOF and RDB persistence can be enabled at the same time without problems.
# If the AOF is enabled on startup Redis will load the AOF, that is the file
# with the better durability guarantees.
#
# Please check http://redis.io/topics/persistence for more information.
# IMPORTANT: Check the BGREWRITEAOF to check how to rewrite the append
# log file in background when it gets too big.
appendonly no
# The name of the append only file (default: "appendonly.aof")
appendfilename "appendonly.aof"
# appendfilename appendonly.aof
# The fsync() call tells the Operating System to actually write data on disk
# instead to wait for more data in the output buffer. Some OS will really flush
# instead to wait for more data in the output buffer. Some OS will really flush
# data on disk, some other OS will just try to do it ASAP.
#
# Redis supports three different modes:
#
# no: don't fsync, just let the OS flush the data when it wants. Faster.
# always: fsync after every write to the append only log . Slow, Safest.
# everysec: fsync only one time every second. Compromise.
# everysec: fsync only if one second passed since the last fsync. Compromise.
#
# The default is "everysec", as that's usually the right compromise between
# The default is "everysec" that's usually the right compromise between
# speed and data safety. It's up to you to understand if you can relax this to
# "no" that will let the operating system flush the output buffer when
# "no" that will will let the operating system flush the output buffer when
# it wants, for better performances (but if you can live with the idea of
# some data loss consider the default persistence mode that's snapshotting),
# or on the contrary, use "always" that's very slow but a bit safer than
# everysec.
#
# More details please check the following article:
# http://antirez.com/post/redis-persistence-demystified.html
#
# If unsure, use "everysec".
# appendfsync always
@@ -481,22 +305,21 @@ appendfsync everysec
# that will prevent fsync() from being called in the main process while a
# BGSAVE or BGREWRITEAOF is in progress.
#
# This means that while another child is saving, the durability of Redis is
# the same as "appendfsync none". In practical terms, this means that it is
# possible to lose up to 30 seconds of log in the worst scenario (with the
# This means that while another child is saving the durability of Redis is
# the same as "appendfsync none", that in pratical terms means that it is
# possible to lost up to 30 seconds of log in the worst scenario (with the
# default Linux settings).
#
#
# If you have latency problems turn this to "yes". Otherwise leave it as
# "no" that is the safest pick from the point of view of durability.
no-appendfsync-on-rewrite no
# Automatic rewrite of the append only file.
# Redis is able to automatically rewrite the log file implicitly calling
# BGREWRITEAOF when the AOF log size grows by the specified percentage.
#
# BGREWRITEAOF when the AOF log size will growth by the specified percentage.
#
# This is how it works: Redis remembers the size of the AOF file after the
# latest rewrite (if no rewrite has happened since the restart, the size of
# latest rewrite (or if no rewrite happened since the restart, the size of
# the AOF at startup is used).
#
# This base size is compared to the current size. If the current size is
@@ -505,30 +328,12 @@ no-appendfsync-on-rewrite no
# is useful to avoid rewriting the AOF file even if the percentage increase
# is reached but it is still pretty small.
#
# Specify a percentage of zero in order to disable the automatic AOF
# Specify a precentage of zero in order to disable the automatic AOF
# rewrite feature.
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
################################ LUA SCRIPTING ###############################
# Max execution time of a Lua script in milliseconds.
#
# If the maximum execution time is reached Redis will log that a script is
# still in execution after the maximum allowed time and will start to
# reply to queries with an error.
#
# When a long running script exceed the maximum execution time only the
# SCRIPT KILL and SHUTDOWN NOSAVE commands are available. The first can be
# used to stop a script that did not yet called write commands. The second
# is the only way to shut down the server in the case a write commands was
# already issue by the script but the user don't want to wait for the natural
# termination of the script.
#
# Set it to 0 or a negative value for unlimited execution without warnings.
lua-time-limit 5000
################################## SLOW LOG ###################################
# The Redis Slow Log is a system to log queries that exceeded a specified
@@ -537,7 +342,7 @@ lua-time-limit 5000
# but just the time needed to actually execute the command (this is the only
# stage of command execution where the thread is blocked and can not serve
# other requests in the meantime).
#
#
# You can configure the slow log with two parameters: one tells Redis
# what is the execution time, in microseconds, to exceed in order for the
# command to get logged, and the other parameter is the length of the
@@ -553,59 +358,88 @@ slowlog-log-slower-than 10000
# You can reclaim memory used by the slow log with SLOWLOG RESET.
slowlog-max-len 128
############################# Event notification ##############################
################################ VIRTUAL MEMORY ###############################
# Redis can notify Pub/Sub clients about events happening in the key space.
# This feature is documented at http://redis.io/topics/keyspace-events
#
# For instance if keyspace events notification is enabled, and a client
# performs a DEL operation on key "foo" stored in the Database 0, two
# messages will be published via Pub/Sub:
### WARNING! Virtual Memory is deprecated in Redis 2.4
### The use of Virtual Memory is strongly discouraged.
# Virtual Memory allows Redis to work with datasets bigger than the actual
# amount of RAM needed to hold the whole dataset in memory.
# In order to do so very used keys are taken in memory while the other keys
# are swapped into a swap file, similarly to what operating systems do
# with memory pages.
#
# PUBLISH __keyspace@0__:foo del
# PUBLISH __keyevent@0__:del foo
# To enable VM just set 'vm-enabled' to yes, and set the following three
# VM parameters accordingly to your needs.
vm-enabled no
# vm-enabled yes
# This is the path of the Redis swap file. As you can guess, swap files
# can't be shared by different Redis instances, so make sure to use a swap
# file for every redis process you are running. Redis will complain if the
# swap file is already in use.
#
# It is possible to select the events that Redis will notify among a set
# of classes. Every class is identified by a single character:
# The best kind of storage for the Redis swap file (that's accessed at random)
# is a Solid State Disk (SSD).
#
# K Keyspace events, published with __keyspace@<db>__ prefix.
# E Keyevent events, published with __keyevent@<db>__ prefix.
# g Generic commands (non-type specific) like DEL, EXPIRE, RENAME, ...
# $ String commands
# l List commands
# s Set commands
# h Hash commands
# z Sorted set commands
# x Expired events (events generated every time a key expires)
# e Evicted events (events generated when a key is evicted for maxmemory)
# A Alias for g$lshzxe, so that the "AKE" string means all the events.
# *** WARNING *** if you are using a shared hosting the default of putting
# the swap file under /tmp is not secure. Create a dir with access granted
# only to Redis user and configure Redis to create the swap file there.
vm-swap-file /var/lib/redis/redis.swap
# vm-max-memory configures the VM to use at max the specified amount of
# RAM. Everything that deos not fit will be swapped on disk *if* possible, that
# is, if there is still enough contiguous space in the swap file.
#
# The "notify-keyspace-events" takes as argument a string that is composed
# by zero or multiple characters. The empty string means that notifications
# are disabled at all.
# With vm-max-memory 0 the system will swap everything it can. Not a good
# default, just specify the max amount of RAM you can in bytes, but it's
# better to leave some margin. For instance specify an amount of RAM
# that's more or less between 60 and 80% of your free RAM.
vm-max-memory 0
# Redis swap files is split into pages. An object can be saved using multiple
# contiguous pages, but pages can't be shared between different objects.
# So if your page is too big, small objects swapped out on disk will waste
# a lot of space. If you page is too small, there is less space in the swap
# file (assuming you configured the same number of total swap file pages).
#
# Example: to enable list and generic events, from the point of view of the
# event name, use:
# If you use a lot of small objects, use a page size of 64 or 32 bytes.
# If you use a lot of big objects, use a bigger page size.
# If unsure, use the default :)
vm-page-size 32
# Number of total memory pages in the swap file.
# Given that the page table (a bitmap of free/used pages) is taken in memory,
# every 8 pages on disk will consume 1 byte of RAM.
#
# notify-keyspace-events Elg
# The total swap size is vm-page-size * vm-pages
#
# Example 2: to get the stream of the expired keys subscribing to channel
# name __keyevent@0__:expired use:
# With the default of 32-bytes memory pages and 134217728 pages Redis will
# use a 4 GB swap file, that will use 16 MB of RAM for the page table.
#
# notify-keyspace-events Ex
# It's better to use the smallest acceptable value for your application,
# but the default is large in order to work in most conditions.
vm-pages 134217728
# Max number of VM I/O threads running at the same time.
# This threads are used to read/write data from/to swap file, since they
# also encode and decode objects from disk to memory or the reverse, a bigger
# number of threads can help with big objects even if they can't help with
# I/O itself as the physical device may not be able to couple with many
# reads/writes operations at the same time.
#
# By default all notifications are disabled because most users don't need
# this feature and the feature has some overhead. Note that if you don't
# specify at least one of K or E, no events will be delivered.
notify-keyspace-events ""
# The special value of 0 turn off threaded I/O and enables the blocking
# Virtual Memory implementation.
vm-max-threads 4
############################### ADVANCED CONFIG ###############################
# Hashes are encoded using a memory efficient data structure when they have a
# small number of entries, and the biggest entry does not exceed a given
# threshold. These thresholds can be configured using the following directives.
hash-max-ziplist-entries 512
hash-max-ziplist-value 64
# Hashes are encoded in a special way (much more memory efficient) when they
# have at max a given numer of elements, and the biggest element does not
# exceed a given threshold. You can configure this limits with the following
# configuration directives.
hash-max-zipmap-entries 512
hash-max-zipmap-value 64
# Similarly to hashes, small lists are also encoded in a special way in order
# to save a lot of space. The special representation is only used when
@@ -628,12 +462,12 @@ zset-max-ziplist-value 64
# Active rehashing uses 1 millisecond every 100 milliseconds of CPU time in
# order to help rehashing the main Redis hash table (the one mapping top-level
# keys to values). The hash table implementation Redis uses (see dict.c)
# performs a lazy rehashing: the more operation you run into a hash table
# that is rehashing, the more rehashing "steps" are performed, so if the
# keys to values). The hash table implementation redis uses (see dict.c)
# performs a lazy rehashing: the more operation you run into an hash table
# that is rhashing, the more rehashing "steps" are performed, so if the
# server is idle the rehashing is never complete and some more memory is used
# by the hash table.
#
#
# The default is to use this millisecond 10 times every second in order to
# active rehashing the main dictionaries, freeing memory when possible.
#
@@ -646,65 +480,12 @@ zset-max-ziplist-value 64
# want to free memory asap when possible.
activerehashing yes
# The client output buffer limits can be used to force disconnection of clients
# that are not reading data from the server fast enough for some reason (a
# common reason is that a Pub/Sub client can't consume messages as fast as the
# publisher can produce them).
#
# The limit can be set differently for the three different classes of clients:
#
# normal -> normal clients
# slave -> slave clients and MONITOR clients
# pubsub -> clients subscribed to at least one pubsub channel or pattern
#
# The syntax of every client-output-buffer-limit directive is the following:
#
# client-output-buffer-limit <class> <hard limit> <soft limit> <soft seconds>
#
# A client is immediately disconnected once the hard limit is reached, or if
# the soft limit is reached and remains reached for the specified number of
# seconds (continuously).
# So for instance if the hard limit is 32 megabytes and the soft limit is
# 16 megabytes / 10 seconds, the client will get disconnected immediately
# if the size of the output buffers reach 32 megabytes, but will also get
# disconnected if the client reaches 16 megabytes and continuously overcomes
# the limit for 10 seconds.
#
# By default normal clients are not limited because they don't receive data
# without asking (in a push way), but just after a request, so only
# asynchronous clients may create a scenario where data is requested faster
# than it can read.
#
# Instead there is a default limit for pubsub and slave clients, since
# subscribers and slaves receive data in a push fashion.
#
# Both the hard or the soft limit can be disabled by setting them to zero.
client-output-buffer-limit normal 0 0 0
client-output-buffer-limit slave 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60
################################## INCLUDES ###################################
# Redis calls an internal function to perform many background tasks, like
# closing connections of clients in timeout, purging expired keys that are
# never requested, and so forth.
# Include one or more other config files here. This is useful if you
# have a standard template that goes to all redis server but also need
# to customize a few per-server settings. Include files can include
# other files, so use this wisely.
#
# Not all tasks are performed with the same frequency, but Redis checks for
# tasks to perform accordingly to the specified "hz" value.
#
# By default "hz" is set to 10. Raising the value will use more CPU when
# Redis is idle, but at the same time will make Redis more responsive when
# there are many keys expiring at the same time, and timeouts may be
# handled with more precision.
#
# The range is between 1 and 500, however a value over 100 is usually not
# a good idea. Most users should use the default of 10 and raise this up to
# 100 only in environments where very low latency is required.
hz 10
# When a child rewrites the AOF file, if the following option is enabled
# the file will be fsync-ed every 32 MB of data generated. This is useful
# in order to commit the file to the disk more incrementally and avoid
# big latency spikes.
aof-rewrite-incremental-fsync yes
# Zulip-specific configuration: disable saving to disk.
save ""
# include /path/to/local.conf
# include /path/to/other.conf

View File

@@ -26,8 +26,8 @@ stopwaitsecs=30 ; max num secs to wait b4 SIGKILL (default 10)
user=zulip ; setuid to this UNIX account to run the program
redirect_stderr=true ; redirect proc stderr to stdout (default false)
stdout_logfile=/var/log/zulip/django.log ; stdout log path, NONE for none; default AUTO
stdout_logfile_maxbytes=1GB ; max # logfile bytes b4 rotation (default 50MB)
stdout_logfile_backups=10 ; # of stdout logfile backups (default 10)
;stdout_logfile_maxbytes=1MB ; max # logfile bytes b4 rotation (default 50MB)
;stdout_logfile_backups=10 ; # of stdout logfile backups (default 10)
;stdout_capture_maxbytes=1MB ; number of bytes in 'capturemode' (default 0)
;stdout_events_enabled=false ; emit events on stdout writes (default false)
;stderr_logfile=/var/log/zulip/app.err ; stderr log path, NONE for none; default AUTO
@@ -52,8 +52,6 @@ stopwaitsecs=30 ; max num secs to wait b4 SIGKILL (default 10)
user=zulip ; setuid to this UNIX account to run the program
redirect_stderr=true ; redirect proc stderr to stdout (default false)
stdout_logfile=/var/log/zulip/tornado.log ; stdout log path, NONE for none; default AUTO
stdout_logfile_maxbytes=1GB ; max # logfile bytes b4 rotation (default 50MB)
stdout_logfile_backups=10 ; # of stdout logfile backups (default 10)
directory=/home/zulip/deployments/current/
[program:zulip-events-user-activity]
@@ -66,8 +64,6 @@ stopwaitsecs=30 ; max num secs to wait b4 SIGKILL (default 10)
user=zulip ; setuid to this UNIX account to run the program
redirect_stderr=true ; redirect proc stderr to stdout (default false)
stdout_logfile=/var/log/zulip/events-user-activity.log ; stdout log path, NONE for none; default AUTO
stdout_logfile_maxbytes=1GB ; max # logfile bytes b4 rotation (default 50MB)
stdout_logfile_backups=10 ; # of stdout logfile backups (default 10)
directory=/home/zulip/deployments/current/
[program:zulip-events-user-activity-interval]
@@ -80,8 +76,6 @@ stopwaitsecs=30 ; max num secs to wait b4 SIGKILL (default 10)
user=zulip ; setuid to this UNIX account to run the program
redirect_stderr=true ; redirect proc stderr to stdout (default false)
stdout_logfile=/var/log/zulip/events-user-activity-interval.log ; stdout log path, NONE for none; default AUTO
stdout_logfile_maxbytes=1GB ; max # logfile bytes b4 rotation (default 50MB)
stdout_logfile_backups=10 ; # of stdout logfile backups (default 10)
directory=/home/zulip/deployments/current/
[program:zulip-events-user-presence]
@@ -94,8 +88,6 @@ stopwaitsecs=30 ; max num secs to wait b4 SIGKILL (default 10)
user=zulip ; setuid to this UNIX account to run the program
redirect_stderr=true ; redirect proc stderr to stdout (default false)
stdout_logfile=/var/log/zulip/events-user-presence.log ; stdout log path, NONE for none; default AUTO
stdout_logfile_maxbytes=1GB ; max # logfile bytes b4 rotation (default 50MB)
stdout_logfile_backups=10 ; # of stdout logfile backups (default 10)
directory=/home/zulip/deployments/current/
[program:zulip-events-signups]
@@ -108,8 +100,6 @@ stopwaitsecs=30 ; max num secs to wait b4 SIGKILL (default 10)
user=zulip ; setuid to this UNIX account to run the program
redirect_stderr=true ; redirect proc stderr to stdout (default false)
stdout_logfile=/var/log/zulip/events-signups.log ; stdout log path, NONE for none; default AUTO
stdout_logfile_maxbytes=1GB ; max # logfile bytes b4 rotation (default 50MB)
stdout_logfile_backups=10 ; # of stdout logfile backups (default 10)
directory=/home/zulip/deployments/current/
[program:zulip-events-confirmation-emails]
@@ -122,8 +112,6 @@ stopwaitsecs=30 ; max num secs to wait b4 SIGKILL (default 10)
user=zulip ; setuid to this UNIX account to run the program
redirect_stderr=true ; redirect proc stderr to stdout (default false)
stdout_logfile=/var/log/zulip/events-confirmation-emails.log ; stdout log path, NONE for none; default AUTO
stdout_logfile_maxbytes=1GB ; max # logfile bytes b4 rotation (default 50MB)
stdout_logfile_backups=10 ; # of stdout logfile backups (default 10)
directory=/home/zulip/deployments/current/
[program:zulip-events-missedmessage_reminders]
@@ -136,8 +124,6 @@ stopwaitsecs=30 ; max num secs to wait b4 SIGKILL (default 10)
user=zulip ; setuid to this UNIX account to run the program
redirect_stderr=true ; redirect proc stderr to stdout (default false)
stdout_logfile=/var/log/zulip/events-missedmessage_reminders.log ; stdout log path, NONE for none; default AUTO
stdout_logfile_maxbytes=1GB ; max # logfile bytes b4 rotation (default 50MB)
stdout_logfile_backups=10 ; # of stdout logfile backups (default 10)
directory=/home/zulip/deployments/current/
[program:zulip-events-missedmessage_mobile_notifications]
@@ -150,8 +136,6 @@ stopwaitsecs=30 ; max num secs to wait b4 SIGKILL (default 10)
user=zulip ; setuid to this UNIX account to run the program
redirect_stderr=true ; redirect proc stderr to stdout (default false)
stdout_logfile=/var/log/zulip/events-missedmessage_mobile_notifications.log ; stdout log path, NONE for none; default AUTO
stdout_logfile_maxbytes=1GB ; max # logfile bytes b4 rotation (default 50MB)
stdout_logfile_backups=10 ; # of stdout logfile backups (default 10)
directory=/home/zulip/deployments/current/
[program:zulip-events-slowqueries]
@@ -164,8 +148,6 @@ stopwaitsecs=30 ; max num secs to wait b4 SIGKILL (default 10)
user=zulip ; setuid to this UNIX account to run the program
redirect_stderr=true ; redirect proc stderr to stdout (default false)
stdout_logfile=/var/log/zulip/events-slow_queries.log ; stdout log path, NONE for none; default AUTO
stdout_logfile_maxbytes=1GB ; max # logfile bytes b4 rotation (default 50MB)
stdout_logfile_backups=10 ; # of stdout logfile backups (default 10)
directory=/home/zulip/deployments/current/
[program:zulip-events-message_sender]
@@ -179,8 +161,6 @@ stopwaitsecs=30 ; max num secs to wait b4 SIGKILL (default 10)
user=zulip ; setuid to this UNIX account to run the program
redirect_stderr=true ; redirect proc stderr to stdout (default false)
stdout_logfile=/var/log/zulip/events-message_sender.log ; stdout log path, NONE for none; default AUTO
stdout_logfile_maxbytes=1GB ; max # logfile bytes b4 rotation (default 50MB)
stdout_logfile_backups=10 ; # of stdout logfile backups (default 10)
directory=/home/zulip/deployments/current/
numprocs=5
@@ -194,8 +174,6 @@ stopwaitsecs=30 ; max num secs to wait b4 SIGKILL (default 10)
user=zulip ; setuid to this UNIX account to run the program
redirect_stderr=true ; redirect proc stderr to stdout (default false)
stdout_logfile=/var/log/zulip/events-feedback_messages.log ; stdout log path, NONE for none; default AUTO
stdout_logfile_maxbytes=1GB ; max # logfile bytes b4 rotation (default 50MB)
stdout_logfile_backups=10 ; # of stdout logfile backups (default 10)
directory=/home/zulip/deployments/current/
[program:zulip-events-error_reports]
@@ -208,8 +186,6 @@ stopwaitsecs=30 ; max num secs to wait b4 SIGKILL (default 10)
user=zulip ; setuid to this UNIX account to run the program
redirect_stderr=true ; redirect proc stderr to stdout (default false)
stdout_logfile=/var/log/zulip/events-error_reports.log ; stdout log path, NONE for none; default AUTO
stdout_logfile_maxbytes=1GB ; max # logfile bytes b4 rotation (default 50MB)
stdout_logfile_backups=10 ; # of stdout logfile backups (default 10)
directory=/home/zulip/deployments/current/
[program:zulip-events-digest_emails]
@@ -222,8 +198,6 @@ stopwaitsecs=30 ; max num secs to wait b4 SIGKILL (default 10)
user=zulip ; setuid to this UNIX account to run the program
redirect_stderr=true ; redirect proc stderr to stdout (default false)
stdout_logfile=/var/log/zulip/events-digest_emails.log ; stdout log path, NONE for none; default AUTO
stdout_logfile_maxbytes=1GB ; max # logfile bytes b4 rotation (default 50MB)
stdout_logfile_backups=10 ; # of stdout logfile backups (default 10)
directory=/home/zulip/deployments/current/
[program:zulip-events-email_mirror]
@@ -236,8 +210,6 @@ stopwaitsecs=30 ; max num secs to wait b4 SIGKILL (default 10)
user=zulip ; setuid to this UNIX account to run the program
redirect_stderr=true ; redirect proc stderr to stdout (default false)
stdout_logfile=/var/log/zulip/events-email_mirror.log ; stdout log path, NONE for none; default AUTO
stdout_logfile_maxbytes=1GB ; max # logfile bytes b4 rotation (default 50MB)
stdout_logfile_backups=10 ; # of stdout logfile backups (default 10)
directory=/home/zulip/deployments/current/
[program:zulip-deliver-enqueued-emails]
@@ -250,8 +222,6 @@ stopwaitsecs=30 ; max num secs to wait b4 SIGKILL (default 10)
user=zulip ; setuid to this UNIX account to run the program
redirect_stderr=true ; redirect proc stderr to stdout (default false)
stdout_logfile=/var/log/zulip/events-deliver_enqueued_emails.log ; stdout log path, NONE for none; default AUTO
stdout_logfile_maxbytes=1GB ; max # logfile bytes b4 rotation (default 50MB)
stdout_logfile_backups=10 ; # of stdout logfile backups (default 10)
directory=/home/zulip/deployments/current/

View File

@@ -11,6 +11,8 @@ class zulip::app_frontend {
# Django dependencies
"python-django",
"python-django-guardian",
"python-django-auth-openid",
"python-django-south",
"python-django-pipeline",
"python-django-bitfield",
# Needed for mock objects in decorators
@@ -26,7 +28,7 @@ class zulip::app_frontend {
# Used for Hesiod lookups, etc.
"python-dns",
# Needed to access our database
"postgresql-client-9.3",
"postgresql-client-9.1",
"python-psycopg2",
# Needed for building complex DB queries
"python-sqlalchemy",
@@ -47,6 +49,7 @@ class zulip::app_frontend {
# Needed for S3 file uploads
"python-boto",
# Needed to send email
"python-postmonkey",
"python-mandrill",
# Needed to generate diffs for edits
"python-diff-match-patch",
@@ -56,12 +59,10 @@ class zulip::app_frontend {
"python-gcm-client",
# Needed for avatar image resizing
"python-imaging",
# Needed for LDAP support
"python-django-auth-ldap",
# Needed for Google Apps mobile auth
"python-googleapi",
# Needed for JWT-based auth
"python-pyjwt",
# Needed for LDAP support
"python-django-auth-ldap",
# Needed for Google Apps mobile auth
"python-googleapi",
]
define safepackage ( $ensure = present ) {
if !defined(Package[$title]) {

View File

@@ -22,12 +22,13 @@ class zulip::base {
group { 'zulip':
ensure => present,
gid => '1000',
}
user { 'zulip':
ensure => present,
uid => '1000',
gid => '1000',
require => Group['zulip'],
gid => 'zulip',
shell => '/bin/bash',
home => '/home/zulip',
managehome => true,
@@ -40,6 +41,14 @@ class zulip::base {
group => 'zulip',
}
file { '/etc/puppet/puppet.conf':
ensure => file,
mode => 640,
owner => "root",
group => "root",
source => 'puppet:///modules/zulip/puppet.conf',
}
file { '/etc/security/limits.conf':
ensure => file,
mode => 640,
@@ -48,13 +57,6 @@ class zulip::base {
source => 'puppet:///modules/zulip/limits.conf',
}
# This directory is written to by cron jobs for reading by Nagios
file { '/var/lib/nagios_state/':
ensure => directory,
group => 'zulip',
mode => 774,
}
file { '/var/log/zulip':
ensure => 'directory',
owner => 'zulip',

View File

@@ -1,15 +1,15 @@
class zulip::voyager {
class zulip::enterprise {
include zulip::base
include zulip::app_frontend
include zulip::postgres_appdb
include zulip::redis
apt::source {'zulip':
location => 'http://ppa.launchpad.net/tabbott/zulip/ubuntu',
release => 'trusty',
repos => 'main',
key => '84C2BE60E50E336456E4749CE84240474E26AE47',
key_source => 'https://zulip.com/dist/keys/zulip.asc',
location => 'http://apt.zulip.com/enterprise',
release => 'precise',
repos => 'v1',
key => 'E5FB045CA79AA8FC25FDE9F3B4F81D07A529EF65',
key_source => 'https://zulip.com/dist/keys/enterprise.asc',
pin => '995',
include_src => true,
}
@@ -44,8 +44,8 @@ class zulip::voyager {
source => "puppet:///modules/zulip/cron.d/restart-zulip",
}
file { '/etc/postgresql/9.3/main/postgresql.conf.template':
require => Package["postgresql-9.3"],
file { '/etc/postgresql/9.1/main/postgresql.conf.template':
require => Package["postgresql-9.1"],
ensure => file,
owner => "postgres",
group => "postgres",
@@ -82,12 +82,12 @@ vm.dirty_background_ratio = 5
exec { 'pgtune':
require => Package["pgtune"],
# Let Postgres use half the memory on the machine
command => "pgtune -T Web -M $half_memory -i /etc/postgresql/9.3/main/postgresql.conf.template -o /etc/postgresql/9.3/main/postgresql.conf",
command => "pgtune -T Web -M $half_memory -i /etc/postgresql/9.1/main/postgresql.conf.template -o /etc/postgresql/9.1/main/postgresql.conf",
refreshonly => true,
subscribe => File['/etc/postgresql/9.3/main/postgresql.conf.template']
subscribe => File['/etc/postgresql/9.1/main/postgresql.conf.template']
}
exec { 'pg_ctlcluster 9.3 main restart':
exec { 'pg_ctlcluster 9.1 main restart':
require => Exec["sysctl_p"],
refreshonly => true,
subscribe => [ Exec['pgtune'], File['/etc/sysctl.d/40-postgresql.conf'] ]

View File

@@ -17,7 +17,7 @@ class zulip::postfix_localmail {
mode => 0644,
owner => root,
group => root,
content => "${fqdn}",
content => "@${fqdn}",
}
file {'/etc/postfix/main.cf':

View File

@@ -5,7 +5,7 @@ class zulip::postgres_appdb {
$appdb_packages = [# Needed to run process_fts_updates
"python-psycopg2",
# Needed for our full text search system
"postgresql-9.3-tsearch-extras",
"postgresql-9.1-tsearch-extras",
]
define safepackage ( $ensure = present ) {
if !defined(Package[$title]) {
@@ -37,16 +37,16 @@ class zulip::postgres_appdb {
notify => Service[supervisor],
}
file { '/usr/share/postgresql/9.3/tsearch_data/en_us.dict':
file { '/usr/share/postgresql/9.1/tsearch_data/en_us.dict':
ensure => 'link',
target => '/var/cache/postgresql/dicts/en_us.dict',
}
file { '/usr/share/postgresql/9.3/tsearch_data/en_us.affix':
file { '/usr/share/postgresql/9.1/tsearch_data/en_us.affix':
ensure => 'link',
target => '/var/cache/postgresql/dicts/en_us.affix',
}
file { "/usr/share/postgresql/9.3/tsearch_data/zulip_english.stop":
require => Package["postgresql-9.3"],
file { "/usr/share/postgresql/9.1/tsearch_data/zulip_english.stop":
require => Package["postgresql-9.1"],
ensure => file,
owner => "root",
group => "root",

View File

@@ -1,6 +1,6 @@
class zulip::postgres_common {
$postgres_packages = [# The database itself
"postgresql-9.3",
"postgresql-9.1",
# tools for database setup
"pgtune",
# tools for database monitoring

View File

@@ -1,6 +1,6 @@
# This file is managed by puppet; local changes will be overridden.
smtpd_banner = $myhostname ESMTP $mail_name (Zulip Voyager)
smtpd_banner = $myhostname ESMTP $mail_name (Zulip Enterprise)
biff = no
# appending .domain is the MUA's job.

View File

@@ -0,0 +1,83 @@
-----BEGIN CERTIFICATE-----
MIIE+zCCA+OgAwIBAgIQDJOL1Hip5tpyq5kwwV/lQzANBgkqhkiG9w0BAQUFADBz
MQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYD
VQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01PRE8gQ0EgTGltaXRlZDEZMBcGA1UE
AxMQUG9zaXRpdmVTU0wgQ0EgMjAeFw0xMzA3MTIwMDAwMDBaFw0xNDA3MTIyMzU5
NTlaMFExITAfBgNVBAsTGERvbWFpbiBDb250cm9sIFZhbGlkYXRlZDEUMBIGA1UE
CxMLUG9zaXRpdmVTU0wxFjAUBgNVBAMTDWFwaS56dWxpcC5jb20wggEiMA0GCSqG
SIb3DQEBAQUAA4IBDwAwggEKAoIBAQC+GsCaNbs6bR4CB0MJ2NARH0JMoXsCVHHC
fT149arpZoAf9s4cmUgqe/qXl7jeh1Hb5UtARhchNMR/poFX9Dd73qTVfDEvtASW
ezpsEAB3KJQiISjUyL8xxRAggYf5AXtJ2QzaHoQ3sQk65lVuarB4aQwFB+SsbdtU
dDTHAgnJ3p8Vz4cFjus2n/EW+td5c74V7Y6nAj/ww8ygRRdAvfGmHa84ZHEu+xCI
5cnX0704hJETDfv1ELg257Rmg5pbwHfThSGs5KWv7AQqpLg+wNRD/s5LO1o6zB1z
Toidcq8HaD2/hS3oAQUibySRjieTHE1JU1ueqjfn0grrCpoSjgrDAgMBAAGjggGr
MIIBpzAfBgNVHSMEGDAWgBSZ5EBfaxRePgXZ3dNjVPxiuPcArDAdBgNVHQ4EFgQU
py+lc7gytud0YnB4ddplmEgkEeIwDgYDVR0PAQH/BAQDAgWgMAwGA1UdEwEB/wQC
MAAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMFAGA1UdIARJMEcwOwYL
KwYBBAGyMQECAgcwLDAqBggrBgEFBQcCARYeaHR0cDovL3d3dy5wb3NpdGl2ZXNz
bC5jb20vQ1BTMAgGBmeBDAECATA7BgNVHR8ENDAyMDCgLqAshipodHRwOi8vY3Js
LmNvbW9kb2NhLmNvbS9Qb3NpdGl2ZVNTTENBMi5jcmwwbAYIKwYBBQUHAQEEYDBe
MDYGCCsGAQUFBzAChipodHRwOi8vY3J0LmNvbW9kb2NhLmNvbS9Qb3NpdGl2ZVNT
TENBMi5jcnQwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmNvbW9kb2NhLmNvbTAr
BgNVHREEJDAigg1hcGkuenVsaXAuY29tghF3d3cuYXBpLnp1bGlwLmNvbTANBgkq
hkiG9w0BAQUFAAOCAQEAQKpkB8eRq5K2KBMVFolxSqix4qWo/uPiOQU6kbjkJNdK
P1Wg+p1R1KsLTLDEZmqTnfIBluez/RqfEoPdh+cF2e0GP55Y2ogno+89oaW4ijUr
IgTor/b1ZVv+yQIi/u27hLpq/h5E5ZM6HpmQ5YcA4z3MY7VoXNxYY5iO34YzuD0n
emoDuM1JJuGTzPkxE/dUzRU7GUmi5cXQgdGQ9lvutI/DuyZsDJV54TW2882cpW82
5x4a77Esvx7VlqBC5KxN/NPN/ZwIs5vl4F1+/sf2Tr7oMDkZ4Tc944mkj5MAbhhm
JZV4K+MlPPP7VSWOr+y+lMHAAqk7nhBi8MPP4XOo0A==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIE5TCCA82gAwIBAgIQB28SRoFFnCjVSNaXxA4AGzANBgkqhkiG9w0BAQUFADBv
MQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFk
ZFRydXN0IEV4dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBF
eHRlcm5hbCBDQSBSb290MB4XDTEyMDIxNjAwMDAwMFoXDTIwMDUzMDEwNDgzOFow
czELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxGTAXBgNV
BAMTEFBvc2l0aXZlU1NMIENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
AoIBAQDo6jnjIqaqucQA0OeqZztDB71Pkuu8vgGjQK3g70QotdA6voBUF4V6a4Rs
NjbloyTi/igBkLzX3Q+5K05IdwVpr95XMLHo+xoD9jxbUx6hAUlocnPWMytDqTcy
Ug+uJ1YxMGCtyb1zLDnukNh1sCUhYHsqfwL9goUfdE+SNHNcHQCgsMDqmOK+ARRY
FygiinddUCXNmmym5QzlqyjDsiCJ8AckHpXCLsDl6ez2PRIHSD3SwyNWQezT3zVL
yOf2hgVSEEOajBd8i6q8eODwRTusgFX+KJPhChFo9FJXb/5IC1tdGmpnc5mCtJ5D
YD7HWyoSbhruyzmuwzWdqLxdsC/DAgMBAAGjggF3MIIBczAfBgNVHSMEGDAWgBSt
vZh6NLQm9/rEJlTvA73gJMtUGjAdBgNVHQ4EFgQUmeRAX2sUXj4F2d3TY1T8Yrj3
AKwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwEQYDVR0gBAow
CDAGBgRVHSAAMEQGA1UdHwQ9MDswOaA3oDWGM2h0dHA6Ly9jcmwudXNlcnRydXN0
LmNvbS9BZGRUcnVzdEV4dGVybmFsQ0FSb290LmNybDCBswYIKwYBBQUHAQEEgaYw
gaMwPwYIKwYBBQUHMAKGM2h0dHA6Ly9jcnQudXNlcnRydXN0LmNvbS9BZGRUcnVz
dEV4dGVybmFsQ0FSb290LnA3YzA5BggrBgEFBQcwAoYtaHR0cDovL2NydC51c2Vy
dHJ1c3QuY29tL0FkZFRydXN0VVROU0dDQ0EuY3J0MCUGCCsGAQUFBzABhhlodHRw
Oi8vb2NzcC51c2VydHJ1c3QuY29tMA0GCSqGSIb3DQEBBQUAA4IBAQCcNuNOrvGK
u2yXjI9LZ9Cf2ISqnyFfNaFbxCtjDei8d12nxDf9Sy2e6B1pocCEzNFti/OBy59L
dLBJKjHoN0DrH9mXoxoR1Sanbg+61b4s/bSRZNy+OxlQDXqV8wQTqbtHD4tc0azC
e3chUN1bq+70ptjUSlNrTa24yOfmUlhNQ0zCoiNPDsAgOa/fT0JbHtMJ9BgJWSrZ
6EoYvzL7+i1ki4fKWyvouAt+vhcSxwOCKa9Yr4WEXT0K3yNRw82vEL+AaXeRCk/l
uuGtm87fM04wO+mPZn+C+mv626PAcwDj1hKvTfIPWhRRH224hoFiB85ccsJP81cq
cdnUl4XmGFO3
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEU
MBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFs
IFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290
MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFowbzELMAkGA1UEBhMCU0Ux
FDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRUcnVzdCBFeHRlcm5h
bCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0EgUm9v
dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvt
H7xsD821+iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9
uMq/NzgtHj6RQa1wVsfwTz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzX
mk6vBbOmcZSccbNQYArHE504B4YCqOmoaSYYkKtMsE8jqzpPhNjfzp/haW+710LX
a0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy2xSoRcRdKn23tNbE7qzN
E0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv77+ldU9U0
WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYD
VR0PBAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0
Jvf6xCZU7wO94CTLVBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRU
cnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsx
IjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJvb3SCAQEwDQYJKoZIhvcN
AQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZlj7DYd7usQWxH
YINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5
6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvC
Nr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEX
c4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5a
mnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ=
-----END CERTIFICATE-----

View File

@@ -0,0 +1,29 @@
-----BEGIN CERTIFICATE-----
MIIE+zCCA+OgAwIBAgIQDJOL1Hip5tpyq5kwwV/lQzANBgkqhkiG9w0BAQUFADBz
MQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYD
VQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01PRE8gQ0EgTGltaXRlZDEZMBcGA1UE
AxMQUG9zaXRpdmVTU0wgQ0EgMjAeFw0xMzA3MTIwMDAwMDBaFw0xNDA3MTIyMzU5
NTlaMFExITAfBgNVBAsTGERvbWFpbiBDb250cm9sIFZhbGlkYXRlZDEUMBIGA1UE
CxMLUG9zaXRpdmVTU0wxFjAUBgNVBAMTDWFwaS56dWxpcC5jb20wggEiMA0GCSqG
SIb3DQEBAQUAA4IBDwAwggEKAoIBAQC+GsCaNbs6bR4CB0MJ2NARH0JMoXsCVHHC
fT149arpZoAf9s4cmUgqe/qXl7jeh1Hb5UtARhchNMR/poFX9Dd73qTVfDEvtASW
ezpsEAB3KJQiISjUyL8xxRAggYf5AXtJ2QzaHoQ3sQk65lVuarB4aQwFB+SsbdtU
dDTHAgnJ3p8Vz4cFjus2n/EW+td5c74V7Y6nAj/ww8ygRRdAvfGmHa84ZHEu+xCI
5cnX0704hJETDfv1ELg257Rmg5pbwHfThSGs5KWv7AQqpLg+wNRD/s5LO1o6zB1z
Toidcq8HaD2/hS3oAQUibySRjieTHE1JU1ueqjfn0grrCpoSjgrDAgMBAAGjggGr
MIIBpzAfBgNVHSMEGDAWgBSZ5EBfaxRePgXZ3dNjVPxiuPcArDAdBgNVHQ4EFgQU
py+lc7gytud0YnB4ddplmEgkEeIwDgYDVR0PAQH/BAQDAgWgMAwGA1UdEwEB/wQC
MAAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMFAGA1UdIARJMEcwOwYL
KwYBBAGyMQECAgcwLDAqBggrBgEFBQcCARYeaHR0cDovL3d3dy5wb3NpdGl2ZXNz
bC5jb20vQ1BTMAgGBmeBDAECATA7BgNVHR8ENDAyMDCgLqAshipodHRwOi8vY3Js
LmNvbW9kb2NhLmNvbS9Qb3NpdGl2ZVNTTENBMi5jcmwwbAYIKwYBBQUHAQEEYDBe
MDYGCCsGAQUFBzAChipodHRwOi8vY3J0LmNvbW9kb2NhLmNvbS9Qb3NpdGl2ZVNT
TENBMi5jcnQwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmNvbW9kb2NhLmNvbTAr
BgNVHREEJDAigg1hcGkuenVsaXAuY29tghF3d3cuYXBpLnp1bGlwLmNvbTANBgkq
hkiG9w0BAQUFAAOCAQEAQKpkB8eRq5K2KBMVFolxSqix4qWo/uPiOQU6kbjkJNdK
P1Wg+p1R1KsLTLDEZmqTnfIBluez/RqfEoPdh+cF2e0GP55Y2ogno+89oaW4ijUr
IgTor/b1ZVv+yQIi/u27hLpq/h5E5ZM6HpmQ5YcA4z3MY7VoXNxYY5iO34YzuD0n
emoDuM1JJuGTzPkxE/dUzRU7GUmi5cXQgdGQ9lvutI/DuyZsDJV54TW2882cpW82
5x4a77Esvx7VlqBC5KxN/NPN/ZwIs5vl4F1+/sf2Tr7oMDkZ4Tc944mkj5MAbhhm
JZV4K+MlPPP7VSWOr+y+lMHAAqk7nhBi8MPP4XOo0A==
-----END CERTIFICATE-----

View File

@@ -1,59 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIFSzCCBDOgAwIBAgIQC9+c6kd+aB3quGVISZS4fzANBgkqhkiG9w0BAQsFADBw
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMS8wLQYDVQQDEyZEaWdpQ2VydCBTSEEyIEhpZ2ggQXNz
dXJhbmNlIFNlcnZlciBDQTAeFw0xNTAyMDYwMDAwMDBaFw0xNzAyMDkxMjAwMDBa
MG4xCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1T
YW4gRnJhbmNpc2NvMRUwEwYDVQQKEwxEcm9wYm94LCBJbmMxGzAZBgNVBAMTEmNo
YXQuZHJvcGJveGVyLm5ldDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
AO8HnnyDj64aGeEoFewFuASlpw8YzBnbF9E1A4CFdevwXCfHhDUXUZd3nGwHTlUc
Yq/Yn6iDc0S08ZTM5OJmeeNxsZojHK6CaZjKEiRkerRVwq7AWEPvJWdVlmRjDXMX
rpGlL44L9voeKDr4ueq9uP85QIffbtF7wRFjxHH5ULPxcVFGeFsShaaWkK1YdVl0
C0KarUBxX6Dz0J5KB9Am2qGz7fEGmMeYmLjUQEohvD+NLnSHIH1gCCrnMDyp7SX4
iVlSwJBfZJB71uTB2+9CX3k+jgMA6l+KrjyUoFTJmxGkcwyEqKoCoJG2mL81L0fZ
Yx55K1kJh6qBXAg4JIwMD7UCAwEAAaOCAeEwggHdMB8GA1UdIwQYMBaAFFFo/5Cv
Agd1PMzZZWRiohK4WXI7MB0GA1UdDgQWBBQgWnzJolAbDp9oilo3SuR3LPcSIDAd
BgNVHREEFjAUghJjaGF0LmRyb3Bib3hlci5uZXQwDgYDVR0PAQH/BAQDAgWgMB0G
A1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjB1BgNVHR8EbjBsMDSgMqAwhi5o
dHRwOi8vY3JsMy5kaWdpY2VydC5jb20vc2hhMi1oYS1zZXJ2ZXItZzMuY3JsMDSg
MqAwhi5odHRwOi8vY3JsNC5kaWdpY2VydC5jb20vc2hhMi1oYS1zZXJ2ZXItZzMu
Y3JsMEIGA1UdIAQ7MDkwNwYJYIZIAYb9bAEBMCowKAYIKwYBBQUHAgEWHGh0dHBz
Oi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwgYMGCCsGAQUFBwEBBHcwdTAkBggrBgEF
BQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tME0GCCsGAQUFBzAChkFodHRw
Oi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRTSEEySGlnaEFzc3VyYW5j
ZVNlcnZlckNBLmNydDAMBgNVHRMBAf8EAjAAMA0GCSqGSIb3DQEBCwUAA4IBAQCa
dUkIIbDl2iEmWE//z9jPgFboPzkzDR+03cBuvBRkqQ8SD/+pfB/TiZQerKS+xcy7
NB/0kvBnMqGsknXYL9w2rGFv0R/sDHDCiwtxh+1mwS9r+AvmCRkA3T7mcSO3O9lI
dIbrIhPJHvmyac7rCAvmW1i4KTbCSaBOLLmSnXjLpa6E3zrv4Xn2k8u6eOCLNgqV
89qswf/pYZcvHKgyFZ9PdhwXxV9MO1c9U/GCWOZWXextAtmAvbxJDkc2JqT2mS1D
8GvkaMudfm1o/dYvv9F0tgsh4UGpWnvlp8IXZil2Ik4m2yfc37MoNgpNa0ytEJUp
tFDLVilooSEBYckHRdm+
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIEsTCCA5mgAwIBAgIQBOHnpNxc8vNtwCtCuF0VnzANBgkqhkiG9w0BAQsFADBs
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j
ZSBFViBSb290IENBMB4XDTEzMTAyMjEyMDAwMFoXDTI4MTAyMjEyMDAwMFowcDEL
MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3
LmRpZ2ljZXJ0LmNvbTEvMC0GA1UEAxMmRGlnaUNlcnQgU0hBMiBIaWdoIEFzc3Vy
YW5jZSBTZXJ2ZXIgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC2
4C/CJAbIbQRf1+8KZAayfSImZRauQkCbztyfn3YHPsMwVYcZuU+UDlqUH1VWtMIC
Kq/QmO4LQNfE0DtyyBSe75CxEamu0si4QzrZCwvV1ZX1QK/IHe1NnF9Xt4ZQaJn1
itrSxwUfqJfJ3KSxgoQtxq2lnMcZgqaFD15EWCo3j/018QsIJzJa9buLnqS9UdAn
4t07QjOjBSjEuyjMmqwrIw14xnvmXnG3Sj4I+4G3FhahnSMSTeXXkgisdaScus0X
sh5ENWV/UyU50RwKmmMbGZJ0aAo3wsJSSMs5WqK24V3B3aAguCGikyZvFEohQcft
bZvySC/zA/WiaJJTL17jAgMBAAGjggFJMIIBRTASBgNVHRMBAf8ECDAGAQH/AgEA
MA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw
NAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2Vy
dC5jb20wSwYDVR0fBEQwQjBAoD6gPIY6aHR0cDovL2NybDQuZGlnaWNlcnQuY29t
L0RpZ2lDZXJ0SGlnaEFzc3VyYW5jZUVWUm9vdENBLmNybDA9BgNVHSAENjA0MDIG
BFUdIAAwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQ
UzAdBgNVHQ4EFgQUUWj/kK8CB3U8zNllZGKiErhZcjswHwYDVR0jBBgwFoAUsT7D
aQP4v0cB1JgmGggC72NkK8MwDQYJKoZIhvcNAQELBQADggEBABiKlYkD5m3fXPwd
aOpKj4PWUS+Na0QWnqxj9dJubISZi6qBcYRb7TROsLd5kinMLYBq8I4g4Xmk/gNH
E+r1hspZcX30BJZr01lYPf7TMSVcGDiEo+afgv2MW5gxTs14nhr9hctJqvIni5ly
/D6q1UEL2tU2ob8cbkdJf17ZSHwD2f2LSaCYJkJA69aSEaRkCldUxPUd1gJea6zu
xICaEnL6VpPX/78whQYwvwt/Tv9XBZ0k7YXDK/umdaisLRbvfXknsuvCnQsH6qqF
0wGjIChBWUMo0oHjqvbsezt3tkBigAVBRQHvFwY+3sAzm2fTYS5yh+Rp/BIAV0Ae
cPUeybQ=
-----END CERTIFICATE-----

View File

@@ -1,59 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIFQTCCBCmgAwIBAgIQAiBxGEAt+S6rlqaxlh4i9TANBgkqhkiG9w0BAQsFADBw
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMS8wLQYDVQQDEyZEaWdpQ2VydCBTSEEyIEhpZ2ggQXNz
dXJhbmNlIFNlcnZlciBDQTAeFw0xNDA0MTYwMDAwMDBaFw0xNjA0MjAxMjAwMDBa
MGkxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1T
YW4gRnJhbmNpc2NvMRUwEwYDVQQKEwxEcm9wYm94LCBJbmMxFjAUBgNVBAMTDWdp
dC56dWxpcC5uZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCgo7bC
QDUprWNwBgGI1uytomGzO141oZQq0TY4VI/EXiAQ1gClyJ6NgEBPD+RVK4/82JIW
RLkztIaM3uyO6JXOBzDifehI32l2Tqj0ZtvipOzE/IJyucAXvVocHCtseKpCcUB0
pSXhie2RH9y0cTRZHMY7OW5N3+SE+W4W57eo0QCHzhKetcD0AOdIx1rDltuyPHCr
xybH4LIYTMsE71Nx7RZI3KJvlWUNQtvY0bF9Xy/2Ag47mLf1vlpWkvWRNTWd6t5v
7zcNAbohYAaeGrUrhFbTojIjzd31BioZPY5N4XJYDQCtlk+g3EhsarPRAsJ3+C/e
HJC3JVYxEtScUlULAgMBAAGjggHcMIIB2DAfBgNVHSMEGDAWgBRRaP+QrwIHdTzM
2WVkYqISuFlyOzAdBgNVHQ4EFgQU/AFjeJNjGOJat2Ng5D/djicf7lIwGAYDVR0R
BBEwD4INZ2l0Lnp1bGlwLm5ldDAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYI
KwYBBQUHAwEGCCsGAQUFBwMCMHUGA1UdHwRuMGwwNKAyoDCGLmh0dHA6Ly9jcmwz
LmRpZ2ljZXJ0LmNvbS9zaGEyLWhhLXNlcnZlci1nMi5jcmwwNKAyoDCGLmh0dHA6
Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWhhLXNlcnZlci1nMi5jcmwwQgYDVR0g
BDswOTA3BglghkgBhv1sAQEwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGln
aWNlcnQuY29tL0NQUzCBgwYIKwYBBQUHAQEEdzB1MCQGCCsGAQUFBzABhhhodHRw
Oi8vb2NzcC5kaWdpY2VydC5jb20wTQYIKwYBBQUHMAKGQWh0dHA6Ly9jYWNlcnRz
LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFNIQTJIaWdoQXNzdXJhbmNlU2VydmVyQ0Eu
Y3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggEBAJUD9412uJCVG5lZ
AYWKQ101Mx5+IcbiNhFpyXiPhmPDHD+qAZUCoFbdcPA9U9AOwcI55+Z6hZ7bcYhB
KOSMEf60hwQbN1CdvR6oV25DZ6QbBF8R6PLMEym/T4auVj98wA1J1kgVS33SRoWt
PWa4eVXxJL/977CMJNoYh5hjmxivXq7swIrn+xA4D79euFPZdzqov6+oKtzRQNY5
qATfF4GD4Sj6qZqIetuIv42BcUGd+s0VH6GMDvKlcDA51q7N8WVoGrsIRHmOV2qF
fNSpzreV9YDFOv0KUJCThdJiwdJVNS/ZgE1fNvyhCNcbISBkfkSR8rROu5LY0xDB
51QMgbM=
-----END CERTIFICATE-----
N CERTIFICATE-----
MIIEsTCCA5mgAwIBAgIQBOHnpNxc8vNtwCtCuF0VnzANBgkqhkiG9w0BAQsFADBs
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j
ZSBFViBSb290IENBMB4XDTEzMTAyMjEyMDAwMFoXDTI4MTAyMjEyMDAwMFowcDEL
MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3
LmRpZ2ljZXJ0LmNvbTEvMC0GA1UEAxMmRGlnaUNlcnQgU0hBMiBIaWdoIEFzc3Vy
YW5jZSBTZXJ2ZXIgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC2
4C/CJAbIbQRf1+8KZAayfSImZRauQkCbztyfn3YHPsMwVYcZuU+UDlqUH1VWtMIC
Kq/QmO4LQNfE0DtyyBSe75CxEamu0si4QzrZCwvV1ZX1QK/IHe1NnF9Xt4ZQaJn1
itrSxwUfqJfJ3KSxgoQtxq2lnMcZgqaFD15EWCo3j/018QsIJzJa9buLnqS9UdAn
4t07QjOjBSjEuyjMmqwrIw14xnvmXnG3Sj4I+4G3FhahnSMSTeXXkgisdaScus0X
sh5ENWV/UyU50RwKmmMbGZJ0aAo3wsJSSMs5WqK24V3B3aAguCGikyZvFEohQcft
bZvySC/zA/WiaJJTL17jAgMBAAGjggFJMIIBRTASBgNVHRMBAf8ECDAGAQH/AgEA
MA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw
NAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2Vy
dC5jb20wSwYDVR0fBEQwQjBAoD6gPIY6aHR0cDovL2NybDQuZGlnaWNlcnQuY29t
L0RpZ2lDZXJ0SGlnaEFzc3VyYW5jZUVWUm9vdENBLmNybDA9BgNVHSAENjA0MDIG
BFUdIAAwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQ
UzAdBgNVHQ4EFgQUUWj/kK8CB3U8zNllZGKiErhZcjswHwYDVR0jBBgwFoAUsT7D
aQP4v0cB1JgmGggC72NkK8MwDQYJKoZIhvcNAQELBQADggEBABiKlYkD5m3fXPwd
aOpKj4PWUS+Na0QWnqxj9dJubISZi6qBcYRb7TROsLd5kinMLYBq8I4g4Xmk/gNH
E+r1hspZcX30BJZr01lYPf7TMSVcGDiEo+afgv2MW5gxTs14nhr9hctJqvIni5ly
/D6q1UEL2tU2ob8cbkdJf17ZSHwD2f2LSaCYJkJA69aSEaRkCldUxPUd1gJea6zu
xICaEnL6VpPX/78whQYwvwt/Tv9XBZ0k7YXDK/umdaisLRbvfXknsuvCnQsH6qqF
0wGjIChBWUMo0oHjqvbsezt3tkBigAVBRQHvFwY+3sAzm2fTYS5yh+Rp/BIAV0Ae
cPUeybQ=
-----END CERTIFICATE-----

View File

@@ -1,31 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIFQTCCBCmgAwIBAgIQAiBxGEAt+S6rlqaxlh4i9TANBgkqhkiG9w0BAQsFADBw
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMS8wLQYDVQQDEyZEaWdpQ2VydCBTSEEyIEhpZ2ggQXNz
dXJhbmNlIFNlcnZlciBDQTAeFw0xNDA0MTYwMDAwMDBaFw0xNjA0MjAxMjAwMDBa
MGkxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1T
YW4gRnJhbmNpc2NvMRUwEwYDVQQKEwxEcm9wYm94LCBJbmMxFjAUBgNVBAMTDWdp
dC56dWxpcC5uZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCgo7bC
QDUprWNwBgGI1uytomGzO141oZQq0TY4VI/EXiAQ1gClyJ6NgEBPD+RVK4/82JIW
RLkztIaM3uyO6JXOBzDifehI32l2Tqj0ZtvipOzE/IJyucAXvVocHCtseKpCcUB0
pSXhie2RH9y0cTRZHMY7OW5N3+SE+W4W57eo0QCHzhKetcD0AOdIx1rDltuyPHCr
xybH4LIYTMsE71Nx7RZI3KJvlWUNQtvY0bF9Xy/2Ag47mLf1vlpWkvWRNTWd6t5v
7zcNAbohYAaeGrUrhFbTojIjzd31BioZPY5N4XJYDQCtlk+g3EhsarPRAsJ3+C/e
HJC3JVYxEtScUlULAgMBAAGjggHcMIIB2DAfBgNVHSMEGDAWgBRRaP+QrwIHdTzM
2WVkYqISuFlyOzAdBgNVHQ4EFgQU/AFjeJNjGOJat2Ng5D/djicf7lIwGAYDVR0R
BBEwD4INZ2l0Lnp1bGlwLm5ldDAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYI
KwYBBQUHAwEGCCsGAQUFBwMCMHUGA1UdHwRuMGwwNKAyoDCGLmh0dHA6Ly9jcmwz
LmRpZ2ljZXJ0LmNvbS9zaGEyLWhhLXNlcnZlci1nMi5jcmwwNKAyoDCGLmh0dHA6
Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWhhLXNlcnZlci1nMi5jcmwwQgYDVR0g
BDswOTA3BglghkgBhv1sAQEwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGln
aWNlcnQuY29tL0NQUzCBgwYIKwYBBQUHAQEEdzB1MCQGCCsGAQUFBzABhhhodHRw
Oi8vb2NzcC5kaWdpY2VydC5jb20wTQYIKwYBBQUHMAKGQWh0dHA6Ly9jYWNlcnRz
LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFNIQTJIaWdoQXNzdXJhbmNlU2VydmVyQ0Eu
Y3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggEBAJUD9412uJCVG5lZ
AYWKQ101Mx5+IcbiNhFpyXiPhmPDHD+qAZUCoFbdcPA9U9AOwcI55+Z6hZ7bcYhB
KOSMEf60hwQbN1CdvR6oV25DZ6QbBF8R6PLMEym/T4auVj98wA1J1kgVS33SRoWt
PWa4eVXxJL/977CMJNoYh5hjmxivXq7swIrn+xA4D79euFPZdzqov6+oKtzRQNY5
qATfF4GD4Sj6qZqIetuIv42BcUGd+s0VH6GMDvKlcDA51q7N8WVoGrsIRHmOV2qF
fNSpzreV9YDFOv0KUJCThdJiwdJVNS/ZgE1fNvyhCNcbISBkfkSR8rROu5LY0xDB
51QMgbM=
-----END CERTIFICATE-----

View File

@@ -1,59 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIFRTCCBC2gAwIBAgIQDDxR9Pi3OvaLaxM1QQINATANBgkqhkiG9w0BAQsFADBw
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMS8wLQYDVQQDEyZEaWdpQ2VydCBTSEEyIEhpZ2ggQXNz
dXJhbmNlIFNlcnZlciBDQTAeFw0xNDA0MTYwMDAwMDBaFw0xNjA0MjAxMjAwMDBa
MGsxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1T
YW4gRnJhbmNpc2NvMRUwEwYDVQQKEwxEcm9wYm94LCBJbmMxGDAWBgNVBAMTD211
bmluLnp1bGlwLm5ldDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMmH
EH72mRFJapF9jJAHZs1dDxka0DD6vEzIlUPylq009VZguROUm1/2/37vtOaZdoRP
zJ+LNq1Aeam3JdVuNd2EA4Rl0UbZM1P+yMggfffMzLczQRTumSCaOPq5SMqnS0az
2UITCxknaQmW8g4nbLElChbW7GYFIYxSizfz5yTqV25mqMN1IIDpRJghGU6154Pk
VSPWvynzWmDAW9UJDBT9dqJp3TAFKNzQGad1ERkkPr2XXd71KjjLFfqKiVCAK4oq
r281CQEHh7uUPVq0zrwLvtCPaMx7Zq+0a82/ABnA2wEDiptSXZ6K/2LF/otGzXsy
udTRD/0hTBQ0R5Y9DscCAwEAAaOCAd4wggHaMB8GA1UdIwQYMBaAFFFo/5CvAgd1
PMzZZWRiohK4WXI7MB0GA1UdDgQWBBRsJooKV4ptTkrJjKsAJ7CwyvzzqTAaBgNV
HREEEzARgg9tdW5pbi56dWxpcC5uZXQwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQW
MBQGCCsGAQUFBwMBBggrBgEFBQcDAjB1BgNVHR8EbjBsMDSgMqAwhi5odHRwOi8v
Y3JsMy5kaWdpY2VydC5jb20vc2hhMi1oYS1zZXJ2ZXItZzIuY3JsMDSgMqAwhi5o
dHRwOi8vY3JsNC5kaWdpY2VydC5jb20vc2hhMi1oYS1zZXJ2ZXItZzIuY3JsMEIG
A1UdIAQ7MDkwNwYJYIZIAYb9bAEBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3
LmRpZ2ljZXJ0LmNvbS9DUFMwgYMGCCsGAQUFBwEBBHcwdTAkBggrBgEFBQcwAYYY
aHR0cDovL29jc3AuZGlnaWNlcnQuY29tME0GCCsGAQUFBzAChkFodHRwOi8vY2Fj
ZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRTSEEySGlnaEFzc3VyYW5jZVNlcnZl
ckNBLmNydDAMBgNVHRMBAf8EAjAAMA0GCSqGSIb3DQEBCwUAA4IBAQAjA309Hd9C
lrPzMKjJTXP6G9PUH3YpkUVdRitV5lrNZwfQL5SomehxL9KG58Obvzuae0SJMWfE
ODP6jkPywbv0n4RKaQEQwB80CZj4nKqrnsJGToSVWE+Wso/E6tBF3NjFqZzVNok2
+ql6rElmI9H0n7be6x78p4TGqzEEbnS56hlppWXYQXPWi40vJSQCo8/YIy62L6wj
Ulaqdx+sqxE7qR/AwhWlsFpcKP2XRN91fzPtKj/mlGyyYk6r1gnhoqvSlQqqucKs
UJ60uG8I4hfwbGIJyuCX3ipvhl9RpH+UL4MQCPD8sKxQfnn7T5iEQylWubCsU3K5
ORxuyUfWjLpo
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIEsTCCA5mgAwIBAgIQBOHnpNxc8vNtwCtCuF0VnzANBgkqhkiG9w0BAQsFADBs
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j
ZSBFViBSb290IENBMB4XDTEzMTAyMjEyMDAwMFoXDTI4MTAyMjEyMDAwMFowcDEL
MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3
LmRpZ2ljZXJ0LmNvbTEvMC0GA1UEAxMmRGlnaUNlcnQgU0hBMiBIaWdoIEFzc3Vy
YW5jZSBTZXJ2ZXIgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC2
4C/CJAbIbQRf1+8KZAayfSImZRauQkCbztyfn3YHPsMwVYcZuU+UDlqUH1VWtMIC
Kq/QmO4LQNfE0DtyyBSe75CxEamu0si4QzrZCwvV1ZX1QK/IHe1NnF9Xt4ZQaJn1
itrSxwUfqJfJ3KSxgoQtxq2lnMcZgqaFD15EWCo3j/018QsIJzJa9buLnqS9UdAn
4t07QjOjBSjEuyjMmqwrIw14xnvmXnG3Sj4I+4G3FhahnSMSTeXXkgisdaScus0X
sh5ENWV/UyU50RwKmmMbGZJ0aAo3wsJSSMs5WqK24V3B3aAguCGikyZvFEohQcft
bZvySC/zA/WiaJJTL17jAgMBAAGjggFJMIIBRTASBgNVHRMBAf8ECDAGAQH/AgEA
MA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw
NAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2Vy
dC5jb20wSwYDVR0fBEQwQjBAoD6gPIY6aHR0cDovL2NybDQuZGlnaWNlcnQuY29t
L0RpZ2lDZXJ0SGlnaEFzc3VyYW5jZUVWUm9vdENBLmNybDA9BgNVHSAENjA0MDIG
BFUdIAAwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQ
UzAdBgNVHQ4EFgQUUWj/kK8CB3U8zNllZGKiErhZcjswHwYDVR0jBBgwFoAUsT7D
aQP4v0cB1JgmGggC72NkK8MwDQYJKoZIhvcNAQELBQADggEBABiKlYkD5m3fXPwd
aOpKj4PWUS+Na0QWnqxj9dJubISZi6qBcYRb7TROsLd5kinMLYBq8I4g4Xmk/gNH
E+r1hspZcX30BJZr01lYPf7TMSVcGDiEo+afgv2MW5gxTs14nhr9hctJqvIni5ly
/D6q1UEL2tU2ob8cbkdJf17ZSHwD2f2LSaCYJkJA69aSEaRkCldUxPUd1gJea6zu
xICaEnL6VpPX/78whQYwvwt/Tv9XBZ0k7YXDK/umdaisLRbvfXknsuvCnQsH6qqF
0wGjIChBWUMo0oHjqvbsezt3tkBigAVBRQHvFwY+3sAzm2fTYS5yh+Rp/BIAV0Ae
cPUeybQ=
-----END CERTIFICATE-----

View File

@@ -1,31 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIFRTCCBC2gAwIBAgIQDDxR9Pi3OvaLaxM1QQINATANBgkqhkiG9w0BAQsFADBw
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMS8wLQYDVQQDEyZEaWdpQ2VydCBTSEEyIEhpZ2ggQXNz
dXJhbmNlIFNlcnZlciBDQTAeFw0xNDA0MTYwMDAwMDBaFw0xNjA0MjAxMjAwMDBa
MGsxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1T
YW4gRnJhbmNpc2NvMRUwEwYDVQQKEwxEcm9wYm94LCBJbmMxGDAWBgNVBAMTD211
bmluLnp1bGlwLm5ldDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMmH
EH72mRFJapF9jJAHZs1dDxka0DD6vEzIlUPylq009VZguROUm1/2/37vtOaZdoRP
zJ+LNq1Aeam3JdVuNd2EA4Rl0UbZM1P+yMggfffMzLczQRTumSCaOPq5SMqnS0az
2UITCxknaQmW8g4nbLElChbW7GYFIYxSizfz5yTqV25mqMN1IIDpRJghGU6154Pk
VSPWvynzWmDAW9UJDBT9dqJp3TAFKNzQGad1ERkkPr2XXd71KjjLFfqKiVCAK4oq
r281CQEHh7uUPVq0zrwLvtCPaMx7Zq+0a82/ABnA2wEDiptSXZ6K/2LF/otGzXsy
udTRD/0hTBQ0R5Y9DscCAwEAAaOCAd4wggHaMB8GA1UdIwQYMBaAFFFo/5CvAgd1
PMzZZWRiohK4WXI7MB0GA1UdDgQWBBRsJooKV4ptTkrJjKsAJ7CwyvzzqTAaBgNV
HREEEzARgg9tdW5pbi56dWxpcC5uZXQwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQW
MBQGCCsGAQUFBwMBBggrBgEFBQcDAjB1BgNVHR8EbjBsMDSgMqAwhi5odHRwOi8v
Y3JsMy5kaWdpY2VydC5jb20vc2hhMi1oYS1zZXJ2ZXItZzIuY3JsMDSgMqAwhi5o
dHRwOi8vY3JsNC5kaWdpY2VydC5jb20vc2hhMi1oYS1zZXJ2ZXItZzIuY3JsMEIG
A1UdIAQ7MDkwNwYJYIZIAYb9bAEBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3
LmRpZ2ljZXJ0LmNvbS9DUFMwgYMGCCsGAQUFBwEBBHcwdTAkBggrBgEFBQcwAYYY
aHR0cDovL29jc3AuZGlnaWNlcnQuY29tME0GCCsGAQUFBzAChkFodHRwOi8vY2Fj
ZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRTSEEySGlnaEFzc3VyYW5jZVNlcnZl
ckNBLmNydDAMBgNVHRMBAf8EAjAAMA0GCSqGSIb3DQEBCwUAA4IBAQAjA309Hd9C
lrPzMKjJTXP6G9PUH3YpkUVdRitV5lrNZwfQL5SomehxL9KG58Obvzuae0SJMWfE
ODP6jkPywbv0n4RKaQEQwB80CZj4nKqrnsJGToSVWE+Wso/E6tBF3NjFqZzVNok2
+ql6rElmI9H0n7be6x78p4TGqzEEbnS56hlppWXYQXPWi40vJSQCo8/YIy62L6wj
Ulaqdx+sqxE7qR/AwhWlsFpcKP2XRN91fzPtKj/mlGyyYk6r1gnhoqvSlQqqucKs
UJ60uG8I4hfwbGIJyuCX3ipvhl9RpH+UL4MQCPD8sKxQfnn7T5iEQylWubCsU3K5
ORxuyUfWjLpo
-----END CERTIFICATE-----

View File

@@ -1,59 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIFRzCCBC+gAwIBAgIQCwfY+SvxDTFK0KY29dqHWjANBgkqhkiG9w0BAQsFADBw
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMS8wLQYDVQQDEyZEaWdpQ2VydCBTSEEyIEhpZ2ggQXNz
dXJhbmNlIFNlcnZlciBDQTAeFw0xNDA0MTYwMDAwMDBaFw0xNjA0MjAxMjAwMDBa
MGwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1T
YW4gRnJhbmNpc2NvMRUwEwYDVQQKEwxEcm9wYm94LCBJbmMxGTAXBgNVBAMTEG5h
Z2lvcy56dWxpcC5uZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCy
J6F6KjG/Y1vf3oj947a+otyc/BFH81K9AsZUrL46kXoCkdr6SJqJDKYLn/adv+OI
GTDo8LpbISE2FkviRFgUEIAkHcxdF4UMv1fpby2VcYleFigD2Fn+LkWcCpqk9uRL
VhAgbZdXLLw0LtTMp0kESO+DsjpfbwjNP+POZBLN96PoOToiUmNJKwhLucckmo/K
QrEfwRdDxJfD12NYCl8ZEOFfQEinWmstvschCM1LOeZTBDBHFXOvi1xhPu8utpHJ
xdibN0vWn17Cole0Blris3sT34KA/FRswCJ4jTxtL58WIE19YLiLDoP3kDNuNjZc
uhXk/sgqrGqam5GQfUOhAgMBAAGjggHfMIIB2zAfBgNVHSMEGDAWgBRRaP+QrwIH
dTzM2WVkYqISuFlyOzAdBgNVHQ4EFgQUGk12Sw4Clj8YyjOggnJ7LXTXRoAwGwYD
VR0RBBQwEoIQbmFnaW9zLnp1bGlwLm5ldDAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0l
BBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMHUGA1UdHwRuMGwwNKAyoDCGLmh0dHA6
Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9zaGEyLWhhLXNlcnZlci1nMi5jcmwwNKAyoDCG
Lmh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWhhLXNlcnZlci1nMi5jcmww
QgYDVR0gBDswOTA3BglghkgBhv1sAQEwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93
d3cuZGlnaWNlcnQuY29tL0NQUzCBgwYIKwYBBQUHAQEEdzB1MCQGCCsGAQUFBzAB
hhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wTQYIKwYBBQUHMAKGQWh0dHA6Ly9j
YWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFNIQTJIaWdoQXNzdXJhbmNlU2Vy
dmVyQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggEBACsGRuZG
SVqbo/VtJJCOLSS4+IeyaPWqvH0e7Nlt4NPrgZVoI+JBPhwEnfbtGPX4epIu+gRF
1Zazk0E9nGUh5AUatruz0wq/FCj4eg+koV1XJLwlJde/s2IgEilG15wBWhH02uJo
oM+wScbr4rPxwgB4Dytz/HAYIXzMyPdYr0/zFGBpCtHIDd5E1mFyCn+0tCh0TRBm
YleHUA6A7CXq9iKNknIpJw/BDOYLtNz91qCBL4U3sB9kfJ4HEF9jC8/HhlW6IH1r
B5zjnj4D0FDyJSzBF44HUbzCxp7t/rEnQTASSdQaMcm9T7rqw8doJ8umnDLLeqp5
2IeiKC3ePDOsopE=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIEsTCCA5mgAwIBAgIQBOHnpNxc8vNtwCtCuF0VnzANBgkqhkiG9w0BAQsFADBs
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j
ZSBFViBSb290IENBMB4XDTEzMTAyMjEyMDAwMFoXDTI4MTAyMjEyMDAwMFowcDEL
MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3
LmRpZ2ljZXJ0LmNvbTEvMC0GA1UEAxMmRGlnaUNlcnQgU0hBMiBIaWdoIEFzc3Vy
YW5jZSBTZXJ2ZXIgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC2
4C/CJAbIbQRf1+8KZAayfSImZRauQkCbztyfn3YHPsMwVYcZuU+UDlqUH1VWtMIC
Kq/QmO4LQNfE0DtyyBSe75CxEamu0si4QzrZCwvV1ZX1QK/IHe1NnF9Xt4ZQaJn1
itrSxwUfqJfJ3KSxgoQtxq2lnMcZgqaFD15EWCo3j/018QsIJzJa9buLnqS9UdAn
4t07QjOjBSjEuyjMmqwrIw14xnvmXnG3Sj4I+4G3FhahnSMSTeXXkgisdaScus0X
sh5ENWV/UyU50RwKmmMbGZJ0aAo3wsJSSMs5WqK24V3B3aAguCGikyZvFEohQcft
bZvySC/zA/WiaJJTL17jAgMBAAGjggFJMIIBRTASBgNVHRMBAf8ECDAGAQH/AgEA
MA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw
NAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2Vy
dC5jb20wSwYDVR0fBEQwQjBAoD6gPIY6aHR0cDovL2NybDQuZGlnaWNlcnQuY29t
L0RpZ2lDZXJ0SGlnaEFzc3VyYW5jZUVWUm9vdENBLmNybDA9BgNVHSAENjA0MDIG
BFUdIAAwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQ
UzAdBgNVHQ4EFgQUUWj/kK8CB3U8zNllZGKiErhZcjswHwYDVR0jBBgwFoAUsT7D
aQP4v0cB1JgmGggC72NkK8MwDQYJKoZIhvcNAQELBQADggEBABiKlYkD5m3fXPwd
aOpKj4PWUS+Na0QWnqxj9dJubISZi6qBcYRb7TROsLd5kinMLYBq8I4g4Xmk/gNH
E+r1hspZcX30BJZr01lYPf7TMSVcGDiEo+afgv2MW5gxTs14nhr9hctJqvIni5ly
/D6q1UEL2tU2ob8cbkdJf17ZSHwD2f2LSaCYJkJA69aSEaRkCldUxPUd1gJea6zu
xICaEnL6VpPX/78whQYwvwt/Tv9XBZ0k7YXDK/umdaisLRbvfXknsuvCnQsH6qqF
0wGjIChBWUMo0oHjqvbsezt3tkBigAVBRQHvFwY+3sAzm2fTYS5yh+Rp/BIAV0Ae
cPUeybQ=
-----END CERTIFICATE-----

View File

@@ -1,31 +1,36 @@
-----BEGIN CERTIFICATE-----
MIIFRzCCBC+gAwIBAgIQCwfY+SvxDTFK0KY29dqHWjANBgkqhkiG9w0BAQsFADBw
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMS8wLQYDVQQDEyZEaWdpQ2VydCBTSEEyIEhpZ2ggQXNz
dXJhbmNlIFNlcnZlciBDQTAeFw0xNDA0MTYwMDAwMDBaFw0xNjA0MjAxMjAwMDBa
MGwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1T
YW4gRnJhbmNpc2NvMRUwEwYDVQQKEwxEcm9wYm94LCBJbmMxGTAXBgNVBAMTEG5h
Z2lvcy56dWxpcC5uZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCy
J6F6KjG/Y1vf3oj947a+otyc/BFH81K9AsZUrL46kXoCkdr6SJqJDKYLn/adv+OI
GTDo8LpbISE2FkviRFgUEIAkHcxdF4UMv1fpby2VcYleFigD2Fn+LkWcCpqk9uRL
VhAgbZdXLLw0LtTMp0kESO+DsjpfbwjNP+POZBLN96PoOToiUmNJKwhLucckmo/K
QrEfwRdDxJfD12NYCl8ZEOFfQEinWmstvschCM1LOeZTBDBHFXOvi1xhPu8utpHJ
xdibN0vWn17Cole0Blris3sT34KA/FRswCJ4jTxtL58WIE19YLiLDoP3kDNuNjZc
uhXk/sgqrGqam5GQfUOhAgMBAAGjggHfMIIB2zAfBgNVHSMEGDAWgBRRaP+QrwIH
dTzM2WVkYqISuFlyOzAdBgNVHQ4EFgQUGk12Sw4Clj8YyjOggnJ7LXTXRoAwGwYD
VR0RBBQwEoIQbmFnaW9zLnp1bGlwLm5ldDAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0l
BBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMHUGA1UdHwRuMGwwNKAyoDCGLmh0dHA6
Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9zaGEyLWhhLXNlcnZlci1nMi5jcmwwNKAyoDCG
Lmh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWhhLXNlcnZlci1nMi5jcmww
QgYDVR0gBDswOTA3BglghkgBhv1sAQEwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93
d3cuZGlnaWNlcnQuY29tL0NQUzCBgwYIKwYBBQUHAQEEdzB1MCQGCCsGAQUFBzAB
hhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wTQYIKwYBBQUHMAKGQWh0dHA6Ly9j
YWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFNIQTJIaWdoQXNzdXJhbmNlU2Vy
dmVyQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggEBACsGRuZG
SVqbo/VtJJCOLSS4+IeyaPWqvH0e7Nlt4NPrgZVoI+JBPhwEnfbtGPX4epIu+gRF
1Zazk0E9nGUh5AUatruz0wq/FCj4eg+koV1XJLwlJde/s2IgEilG15wBWhH02uJo
oM+wScbr4rPxwgB4Dytz/HAYIXzMyPdYr0/zFGBpCtHIDd5E1mFyCn+0tCh0TRBm
YleHUA6A7CXq9iKNknIpJw/BDOYLtNz91qCBL4U3sB9kfJ4HEF9jC8/HhlW6IH1r
B5zjnj4D0FDyJSzBF44HUbzCxp7t/rEnQTASSdQaMcm9T7rqw8doJ8umnDLLeqp5
2IeiKC3ePDOsopE=
MIIGVDCCBTygAwIBAgIDC9I3MA0GCSqGSIb3DQEBBQUAMIGMMQswCQYDVQQGEwJJ
TDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0
YWwgQ2VydGlmaWNhdGUgU2lnbmluZzE4MDYGA1UEAxMvU3RhcnRDb20gQ2xhc3Mg
MSBQcmltYXJ5IEludGVybWVkaWF0ZSBTZXJ2ZXIgQ0EwHhcNMTMwOTA0MTcxMDI4
WhcNMTQwOTA1MTA1ODI3WjBoMRkwFwYDVQQNExBncWdkOTFoVlNLUUw4d2k2MQsw
CQYDVQQGEwJVUzEZMBcGA1UEAxMQbmFnaW9zLnp1bGlwLm5ldDEjMCEGCSqGSIb3
DQEJARYUaG9zdG1hc3RlckB6dWxpcC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IB
DwAwggEKAoIBAQC3r6IfMWzcOZzQUlY3AU5P89WsWt0JLjCPFhxCLplVfR9a0VZk
2e7xiOuldoXSkwuzXPATQHPlmsbJdN9g86agj9VLhfiIr7rZV3Fx4IUJqaAE62eB
rMdPYfP5EjB3zMSuJYFldqsLFfHvucBqGvM2b9F7iuDFHaeQk9xETeKx5fADUdI7
FqLyL3mWmfm8vS9mNLOdkxN93D6R6zvIwUUvDya9wYl5b1D3IAL1ADaMsAGqbihW
N5Prdv2d+v4S/OiA+x9fM26WRVr4oFfSNsVQzHOVEwuuazXx8IgN2NgjcAMmbJBz
dWzjy1XOek07vEKo5D7Quh4IxuQXF2GFbExxAgMBAAGjggLgMIIC3DAJBgNVHRME
AjAAMAsGA1UdDwQEAwIDqDATBgNVHSUEDDAKBggrBgEFBQcDATAdBgNVHQ4EFgQU
ydhvTxMKSA0pXcaM0rZaN3IxCRswHwYDVR0jBBgwFoAU60I00Jiwq5/0G2sI98xk
Lu8OLEUwJgYDVR0RBB8wHYIQbmFnaW9zLnp1bGlwLm5ldIIJenVsaXAubmV0MIIB
VgYDVR0gBIIBTTCCAUkwCAYGZ4EMAQIBMIIBOwYLKwYBBAGBtTcBAgMwggEqMC4G
CCsGAQUFBwIBFiJodHRwOi8vd3d3LnN0YXJ0c3NsLmNvbS9wb2xpY3kucGRmMIH3
BggrBgEFBQcCAjCB6jAnFiBTdGFydENvbSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0
eTADAgEBGoG+VGhpcyBjZXJ0aWZpY2F0ZSB3YXMgaXNzdWVkIGFjY29yZGluZyB0
byB0aGUgQ2xhc3MgMSBWYWxpZGF0aW9uIHJlcXVpcmVtZW50cyBvZiB0aGUgU3Rh
cnRDb20gQ0EgcG9saWN5LCByZWxpYW5jZSBvbmx5IGZvciB0aGUgaW50ZW5kZWQg
cHVycG9zZSBpbiBjb21wbGlhbmNlIG9mIHRoZSByZWx5aW5nIHBhcnR5IG9ibGln
YXRpb25zLjA1BgNVHR8ELjAsMCqgKKAmhiRodHRwOi8vY3JsLnN0YXJ0c3NsLmNv
bS9jcnQxLWNybC5jcmwwgY4GCCsGAQUFBwEBBIGBMH8wOQYIKwYBBQUHMAGGLWh0
dHA6Ly9vY3NwLnN0YXJ0c3NsLmNvbS9zdWIvY2xhc3MxL3NlcnZlci9jYTBCBggr
BgEFBQcwAoY2aHR0cDovL2FpYS5zdGFydHNzbC5jb20vY2VydHMvc3ViLmNsYXNz
MS5zZXJ2ZXIuY2EuY3J0MCMGA1UdEgQcMBqGGGh0dHA6Ly93d3cuc3RhcnRzc2wu
Y29tLzANBgkqhkiG9w0BAQUFAAOCAQEAIT+IkU07y1M1LNVr6CMjqz3voIYkQPNX
SssClaGMfyi3QSPVhniMUZJWiHvPLdLsDP1fbI4lRGAuIjHv6kAwGD1ZLrMTCTMl
pHD0Jnlf5rtWFzklWAt/dDslauaC7eYgMFx1fHja1vJu9QXUaTXas6GGxKfNYma9
OQgjxnEKjTciyyxnAA+i5d4I/eaJHeX79+PpyCULknDjrfBF1wAPakq9WJx+yzlt
pz9+3Ggdfhhecaixb/StyXYT8tXnQy+aTnLZqh7mmPWGd01oD5AFMwyCRr5nzepj
6R8DkHRe/3LFg4YDUpY8WORLTSAeQHVA3inGymsPlVJdmVSq///HdA==
-----END CERTIFICATE-----

View File

@@ -0,0 +1,116 @@
-----BEGIN CERTIFICATE-----
MIIGVjCCBT6gAwIBAgIDCxnMMA0GCSqGSIb3DQEBBQUAMIGMMQswCQYDVQQGEwJJ
TDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0
YWwgQ2VydGlmaWNhdGUgU2lnbmluZzE4MDYGA1UEAxMvU3RhcnRDb20gQ2xhc3Mg
MSBQcmltYXJ5IEludGVybWVkaWF0ZSBTZXJ2ZXIgQ0EwHhcNMTMwNzEyMTUwMjQ1
WhcNMTQwNzEyMjI0NDM0WjBpMRkwFwYDVQQNExBXODl0UjVjVkIyNTZ4ZzFwMQsw
CQYDVQQGEwJVUzEaMBgGA1UEAxMRc3RhZ2luZy56dWxpcC5jb20xIzAhBgkqhkiG
9w0BCQEWFGhvc3RtYXN0ZXJAenVsaXAuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOC
AQ8AMIIBCgKCAQEA+omI0rp0LrwoxQ3vFPQDgqyOeHfoLLpSSqCLRZv+oH9aPscg
oTb2ua1VJjPGjBSKw7tsBitCLF9BEsDXZc0eQa6gqFzTEwC4n7xdqr9t0qxrF7ht
Uy9AJZZ0GuWkzk+qSMgl+/iRXv9PzCU/UnGNxI1AqiJUCRXcItriFbb5+mgOQlS8
EYYGnNR5mtU29UQadNiDzp73QgkCGfUxTBvJOcLntZRVAI9ElEcN4y2wfLcBhKJT
EE134j6JmY4Z7/UtyJa3gas3CM4Z2ttx5pEqT+qten7+/TdpkTj4R1BvYvPSRzDZ
TisDb0xa67CZ7bNf/Tyl9UeXRqAUix38TPuJ8QIDAQABo4IC4TCCAt0wCQYDVR0T
BAIwADALBgNVHQ8EBAMCA6gwEwYDVR0lBAwwCgYIKwYBBQUHAwEwHQYDVR0OBBYE
FHQVTfN38Y2YZmpjAHBIp/aLDSOyMB8GA1UdIwQYMBaAFOtCNNCYsKuf9BtrCPfM
ZC7vDixFMCcGA1UdEQQgMB6CEXN0YWdpbmcuenVsaXAuY29tggl6dWxpcC5jb20w
ggFWBgNVHSAEggFNMIIBSTAIBgZngQwBAgEwggE7BgsrBgEEAYG1NwECAzCCASow
LgYIKwYBBQUHAgEWImh0dHA6Ly93d3cuc3RhcnRzc2wuY29tL3BvbGljeS5wZGYw
gfcGCCsGAQUFBwICMIHqMCcWIFN0YXJ0Q29tIENlcnRpZmljYXRpb24gQXV0aG9y
aXR5MAMCAQEagb5UaGlzIGNlcnRpZmljYXRlIHdhcyBpc3N1ZWQgYWNjb3JkaW5n
IHRvIHRoZSBDbGFzcyAxIFZhbGlkYXRpb24gcmVxdWlyZW1lbnRzIG9mIHRoZSBT
dGFydENvbSBDQSBwb2xpY3ksIHJlbGlhbmNlIG9ubHkgZm9yIHRoZSBpbnRlbmRl
ZCBwdXJwb3NlIGluIGNvbXBsaWFuY2Ugb2YgdGhlIHJlbHlpbmcgcGFydHkgb2Js
aWdhdGlvbnMuMDUGA1UdHwQuMCwwKqAooCaGJGh0dHA6Ly9jcmwuc3RhcnRzc2wu
Y29tL2NydDEtY3JsLmNybDCBjgYIKwYBBQUHAQEEgYEwfzA5BggrBgEFBQcwAYYt
aHR0cDovL29jc3Auc3RhcnRzc2wuY29tL3N1Yi9jbGFzczEvc2VydmVyL2NhMEIG
CCsGAQUFBzAChjZodHRwOi8vYWlhLnN0YXJ0c3NsLmNvbS9jZXJ0cy9zdWIuY2xh
c3MxLnNlcnZlci5jYS5jcnQwIwYDVR0SBBwwGoYYaHR0cDovL3d3dy5zdGFydHNz
bC5jb20vMA0GCSqGSIb3DQEBBQUAA4IBAQCTTSbioYG8QJfK6Yfc3ijdS2oOh8AI
Gf3IN1TpmWAM8ijhDsDX0E8/Us6PHCwsg+yLuHI+92/MtHHSMnfew5HenTol6hNY
CDPnaHd1UtDfp6/yp8U0iQMWIjxecL46IAyjdD9tX43dLhL5fziQYEJ2rjFHtK8J
FBRg9QZI536BJ4aPfcFWwWtaYqWB7Nib1n86SKCPl0Tn1HfFJ+j0vkh0EwoJ3y3z
8VbJNwI0DxYMUDN2burWvEzUfAtNh2c7vuHhY6q96kNTMmbed/1DPUWWVyXKYtVc
FC9Q+3yQ3JqCJ1XoV3OxiYzdQnNn8WQGsEx1pxD9D6mHYnffeOUlHqhB
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIGNDCCBBygAwIBAgIBGDANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEW
MBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwg
Q2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNh
dGlvbiBBdXRob3JpdHkwHhcNMDcxMDI0MjA1NDE3WhcNMTcxMDI0MjA1NDE3WjCB
jDELMAkGA1UEBhMCSUwxFjAUBgNVBAoTDVN0YXJ0Q29tIEx0ZC4xKzApBgNVBAsT
IlNlY3VyZSBEaWdpdGFsIENlcnRpZmljYXRlIFNpZ25pbmcxODA2BgNVBAMTL1N0
YXJ0Q29tIENsYXNzIDEgUHJpbWFyeSBJbnRlcm1lZGlhdGUgU2VydmVyIENBMIIB
IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtonGrO8JUngHrJJj0PREGBiE
gFYfka7hh/oyULTTRwbw5gdfcA4Q9x3AzhA2NIVaD5Ksg8asWFI/ujjo/OenJOJA
pgh2wJJuniptTT9uYSAK21ne0n1jsz5G/vohURjXzTCm7QduO3CHtPn66+6CPAVv
kvek3AowHpNz/gfK11+AnSJYUq4G2ouHI2mw5CrY6oPSvfNx23BaKA+vWjhwRRI/
ME3NO68X5Q/LoKldSKqxYVDLNM08XMML6BDAjJvwAwNi/rJsPnIO7hxDKslIDlc5
xDEhyBDBLIf+VJVSH1I8MRKbf+fAoKVZ1eKPPvDVqOHXcDGpxLPPr21TLwb0pwID
AQABo4IBrTCCAakwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD
VR0OBBYEFOtCNNCYsKuf9BtrCPfMZC7vDixFMB8GA1UdIwQYMBaAFE4L7xqkQFul
F2mHMMo0aEPQQa7yMGYGCCsGAQUFBwEBBFowWDAnBggrBgEFBQcwAYYbaHR0cDov
L29jc3Auc3RhcnRzc2wuY29tL2NhMC0GCCsGAQUFBzAChiFodHRwOi8vd3d3LnN0
YXJ0c3NsLmNvbS9zZnNjYS5jcnQwWwYDVR0fBFQwUjAnoCWgI4YhaHR0cDovL3d3
dy5zdGFydHNzbC5jb20vc2ZzY2EuY3JsMCegJaAjhiFodHRwOi8vY3JsLnN0YXJ0
c3NsLmNvbS9zZnNjYS5jcmwwgYAGA1UdIAR5MHcwdQYLKwYBBAGBtTcBAgEwZjAu
BggrBgEFBQcCARYiaHR0cDovL3d3dy5zdGFydHNzbC5jb20vcG9saWN5LnBkZjA0
BggrBgEFBQcCARYoaHR0cDovL3d3dy5zdGFydHNzbC5jb20vaW50ZXJtZWRpYXRl
LnBkZjANBgkqhkiG9w0BAQUFAAOCAgEAIQlJPqWIbuALi0jaMU2P91ZXouHTYlfp
tVbzhUV1O+VQHwSL5qBaPucAroXQ+/8gA2TLrQLhxpFy+KNN1t7ozD+hiqLjfDen
xk+PNdb01m4Ge90h2c9W/8swIkn+iQTzheWq8ecf6HWQTd35RvdCNPdFWAwRDYSw
xtpdPvkBnufh2lWVvnQce/xNFE+sflVHfXv0pQ1JHpXo9xLBzP92piVH0PN1Nb6X
t1gW66pceG/sUzCv6gRNzKkC4/C2BBL2MLERPZBOVmTX3DxDX3M570uvh+v2/miI
RHLq0gfGabDBoYvvF0nXYbFFSF87ICHpW7LM9NfpMfULFWE7epTj69m8f5SuauNi
YpaoZHy4h/OZMn6SolK+u/hlz8nyMPyLwcKmltdfieFcNID1j0cHL7SRv7Gifl9L
WtBbnySGBVFaaQNlQ0lxxeBvlDRr9hvYqbBMflPrj0jfyjO1SPo2ShpTpjMM0InN
SRXNiTE8kMBy12VLUjWKRhFEuT2OKGWmPnmeXAhEKa2wNREuIU640ucQPl2Eg7PD
wuTSxv0JS3QJ3fGz0xk+gA2iCxnwOOfFwq/iI9th4p1cbiCJSS4jarJiwUW0n6+L
p/EiO/h94pDQehn7Skzj0n1fSoMD7SfWI55rjbRZotnvbIIp3XUZPD9MEI3vu3Un
0q6Dp6jOW6c=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIHyTCCBbGgAwIBAgIBATANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEW
MBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwg
Q2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNh
dGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0NjM2WhcNMzYwOTE3MTk0NjM2WjB9
MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMi
U2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3Rh
cnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUA
A4ICDwAwggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZk
pMyONvg45iPwbm2xPN1yo4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rf
OQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/C
Ji/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/deMotHweXMAEtcnn6RtYT
Kqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt2PZE4XNi
HzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMM
Av+Z6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w
+2OqqGwaVLRcJXrJosmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+
Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3
Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVcUjyJthkqcwEKDwOzEmDyei+B
26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT37uMdBNSSwID
AQABo4ICUjCCAk4wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAa4wHQYDVR0OBBYE
FE4L7xqkQFulF2mHMMo0aEPQQa7yMGQGA1UdHwRdMFswLKAqoCiGJmh0dHA6Ly9j
ZXJ0LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMCugKaAnhiVodHRwOi8vY3Js
LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMIIBXQYDVR0gBIIBVDCCAVAwggFM
BgsrBgEEAYG1NwEBATCCATswLwYIKwYBBQUHAgEWI2h0dHA6Ly9jZXJ0LnN0YXJ0
Y29tLm9yZy9wb2xpY3kucGRmMDUGCCsGAQUFBwIBFilodHRwOi8vY2VydC5zdGFy
dGNvbS5vcmcvaW50ZXJtZWRpYXRlLnBkZjCB0AYIKwYBBQUHAgIwgcMwJxYgU3Rh
cnQgQ29tbWVyY2lhbCAoU3RhcnRDb20pIEx0ZC4wAwIBARqBl0xpbWl0ZWQgTGlh
YmlsaXR5LCByZWFkIHRoZSBzZWN0aW9uICpMZWdhbCBMaW1pdGF0aW9ucyogb2Yg
dGhlIFN0YXJ0Q29tIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFBvbGljeSBhdmFp
bGFibGUgYXQgaHR0cDovL2NlcnQuc3RhcnRjb20ub3JnL3BvbGljeS5wZGYwEQYJ
YIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilTdGFydENvbSBGcmVlIFNT
TCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQUFAAOCAgEAFmyZ
9GYMNPXQhV59CuzaEE44HF7fpiUFS5Eyweg78T3dRAlbB0mKKctmArexmvclmAk8
jhvh3TaHK0u7aNM5Zj2gJsfyOZEdUauCe37Vzlrk4gNXcGmXCPleWKYK34wGmkUW
FjgKXlf2Ysd6AgXmvB618p70qSmD+LIU424oh0TDkBreOKk8rENNZEXO3SipXPJz
ewT4F+irsfMuXGRuczE6Eri8sxHkfY+BUZo7jYn0TZNmezwD7dOaHZrzZVD1oNB1
ny+v8OqCQ5j4aZyJecRDjkZy42Q2Eq/3JR44iZB3fsNrarnDy0RLrHiQi+fHLB5L
EUTINFInzQpdn4XBidUaePKVEFMy3YCEZnXZtWgo+2EuvoSoOMCZEoalHmdkrQYu
L6lwhceWD3yJZfWOQ1QOq92lgDmUYMA0yZZwLKMS9R9Ie70cfmu3nZD0Ijuu+Pwq
yvqCUqDvr0tVk+vBtfAii6w0TiYiBKGHLHVKt+V9E9e4DGTANtLJL4YSjCMJwRuC
O3NJo2pXh5Tl1njFmUNj403gdy3hZZlyaQQaRwnmDwFWJPsfvw55qVguucQJAX6V
um0ABj6y6koQOdjQK/W/7HW/lwLFCRsI3FU34oH7N4RDYiDK51ZLZer+bMEkkySh
NOsF/5oirpt9P/FlUQqmMGqz9IgcgA38corog14=
-----END CERTIFICATE-----

View File

@@ -0,0 +1,36 @@
-----BEGIN CERTIFICATE-----
MIIGVjCCBT6gAwIBAgIDCxnMMA0GCSqGSIb3DQEBBQUAMIGMMQswCQYDVQQGEwJJ
TDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0
YWwgQ2VydGlmaWNhdGUgU2lnbmluZzE4MDYGA1UEAxMvU3RhcnRDb20gQ2xhc3Mg
MSBQcmltYXJ5IEludGVybWVkaWF0ZSBTZXJ2ZXIgQ0EwHhcNMTMwNzEyMTUwMjQ1
WhcNMTQwNzEyMjI0NDM0WjBpMRkwFwYDVQQNExBXODl0UjVjVkIyNTZ4ZzFwMQsw
CQYDVQQGEwJVUzEaMBgGA1UEAxMRc3RhZ2luZy56dWxpcC5jb20xIzAhBgkqhkiG
9w0BCQEWFGhvc3RtYXN0ZXJAenVsaXAuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOC
AQ8AMIIBCgKCAQEA+omI0rp0LrwoxQ3vFPQDgqyOeHfoLLpSSqCLRZv+oH9aPscg
oTb2ua1VJjPGjBSKw7tsBitCLF9BEsDXZc0eQa6gqFzTEwC4n7xdqr9t0qxrF7ht
Uy9AJZZ0GuWkzk+qSMgl+/iRXv9PzCU/UnGNxI1AqiJUCRXcItriFbb5+mgOQlS8
EYYGnNR5mtU29UQadNiDzp73QgkCGfUxTBvJOcLntZRVAI9ElEcN4y2wfLcBhKJT
EE134j6JmY4Z7/UtyJa3gas3CM4Z2ttx5pEqT+qten7+/TdpkTj4R1BvYvPSRzDZ
TisDb0xa67CZ7bNf/Tyl9UeXRqAUix38TPuJ8QIDAQABo4IC4TCCAt0wCQYDVR0T
BAIwADALBgNVHQ8EBAMCA6gwEwYDVR0lBAwwCgYIKwYBBQUHAwEwHQYDVR0OBBYE
FHQVTfN38Y2YZmpjAHBIp/aLDSOyMB8GA1UdIwQYMBaAFOtCNNCYsKuf9BtrCPfM
ZC7vDixFMCcGA1UdEQQgMB6CEXN0YWdpbmcuenVsaXAuY29tggl6dWxpcC5jb20w
ggFWBgNVHSAEggFNMIIBSTAIBgZngQwBAgEwggE7BgsrBgEEAYG1NwECAzCCASow
LgYIKwYBBQUHAgEWImh0dHA6Ly93d3cuc3RhcnRzc2wuY29tL3BvbGljeS5wZGYw
gfcGCCsGAQUFBwICMIHqMCcWIFN0YXJ0Q29tIENlcnRpZmljYXRpb24gQXV0aG9y
aXR5MAMCAQEagb5UaGlzIGNlcnRpZmljYXRlIHdhcyBpc3N1ZWQgYWNjb3JkaW5n
IHRvIHRoZSBDbGFzcyAxIFZhbGlkYXRpb24gcmVxdWlyZW1lbnRzIG9mIHRoZSBT
dGFydENvbSBDQSBwb2xpY3ksIHJlbGlhbmNlIG9ubHkgZm9yIHRoZSBpbnRlbmRl
ZCBwdXJwb3NlIGluIGNvbXBsaWFuY2Ugb2YgdGhlIHJlbHlpbmcgcGFydHkgb2Js
aWdhdGlvbnMuMDUGA1UdHwQuMCwwKqAooCaGJGh0dHA6Ly9jcmwuc3RhcnRzc2wu
Y29tL2NydDEtY3JsLmNybDCBjgYIKwYBBQUHAQEEgYEwfzA5BggrBgEFBQcwAYYt
aHR0cDovL29jc3Auc3RhcnRzc2wuY29tL3N1Yi9jbGFzczEvc2VydmVyL2NhMEIG
CCsGAQUFBzAChjZodHRwOi8vYWlhLnN0YXJ0c3NsLmNvbS9jZXJ0cy9zdWIuY2xh
c3MxLnNlcnZlci5jYS5jcnQwIwYDVR0SBBwwGoYYaHR0cDovL3d3dy5zdGFydHNz
bC5jb20vMA0GCSqGSIb3DQEBBQUAA4IBAQCTTSbioYG8QJfK6Yfc3ijdS2oOh8AI
Gf3IN1TpmWAM8ijhDsDX0E8/Us6PHCwsg+yLuHI+92/MtHHSMnfew5HenTol6hNY
CDPnaHd1UtDfp6/yp8U0iQMWIjxecL46IAyjdD9tX43dLhL5fziQYEJ2rjFHtK8J
FBRg9QZI536BJ4aPfcFWwWtaYqWB7Nib1n86SKCPl0Tn1HfFJ+j0vkh0EwoJ3y3z
8VbJNwI0DxYMUDN2burWvEzUfAtNh2c7vuHhY6q96kNTMmbed/1DPUWWVyXKYtVc
FC9Q+3yQ3JqCJ1XoV3OxiYzdQnNn8WQGsEx1pxD9D6mHYnffeOUlHqhB
-----END CERTIFICATE-----

View File

@@ -1,59 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIFRTCCBC2gAwIBAgIQCeu0vyc0EdwhoPpohoWSuzANBgkqhkiG9w0BAQsFADBw
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMS8wLQYDVQQDEyZEaWdpQ2VydCBTSEEyIEhpZ2ggQXNz
dXJhbmNlIFNlcnZlciBDQTAeFw0xNDA0MTYwMDAwMDBaFw0xNjA0MjAxMjAwMDBa
MGsxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1T
YW4gRnJhbmNpc2NvMRUwEwYDVQQKEwxEcm9wYm94LCBJbmMxGDAWBgNVBAMTD3N0
YXRzLnp1bGlwLm5ldDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANPQ
XZXfNdVW7N6CSzpM74dtLMAawINFfYuk1VFUqzC5L5uP7ZUwvhYVKVlJrnd5afGp
XARqaYhddvJxbDihO3vgCopkHdcRikRrJgwSvLUtCeX8kLUyHTX6XXmn52CspX+r
s2OYecGna+dnscWyL3K1UlVISJ2lyKGZU6t72Fyt7XYIFzVd/VruK6jfWsbZOpZ6
HZgKzcYP1CTrsAg5LvW4dqNaEJya9+JdyRWJ9zgDSWV+XzsJtbY3hg8IrCNLB/ck
F7wElqQg/tJNELgUyQmrIhyxqgHu0Nsg56Ug2KhIby4QaBzgBy7U+oTRgM8SYVCN
iFM74FG1/DA08pERaBkCAwEAAaOCAd4wggHaMB8GA1UdIwQYMBaAFFFo/5CvAgd1
PMzZZWRiohK4WXI7MB0GA1UdDgQWBBQRkQ0SirqkXztkBjr55UekEAqdljAaBgNV
HREEEzARgg9zdGF0cy56dWxpcC5uZXQwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQW
MBQGCCsGAQUFBwMBBggrBgEFBQcDAjB1BgNVHR8EbjBsMDSgMqAwhi5odHRwOi8v
Y3JsMy5kaWdpY2VydC5jb20vc2hhMi1oYS1zZXJ2ZXItZzIuY3JsMDSgMqAwhi5o
dHRwOi8vY3JsNC5kaWdpY2VydC5jb20vc2hhMi1oYS1zZXJ2ZXItZzIuY3JsMEIG
A1UdIAQ7MDkwNwYJYIZIAYb9bAEBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3
LmRpZ2ljZXJ0LmNvbS9DUFMwgYMGCCsGAQUFBwEBBHcwdTAkBggrBgEFBQcwAYYY
aHR0cDovL29jc3AuZGlnaWNlcnQuY29tME0GCCsGAQUFBzAChkFodHRwOi8vY2Fj
ZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRTSEEySGlnaEFzc3VyYW5jZVNlcnZl
ckNBLmNydDAMBgNVHRMBAf8EAjAAMA0GCSqGSIb3DQEBCwUAA4IBAQArykRu8hdK
9tFLzDUcApS9xGuOSjJgGOPRW8symfNq4pU8dPp+gXtZ2BlxLeKn2bLR4XeLlvCj
LZRZaMVfrGyaEV9WzkyTVG64l7zjKNHqdN/AY/YAp6HcxXDNJs1eFUOB45yHLfkH
pG0gx9dnCR+rRyDpOVODNLP6/JIq79xluk6Eb4VaSlHrxnDoDb18Yolx3OlYnwNF
cceJrPJEL1AX7NqBRav7dSfR4DsyYzT+GKXx/mZe/igMn2pUjE5Idf5aw9citsU3
SaltVJZ3Kp4KBx1xHF06HUA3eb50vghOeGmMVYAWQIZeYHRDcbAhrFW0W7SnJwFc
ZQHYMrD1uDAQ
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIEsTCCA5mgAwIBAgIQBOHnpNxc8vNtwCtCuF0VnzANBgkqhkiG9w0BAQsFADBs
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j
ZSBFViBSb290IENBMB4XDTEzMTAyMjEyMDAwMFoXDTI4MTAyMjEyMDAwMFowcDEL
MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3
LmRpZ2ljZXJ0LmNvbTEvMC0GA1UEAxMmRGlnaUNlcnQgU0hBMiBIaWdoIEFzc3Vy
YW5jZSBTZXJ2ZXIgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC2
4C/CJAbIbQRf1+8KZAayfSImZRauQkCbztyfn3YHPsMwVYcZuU+UDlqUH1VWtMIC
Kq/QmO4LQNfE0DtyyBSe75CxEamu0si4QzrZCwvV1ZX1QK/IHe1NnF9Xt4ZQaJn1
itrSxwUfqJfJ3KSxgoQtxq2lnMcZgqaFD15EWCo3j/018QsIJzJa9buLnqS9UdAn
4t07QjOjBSjEuyjMmqwrIw14xnvmXnG3Sj4I+4G3FhahnSMSTeXXkgisdaScus0X
sh5ENWV/UyU50RwKmmMbGZJ0aAo3wsJSSMs5WqK24V3B3aAguCGikyZvFEohQcft
bZvySC/zA/WiaJJTL17jAgMBAAGjggFJMIIBRTASBgNVHRMBAf8ECDAGAQH/AgEA
MA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw
NAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2Vy
dC5jb20wSwYDVR0fBEQwQjBAoD6gPIY6aHR0cDovL2NybDQuZGlnaWNlcnQuY29t
L0RpZ2lDZXJ0SGlnaEFzc3VyYW5jZUVWUm9vdENBLmNybDA9BgNVHSAENjA0MDIG
BFUdIAAwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQ
UzAdBgNVHQ4EFgQUUWj/kK8CB3U8zNllZGKiErhZcjswHwYDVR0jBBgwFoAUsT7D
aQP4v0cB1JgmGggC72NkK8MwDQYJKoZIhvcNAQELBQADggEBABiKlYkD5m3fXPwd
aOpKj4PWUS+Na0QWnqxj9dJubISZi6qBcYRb7TROsLd5kinMLYBq8I4g4Xmk/gNH
E+r1hspZcX30BJZr01lYPf7TMSVcGDiEo+afgv2MW5gxTs14nhr9hctJqvIni5ly
/D6q1UEL2tU2ob8cbkdJf17ZSHwD2f2LSaCYJkJA69aSEaRkCldUxPUd1gJea6zu
xICaEnL6VpPX/78whQYwvwt/Tv9XBZ0k7YXDK/umdaisLRbvfXknsuvCnQsH6qqF
0wGjIChBWUMo0oHjqvbsezt3tkBigAVBRQHvFwY+3sAzm2fTYS5yh+Rp/BIAV0Ae
cPUeybQ=
-----END CERTIFICATE-----

View File

@@ -1,31 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIFRTCCBC2gAwIBAgIQCeu0vyc0EdwhoPpohoWSuzANBgkqhkiG9w0BAQsFADBw
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMS8wLQYDVQQDEyZEaWdpQ2VydCBTSEEyIEhpZ2ggQXNz
dXJhbmNlIFNlcnZlciBDQTAeFw0xNDA0MTYwMDAwMDBaFw0xNjA0MjAxMjAwMDBa
MGsxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1T
YW4gRnJhbmNpc2NvMRUwEwYDVQQKEwxEcm9wYm94LCBJbmMxGDAWBgNVBAMTD3N0
YXRzLnp1bGlwLm5ldDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANPQ
XZXfNdVW7N6CSzpM74dtLMAawINFfYuk1VFUqzC5L5uP7ZUwvhYVKVlJrnd5afGp
XARqaYhddvJxbDihO3vgCopkHdcRikRrJgwSvLUtCeX8kLUyHTX6XXmn52CspX+r
s2OYecGna+dnscWyL3K1UlVISJ2lyKGZU6t72Fyt7XYIFzVd/VruK6jfWsbZOpZ6
HZgKzcYP1CTrsAg5LvW4dqNaEJya9+JdyRWJ9zgDSWV+XzsJtbY3hg8IrCNLB/ck
F7wElqQg/tJNELgUyQmrIhyxqgHu0Nsg56Ug2KhIby4QaBzgBy7U+oTRgM8SYVCN
iFM74FG1/DA08pERaBkCAwEAAaOCAd4wggHaMB8GA1UdIwQYMBaAFFFo/5CvAgd1
PMzZZWRiohK4WXI7MB0GA1UdDgQWBBQRkQ0SirqkXztkBjr55UekEAqdljAaBgNV
HREEEzARgg9zdGF0cy56dWxpcC5uZXQwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQW
MBQGCCsGAQUFBwMBBggrBgEFBQcDAjB1BgNVHR8EbjBsMDSgMqAwhi5odHRwOi8v
Y3JsMy5kaWdpY2VydC5jb20vc2hhMi1oYS1zZXJ2ZXItZzIuY3JsMDSgMqAwhi5o
dHRwOi8vY3JsNC5kaWdpY2VydC5jb20vc2hhMi1oYS1zZXJ2ZXItZzIuY3JsMEIG
A1UdIAQ7MDkwNwYJYIZIAYb9bAEBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3
LmRpZ2ljZXJ0LmNvbS9DUFMwgYMGCCsGAQUFBwEBBHcwdTAkBggrBgEFBQcwAYYY
aHR0cDovL29jc3AuZGlnaWNlcnQuY29tME0GCCsGAQUFBzAChkFodHRwOi8vY2Fj
ZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRTSEEySGlnaEFzc3VyYW5jZVNlcnZl
ckNBLmNydDAMBgNVHRMBAf8EAjAAMA0GCSqGSIb3DQEBCwUAA4IBAQArykRu8hdK
9tFLzDUcApS9xGuOSjJgGOPRW8symfNq4pU8dPp+gXtZ2BlxLeKn2bLR4XeLlvCj
LZRZaMVfrGyaEV9WzkyTVG64l7zjKNHqdN/AY/YAp6HcxXDNJs1eFUOB45yHLfkH
pG0gx9dnCR+rRyDpOVODNLP6/JIq79xluk6Eb4VaSlHrxnDoDb18Yolx3OlYnwNF
cceJrPJEL1AX7NqBRav7dSfR4DsyYzT+GKXx/mZe/igMn2pUjE5Idf5aw9citsU3
SaltVJZ3Kp4KBx1xHF06HUA3eb50vghOeGmMVYAWQIZeYHRDcbAhrFW0W7SnJwFc
ZQHYMrD1uDAQ
-----END CERTIFICATE-----

View File

@@ -0,0 +1,37 @@
-----BEGIN CERTIFICATE-----
MIIGeDCCBWCgAwIBAgIDCzx7MA0GCSqGSIb3DQEBBQUAMIGMMQswCQYDVQQGEwJJ
TDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0
YWwgQ2VydGlmaWNhdGUgU2lnbmluZzE4MDYGA1UEAxMvU3RhcnRDb20gQ2xhc3Mg
MSBQcmltYXJ5IEludGVybWVkaWF0ZSBTZXJ2ZXIgQ0EwHhcNMTMwNzI3MjA0OTI2
WhcNMTQwNzI4MjAyMjU4WjCBizEZMBcGA1UEDRMQZXJIOUp3Y3NxcFB3T1pQdTEL
MAkGA1UEBhMCVVMxGTAXBgNVBAMTEHN0YXRzMS56dWxpcC5uZXQxRjBEBgkqhkiG
9w0BCQEWNzE5YmI4ZDJjYjkwNzRjZGRhODY0OWQzNDFkZDhlY2Q1LnByb3RlY3RA
d2hvaXNndWFyZC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDn
/nUFbsm89+Npxgq+B2jRqGvOnCPQ6QRgWj6ZQdZGuyOJ9JquSVc9YGgG/MGSa5hv
vzPxhC3NI0hH1nHypJtXbQS+UkI2tRSKdW89LVLcMJi2epqwlisBpobNIuMIQbsA
6HXY6qFI1r3WyRUZ3YggL4j35FEOW7pwx81fBFOgZaFu7b1PSjWyy1G0IrPalVaI
USsHu/pX1RxoTkcPlqG40pjVaQKHruJIaAQBBrW1r/QpDgan6PwiOSWrTJe/+WHU
xqlKO4WmPV70HRTZOFfMBQzO3PdR6a4RntjVbvvMycmCn6B0DKjDdnlP0iKAnlii
Lxiv/QO0MNkeX2l/l0H7AgMBAAGjggLgMIIC3DAJBgNVHRMEAjAAMAsGA1UdDwQE
AwIDqDATBgNVHSUEDDAKBggrBgEFBQcDATAdBgNVHQ4EFgQUPZ5uzgMNpTBQ5DBA
kipoNphC4uYwHwYDVR0jBBgwFoAU60I00Jiwq5/0G2sI98xkLu8OLEUwJgYDVR0R
BB8wHYIQc3RhdHMxLnp1bGlwLm5ldIIJenVsaXAubmV0MIIBVgYDVR0gBIIBTTCC
AUkwCAYGZ4EMAQIBMIIBOwYLKwYBBAGBtTcBAgMwggEqMC4GCCsGAQUFBwIBFiJo
dHRwOi8vd3d3LnN0YXJ0c3NsLmNvbS9wb2xpY3kucGRmMIH3BggrBgEFBQcCAjCB
6jAnFiBTdGFydENvbSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTADAgEBGoG+VGhp
cyBjZXJ0aWZpY2F0ZSB3YXMgaXNzdWVkIGFjY29yZGluZyB0byB0aGUgQ2xhc3Mg
MSBWYWxpZGF0aW9uIHJlcXVpcmVtZW50cyBvZiB0aGUgU3RhcnRDb20gQ0EgcG9s
aWN5LCByZWxpYW5jZSBvbmx5IGZvciB0aGUgaW50ZW5kZWQgcHVycG9zZSBpbiBj
b21wbGlhbmNlIG9mIHRoZSByZWx5aW5nIHBhcnR5IG9ibGlnYXRpb25zLjA1BgNV
HR8ELjAsMCqgKKAmhiRodHRwOi8vY3JsLnN0YXJ0c3NsLmNvbS9jcnQxLWNybC5j
cmwwgY4GCCsGAQUFBwEBBIGBMH8wOQYIKwYBBQUHMAGGLWh0dHA6Ly9vY3NwLnN0
YXJ0c3NsLmNvbS9zdWIvY2xhc3MxL3NlcnZlci9jYTBCBggrBgEFBQcwAoY2aHR0
cDovL2FpYS5zdGFydHNzbC5jb20vY2VydHMvc3ViLmNsYXNzMS5zZXJ2ZXIuY2Eu
Y3J0MCMGA1UdEgQcMBqGGGh0dHA6Ly93d3cuc3RhcnRzc2wuY29tLzANBgkqhkiG
9w0BAQUFAAOCAQEApEbVfCf5LBHi7wFwtfraYMuf8TTZ6B41mBmN3wnavc2STtOd
+G9J3+oJeI6pwuNAHeY08EQZqAj8ijUnXPueeIziWISzFIaCQC8svHruxgR0nPUk
vSas89B74EhQ3gFpoEwnyi8rq59xVjluLkLmA93PGIk8c/02Z5NsW05k508kZwsm
Y1qtD1vAbhHQaTTzyc+8VK7SNtzIkjaIRcyEwE+J63q5uTisMIoJFnZJiUN2vQqg
I6sFnSNahB5WxEKsX5PF3tC7XLH6d5NmRL7kEaHS7U5QHUPLAPZEsYTcBHreAzEl
cBHkBWDioqskhYGkrBBE5RFWCtzUmVo86mxHYA==
-----END CERTIFICATE-----

View File

@@ -1,59 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIFQzCCBCugAwIBAgIQD9VdZebVvG9+AG9yMOzijTANBgkqhkiG9w0BAQsFADBw
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMS8wLQYDVQQDEyZEaWdpQ2VydCBTSEEyIEhpZ2ggQXNz
dXJhbmNlIFNlcnZlciBDQTAeFw0xNDA0MTYwMDAwMDBaFw0xNjA0MjAxMjAwMDBa
MGoxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1T
YW4gRnJhbmNpc2NvMRUwEwYDVQQKEwxEcm9wYm94LCBJbmMxFzAVBgNVBAMTDnRy
YWMuenVsaXAubmV0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzdeK
urQ+rI5ICqWM5KIcPrEprv281Vf9yuQRInk9mz7WdoscuPEIfCrnVj+wXG9L4Pco
u+BIDRCZ5/a0yfimS8U23zcieDNtZP4/HKpgwIkk4NkIZ/6u2muWzMe6AEjePKsd
EImJzcuTGoXJIY+z3I1HlzPUwLMSk4dHXPho4c/TJcJvNBp/MPbWCAvAKNq1Ehwj
GqtQjSYeUq1JJlF+jRZl8UvJANIObvMFuxGllw9H5IUCBIzRNpXxARpd4Fnz1Au0
m7bhBmNYIzXqQWqBZfU/qng118YjOYC+ZrcJqG1j1Rk0lrXhnq36LfC1OrefwjsZ
p6ly/U5F8oVvC8wlxQIDAQABo4IB3TCCAdkwHwYDVR0jBBgwFoAUUWj/kK8CB3U8
zNllZGKiErhZcjswHQYDVR0OBBYEFMi87D8ybP+KnZR3Lg788zRzn2CiMBkGA1Ud
EQQSMBCCDnRyYWMuenVsaXAubmV0MA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAU
BggrBgEFBQcDAQYIKwYBBQUHAwIwdQYDVR0fBG4wbDA0oDKgMIYuaHR0cDovL2Ny
bDMuZGlnaWNlcnQuY29tL3NoYTItaGEtc2VydmVyLWcyLmNybDA0oDKgMIYuaHR0
cDovL2NybDQuZGlnaWNlcnQuY29tL3NoYTItaGEtc2VydmVyLWcyLmNybDBCBgNV
HSAEOzA5MDcGCWCGSAGG/WwBATAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5k
aWdpY2VydC5jb20vQ1BTMIGDBggrBgEFBQcBAQR3MHUwJAYIKwYBBQUHMAGGGGh0
dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBNBggrBgEFBQcwAoZBaHR0cDovL2NhY2Vy
dHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkhpZ2hBc3N1cmFuY2VTZXJ2ZXJD
QS5jcnQwDAYDVR0TAQH/BAIwADANBgkqhkiG9w0BAQsFAAOCAQEAQEK5QSNBYXCR
VVWJtJYU3ftiA1vlzkUvSBBC3McgLk+xPyLJEZspKJ6SEqenbNLi05heT2i7DNi4
ePJA9sQHBPUUYralS2be0CXym5Kj8+J9DRUXG829VLUs3ZLEwzCPTJC0gJ5Qm9r0
DMOgce059q62pgSxqHGq9PRnYLfsImanr1fWxonrA+tSxr+ACA77617uShRFtEe7
w7W9kaHG/rxNX4NyaA1dTPKJ/+R70k1UJWyiwnpW1aKzdwF1sN4FZx0PW3YW5Fww
JFO5LluyysXF/ccndhPBphF+KE0H7PdWUjQsQWq2qd6nLt1ZWmJaJsRK+YmbxSzE
ijy7IvLskw==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIEsTCCA5mgAwIBAgIQBOHnpNxc8vNtwCtCuF0VnzANBgkqhkiG9w0BAQsFADBs
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j
ZSBFViBSb290IENBMB4XDTEzMTAyMjEyMDAwMFoXDTI4MTAyMjEyMDAwMFowcDEL
MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3
LmRpZ2ljZXJ0LmNvbTEvMC0GA1UEAxMmRGlnaUNlcnQgU0hBMiBIaWdoIEFzc3Vy
YW5jZSBTZXJ2ZXIgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC2
4C/CJAbIbQRf1+8KZAayfSImZRauQkCbztyfn3YHPsMwVYcZuU+UDlqUH1VWtMIC
Kq/QmO4LQNfE0DtyyBSe75CxEamu0si4QzrZCwvV1ZX1QK/IHe1NnF9Xt4ZQaJn1
itrSxwUfqJfJ3KSxgoQtxq2lnMcZgqaFD15EWCo3j/018QsIJzJa9buLnqS9UdAn
4t07QjOjBSjEuyjMmqwrIw14xnvmXnG3Sj4I+4G3FhahnSMSTeXXkgisdaScus0X
sh5ENWV/UyU50RwKmmMbGZJ0aAo3wsJSSMs5WqK24V3B3aAguCGikyZvFEohQcft
bZvySC/zA/WiaJJTL17jAgMBAAGjggFJMIIBRTASBgNVHRMBAf8ECDAGAQH/AgEA
MA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw
NAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2Vy
dC5jb20wSwYDVR0fBEQwQjBAoD6gPIY6aHR0cDovL2NybDQuZGlnaWNlcnQuY29t
L0RpZ2lDZXJ0SGlnaEFzc3VyYW5jZUVWUm9vdENBLmNybDA9BgNVHSAENjA0MDIG
BFUdIAAwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQ
UzAdBgNVHQ4EFgQUUWj/kK8CB3U8zNllZGKiErhZcjswHwYDVR0jBBgwFoAUsT7D
aQP4v0cB1JgmGggC72NkK8MwDQYJKoZIhvcNAQELBQADggEBABiKlYkD5m3fXPwd
aOpKj4PWUS+Na0QWnqxj9dJubISZi6qBcYRb7TROsLd5kinMLYBq8I4g4Xmk/gNH
E+r1hspZcX30BJZr01lYPf7TMSVcGDiEo+afgv2MW5gxTs14nhr9hctJqvIni5ly
/D6q1UEL2tU2ob8cbkdJf17ZSHwD2f2LSaCYJkJA69aSEaRkCldUxPUd1gJea6zu
xICaEnL6VpPX/78whQYwvwt/Tv9XBZ0k7YXDK/umdaisLRbvfXknsuvCnQsH6qqF
0wGjIChBWUMo0oHjqvbsezt3tkBigAVBRQHvFwY+3sAzm2fTYS5yh+Rp/BIAV0Ae
cPUeybQ=
-----END CERTIFICATE-----

View File

@@ -1,31 +1,36 @@
-----BEGIN CERTIFICATE-----
MIIFQzCCBCugAwIBAgIQD9VdZebVvG9+AG9yMOzijTANBgkqhkiG9w0BAQsFADBw
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMS8wLQYDVQQDEyZEaWdpQ2VydCBTSEEyIEhpZ2ggQXNz
dXJhbmNlIFNlcnZlciBDQTAeFw0xNDA0MTYwMDAwMDBaFw0xNjA0MjAxMjAwMDBa
MGoxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1T
YW4gRnJhbmNpc2NvMRUwEwYDVQQKEwxEcm9wYm94LCBJbmMxFzAVBgNVBAMTDnRy
YWMuenVsaXAubmV0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzdeK
urQ+rI5ICqWM5KIcPrEprv281Vf9yuQRInk9mz7WdoscuPEIfCrnVj+wXG9L4Pco
u+BIDRCZ5/a0yfimS8U23zcieDNtZP4/HKpgwIkk4NkIZ/6u2muWzMe6AEjePKsd
EImJzcuTGoXJIY+z3I1HlzPUwLMSk4dHXPho4c/TJcJvNBp/MPbWCAvAKNq1Ehwj
GqtQjSYeUq1JJlF+jRZl8UvJANIObvMFuxGllw9H5IUCBIzRNpXxARpd4Fnz1Au0
m7bhBmNYIzXqQWqBZfU/qng118YjOYC+ZrcJqG1j1Rk0lrXhnq36LfC1OrefwjsZ
p6ly/U5F8oVvC8wlxQIDAQABo4IB3TCCAdkwHwYDVR0jBBgwFoAUUWj/kK8CB3U8
zNllZGKiErhZcjswHQYDVR0OBBYEFMi87D8ybP+KnZR3Lg788zRzn2CiMBkGA1Ud
EQQSMBCCDnRyYWMuenVsaXAubmV0MA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAU
BggrBgEFBQcDAQYIKwYBBQUHAwIwdQYDVR0fBG4wbDA0oDKgMIYuaHR0cDovL2Ny
bDMuZGlnaWNlcnQuY29tL3NoYTItaGEtc2VydmVyLWcyLmNybDA0oDKgMIYuaHR0
cDovL2NybDQuZGlnaWNlcnQuY29tL3NoYTItaGEtc2VydmVyLWcyLmNybDBCBgNV
HSAEOzA5MDcGCWCGSAGG/WwBATAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5k
aWdpY2VydC5jb20vQ1BTMIGDBggrBgEFBQcBAQR3MHUwJAYIKwYBBQUHMAGGGGh0
dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBNBggrBgEFBQcwAoZBaHR0cDovL2NhY2Vy
dHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkhpZ2hBc3N1cmFuY2VTZXJ2ZXJD
QS5jcnQwDAYDVR0TAQH/BAIwADANBgkqhkiG9w0BAQsFAAOCAQEAQEK5QSNBYXCR
VVWJtJYU3ftiA1vlzkUvSBBC3McgLk+xPyLJEZspKJ6SEqenbNLi05heT2i7DNi4
ePJA9sQHBPUUYralS2be0CXym5Kj8+J9DRUXG829VLUs3ZLEwzCPTJC0gJ5Qm9r0
DMOgce059q62pgSxqHGq9PRnYLfsImanr1fWxonrA+tSxr+ACA77617uShRFtEe7
w7W9kaHG/rxNX4NyaA1dTPKJ/+R70k1UJWyiwnpW1aKzdwF1sN4FZx0PW3YW5Fww
JFO5LluyysXF/ccndhPBphF+KE0H7PdWUjQsQWq2qd6nLt1ZWmJaJsRK+YmbxSzE
ijy7IvLskw==
MIIGUDCCBTigAwIBAgIDC9HlMA0GCSqGSIb3DQEBBQUAMIGMMQswCQYDVQQGEwJJ
TDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0
YWwgQ2VydGlmaWNhdGUgU2lnbmluZzE4MDYGA1UEAxMvU3RhcnRDb20gQ2xhc3Mg
MSBQcmltYXJ5IEludGVybWVkaWF0ZSBTZXJ2ZXIgQ0EwHhcNMTMwOTA0MDAxNzUy
WhcNMTQwOTA1MDIzOTIzWjBmMRkwFwYDVQQNExBVRURrSjRETjlnOVRHSU9EMQsw
CQYDVQQGEwJVUzEXMBUGA1UEAxMOdHJhYy56dWxpcC5uZXQxIzAhBgkqhkiG9w0B
CQEWFGhvc3RtYXN0ZXJAenVsaXAuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
MIIBCgKCAQEAzTJPAx4P6DYswRvG+nlzozYqEQJ07YoUMFOW+Gl11uu+OTF7coAF
fI6zbCyufA8z3vekSYst6DGvkPJVzSgPffJX6TUrfEGmWjZ1cGR9yYx4n894ZjD0
rQprnc5v0AU1dusYIzw/DwxoV0Ah6v+XW3ovlllAPkuzgDPgL4pLbvnRqMjuJZpb
RRL5L2WMP9ViS5BtZnwQaT9f36IOb+La62n5WuBUrcY8VqTALoZ0Mn1ePedwWfP1
ASpTBaoSIOXnX99bdyfcXAZ34SIVh4w2or6DiweRWPCLAGmf4zcX4JZuLRqodRzA
Yp8Nb+e9fyECNQXh7d9eCGGnRQKvTbWQsQIDAQABo4IC3jCCAtowCQYDVR0TBAIw
ADALBgNVHQ8EBAMCA6gwEwYDVR0lBAwwCgYIKwYBBQUHAwEwHQYDVR0OBBYEFE+l
z3QC+/II2yTMU2ySY1bk/shOMB8GA1UdIwQYMBaAFOtCNNCYsKuf9BtrCPfMZC7v
DixFMCQGA1UdEQQdMBuCDnRyYWMuenVsaXAubmV0ggl6dWxpcC5uZXQwggFWBgNV
HSAEggFNMIIBSTAIBgZngQwBAgEwggE7BgsrBgEEAYG1NwECAzCCASowLgYIKwYB
BQUHAgEWImh0dHA6Ly93d3cuc3RhcnRzc2wuY29tL3BvbGljeS5wZGYwgfcGCCsG
AQUFBwICMIHqMCcWIFN0YXJ0Q29tIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MAMC
AQEagb5UaGlzIGNlcnRpZmljYXRlIHdhcyBpc3N1ZWQgYWNjb3JkaW5nIHRvIHRo
ZSBDbGFzcyAxIFZhbGlkYXRpb24gcmVxdWlyZW1lbnRzIG9mIHRoZSBTdGFydENv
bSBDQSBwb2xpY3ksIHJlbGlhbmNlIG9ubHkgZm9yIHRoZSBpbnRlbmRlZCBwdXJw
b3NlIGluIGNvbXBsaWFuY2Ugb2YgdGhlIHJlbHlpbmcgcGFydHkgb2JsaWdhdGlv
bnMuMDUGA1UdHwQuMCwwKqAooCaGJGh0dHA6Ly9jcmwuc3RhcnRzc2wuY29tL2Ny
dDEtY3JsLmNybDCBjgYIKwYBBQUHAQEEgYEwfzA5BggrBgEFBQcwAYYtaHR0cDov
L29jc3Auc3RhcnRzc2wuY29tL3N1Yi9jbGFzczEvc2VydmVyL2NhMEIGCCsGAQUF
BzAChjZodHRwOi8vYWlhLnN0YXJ0c3NsLmNvbS9jZXJ0cy9zdWIuY2xhc3MxLnNl
cnZlci5jYS5jcnQwIwYDVR0SBBwwGoYYaHR0cDovL3d3dy5zdGFydHNzbC5jb20v
MA0GCSqGSIb3DQEBBQUAA4IBAQAesF3CsRJ0xYo6DMY4nK+pUdNvo36hnbmibMeI
mm4likq/gLPIWTujD/nRmfanhDAf4s5N0KTC7Dg/cz4F3b79k8E84abxA5FOvyBj
bBqQWTAQk55N2sZYiZKsUC7Jg6gHT4A13pYCpO6YXog7Yu6MsNuH+1PSMe1bLy7f
n3zSU5KIN39x5DuHz50bG/1M/IM+7OUkexojZsDtIvjAvNcdQuEEQqsPXCSkksPp
Bq7qVB6XUKiTlbIPz41JkJS6uAHJ6/bScj/wcPGsxKVo9DxmThfJ4WPircObR0gD
keboaE9UsYvK25Zr32NHDSN0cj21TzuVHwVIioz6ct3xkZYb
-----END CERTIFICATE-----

View File

@@ -1,62 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIF3DCCBMSgAwIBAgIQB/FzpmEZ29lq/NnM5SNypTANBgkqhkiG9w0BAQsFADBw
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMS8wLQYDVQQDEyZEaWdpQ2VydCBTSEEyIEhpZ2ggQXNz
dXJhbmNlIFNlcnZlciBDQTAeFw0xNDA0MTAwMDAwMDBaFw0xNzA0MTMxMjAwMDBa
MGoxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1T
YW4gRnJhbmNpc2NvMRUwEwYDVQQKEwxEcm9wYm94LCBJbmMxFzAVBgNVBAMMDiou
aHVtYnVnaHEuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4mVr
lCy+dTQe5dc5dE0CoAlOtIgLfAcIbHvoqtXpo6M1fhdCCJG8THvsdqgzRAJGsvmp
cPkjd1ahz8cs0Awq/4E1yRYvwc4n0Uj7kVkLo/daZB3U+9YE9zRNz8m0C7+5MVx3
yNXrSzsueA5Z2AHU7rsWGU4bFn0HD19BS0SsL4T/5XuHdxD5rY357lN2oy4hSGQO
Pzr/JkxiZCqvcyT/lYT1K0Z0OUjZxzZWnCKemXXCEreN7jyYqatgS3YolYeCtfr3
1LToY05r4br08frt6HfoJ/b+0wT5vLtBStRBoYbrXQ8bJh+pNdK/CdmnoOchxBUB
s3klxcji0z2P/j4q8wIDAQABo4ICdjCCAnIwHwYDVR0jBBgwFoAUUWj/kK8CB3U8
zNllZGKiErhZcjswHQYDVR0OBBYEFAPpaDtaKOl1+zRnO2xhgDQq/SxWMIGxBgNV
HREEgakwgaaCDiouaHVtYnVnaHEuY29tggxodW1idWdocS5jb22CDSouZS56dWxp
cC5jb22CC2UuenVsaXAuY29tgg4qLnp1bGlwY2RuLm5ldIIMenVsaXBjZG4ubmV0
gg4qLnp1bGlwY2RuLmNvbYIMenVsaXBjZG4uY29tggsqLnp1bGlwLm5ldIIJenVs
aXAubmV0ggsqLnp1bGlwLmNvbYIJenVsaXAuY29tMA4GA1UdDwEB/wQEAwIFoDAd
BgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwdQYDVR0fBG4wbDA0oDKgMIYu
aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL3NoYTItaGEtc2VydmVyLWcxLmNybDA0
oDKgMIYuaHR0cDovL2NybDQuZGlnaWNlcnQuY29tL3NoYTItaGEtc2VydmVyLWcx
LmNybDBCBgNVHSAEOzA5MDcGCWCGSAGG/WwBATAqMCgGCCsGAQUFBwIBFhxodHRw
czovL3d3dy5kaWdpY2VydC5jb20vQ1BTMIGDBggrBgEFBQcBAQR3MHUwJAYIKwYB
BQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBNBggrBgEFBQcwAoZBaHR0
cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkhpZ2hBc3N1cmFu
Y2VTZXJ2ZXJDQS5jcnQwDAYDVR0TAQH/BAIwADANBgkqhkiG9w0BAQsFAAOCAQEA
UbdsR5JFf+lqTU9T4H9Qz0A0Vi7T+1B2+uPEpsarTULENCImoJHt4nsglQrFmqlv
P3xnV7QoMuz+Fn/TWDDGNWYc3HxepMRsSpRFfrnrq8eLFYFCbNk9EG41mMA+kmyM
O+7Tg5o8Vz935Mwa1vWP/EIsgEINvgYx83MFelcP3lpxoRO1JTtA4sweLjZuPvLk
66o2lQi9tOEU735ySGEO/tgzPBPCwadfRz2olT8riUJf1ddi+BCXqoMQOUaENmRi
nyJ3vS2cNrX47gE7kYFlogvLAFgLBvlBXbQ5rI7YdXsvXpY4hY6bcd2LRZ92i614
MEvDJULOZS5Q7WFH9xp7+Q==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIEsTCCA5mgAwIBAgIQBOHnpNxc8vNtwCtCuF0VnzANBgkqhkiG9w0BAQsFADBs
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j
ZSBFViBSb290IENBMB4XDTEzMTAyMjEyMDAwMFoXDTI4MTAyMjEyMDAwMFowcDEL
MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3
LmRpZ2ljZXJ0LmNvbTEvMC0GA1UEAxMmRGlnaUNlcnQgU0hBMiBIaWdoIEFzc3Vy
YW5jZSBTZXJ2ZXIgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC2
4C/CJAbIbQRf1+8KZAayfSImZRauQkCbztyfn3YHPsMwVYcZuU+UDlqUH1VWtMIC
Kq/QmO4LQNfE0DtyyBSe75CxEamu0si4QzrZCwvV1ZX1QK/IHe1NnF9Xt4ZQaJn1
itrSxwUfqJfJ3KSxgoQtxq2lnMcZgqaFD15EWCo3j/018QsIJzJa9buLnqS9UdAn
4t07QjOjBSjEuyjMmqwrIw14xnvmXnG3Sj4I+4G3FhahnSMSTeXXkgisdaScus0X
sh5ENWV/UyU50RwKmmMbGZJ0aAo3wsJSSMs5WqK24V3B3aAguCGikyZvFEohQcft
bZvySC/zA/WiaJJTL17jAgMBAAGjggFJMIIBRTASBgNVHRMBAf8ECDAGAQH/AgEA
MA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw
NAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2Vy
dC5jb20wSwYDVR0fBEQwQjBAoD6gPIY6aHR0cDovL2NybDQuZGlnaWNlcnQuY29t
L0RpZ2lDZXJ0SGlnaEFzc3VyYW5jZUVWUm9vdENBLmNybDA9BgNVHSAENjA0MDIG
BFUdIAAwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQ
UzAdBgNVHQ4EFgQUUWj/kK8CB3U8zNllZGKiErhZcjswHwYDVR0jBBgwFoAUsT7D
aQP4v0cB1JgmGggC72NkK8MwDQYJKoZIhvcNAQELBQADggEBABiKlYkD5m3fXPwd
aOpKj4PWUS+Na0QWnqxj9dJubISZi6qBcYRb7TROsLd5kinMLYBq8I4g4Xmk/gNH
E+r1hspZcX30BJZr01lYPf7TMSVcGDiEo+afgv2MW5gxTs14nhr9hctJqvIni5ly
/D6q1UEL2tU2ob8cbkdJf17ZSHwD2f2LSaCYJkJA69aSEaRkCldUxPUd1gJea6zu
xICaEnL6VpPX/78whQYwvwt/Tv9XBZ0k7YXDK/umdaisLRbvfXknsuvCnQsH6qqF
0wGjIChBWUMo0oHjqvbsezt3tkBigAVBRQHvFwY+3sAzm2fTYS5yh+Rp/BIAV0Ae
cPUeybQ=
-----END CERTIFICATE-----

View File

@@ -1,34 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIF3DCCBMSgAwIBAgIQB/FzpmEZ29lq/NnM5SNypTANBgkqhkiG9w0BAQsFADBw
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMS8wLQYDVQQDEyZEaWdpQ2VydCBTSEEyIEhpZ2ggQXNz
dXJhbmNlIFNlcnZlciBDQTAeFw0xNDA0MTAwMDAwMDBaFw0xNzA0MTMxMjAwMDBa
MGoxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1T
YW4gRnJhbmNpc2NvMRUwEwYDVQQKEwxEcm9wYm94LCBJbmMxFzAVBgNVBAMMDiou
aHVtYnVnaHEuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4mVr
lCy+dTQe5dc5dE0CoAlOtIgLfAcIbHvoqtXpo6M1fhdCCJG8THvsdqgzRAJGsvmp
cPkjd1ahz8cs0Awq/4E1yRYvwc4n0Uj7kVkLo/daZB3U+9YE9zRNz8m0C7+5MVx3
yNXrSzsueA5Z2AHU7rsWGU4bFn0HD19BS0SsL4T/5XuHdxD5rY357lN2oy4hSGQO
Pzr/JkxiZCqvcyT/lYT1K0Z0OUjZxzZWnCKemXXCEreN7jyYqatgS3YolYeCtfr3
1LToY05r4br08frt6HfoJ/b+0wT5vLtBStRBoYbrXQ8bJh+pNdK/CdmnoOchxBUB
s3klxcji0z2P/j4q8wIDAQABo4ICdjCCAnIwHwYDVR0jBBgwFoAUUWj/kK8CB3U8
zNllZGKiErhZcjswHQYDVR0OBBYEFAPpaDtaKOl1+zRnO2xhgDQq/SxWMIGxBgNV
HREEgakwgaaCDiouaHVtYnVnaHEuY29tggxodW1idWdocS5jb22CDSouZS56dWxp
cC5jb22CC2UuenVsaXAuY29tgg4qLnp1bGlwY2RuLm5ldIIMenVsaXBjZG4ubmV0
gg4qLnp1bGlwY2RuLmNvbYIMenVsaXBjZG4uY29tggsqLnp1bGlwLm5ldIIJenVs
aXAubmV0ggsqLnp1bGlwLmNvbYIJenVsaXAuY29tMA4GA1UdDwEB/wQEAwIFoDAd
BgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwdQYDVR0fBG4wbDA0oDKgMIYu
aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL3NoYTItaGEtc2VydmVyLWcxLmNybDA0
oDKgMIYuaHR0cDovL2NybDQuZGlnaWNlcnQuY29tL3NoYTItaGEtc2VydmVyLWcx
LmNybDBCBgNVHSAEOzA5MDcGCWCGSAGG/WwBATAqMCgGCCsGAQUFBwIBFhxodHRw
czovL3d3dy5kaWdpY2VydC5jb20vQ1BTMIGDBggrBgEFBQcBAQR3MHUwJAYIKwYB
BQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBNBggrBgEFBQcwAoZBaHR0
cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkhpZ2hBc3N1cmFu
Y2VTZXJ2ZXJDQS5jcnQwDAYDVR0TAQH/BAIwADANBgkqhkiG9w0BAQsFAAOCAQEA
UbdsR5JFf+lqTU9T4H9Qz0A0Vi7T+1B2+uPEpsarTULENCImoJHt4nsglQrFmqlv
P3xnV7QoMuz+Fn/TWDDGNWYc3HxepMRsSpRFfrnrq8eLFYFCbNk9EG41mMA+kmyM
O+7Tg5o8Vz935Mwa1vWP/EIsgEINvgYx83MFelcP3lpxoRO1JTtA4sweLjZuPvLk
66o2lQi9tOEU735ySGEO/tgzPBPCwadfRz2olT8riUJf1ddi+BCXqoMQOUaENmRi
nyJ3vS2cNrX47gE7kYFlogvLAFgLBvlBXbQ5rI7YdXsvXpY4hY6bcd2LRZ92i614
MEvDJULOZS5Q7WFH9xp7+Q==
-----END CERTIFICATE-----

View File

@@ -0,0 +1,84 @@
-----BEGIN CERTIFICATE-----
MIIFGzCCBAOgAwIBAgIQJMWnZBA8pItLin6/RwqFKzANBgkqhkiG9w0BAQUFADBz
MQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYD
VQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01PRE8gQ0EgTGltaXRlZDEZMBcGA1UE
AxMQUG9zaXRpdmVTU0wgQ0EgMjAeFw0xNDAxMTcwMDAwMDBaFw0xNTAxMTcyMzU5
NTlaMGExITAfBgNVBAsTGERvbWFpbiBDb250cm9sIFZhbGlkYXRlZDEhMB8GA1UE
CxMYUG9zaXRpdmVTU0wgTXVsdGktRG9tYWluMRkwFwYDVQQDExB3d3cuaHVtYnVn
aHEuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvhrAmjW7Om0e
AgdDCdjQER9CTKF7AlRxwn09ePWq6WaAH/bOHJlIKnv6l5e43odR2+VLQEYXITTE
f6aBV/Q3e96k1XwxL7QElns6bBAAdyiUIiEo1Mi/McUQIIGH+QF7SdkM2h6EN7EJ
OuZVbmqweGkMBQfkrG3bVHQ0xwIJyd6fFc+HBY7rNp/xFvrXeXO+Fe2OpwI/8MPM
oEUXQL3xph2vOGRxLvsQiOXJ19O9OISREw379RC4Nue0ZoOaW8B304UhrOSlr+wE
KqS4PsDUQ/7OSztaOswdc06InXKvB2g9v4Ut6AEFIm8kkY4nkxxNSVNbnqo359IK
6wqaEo4KwwIDAQABo4IBuzCCAbcwHwYDVR0jBBgwFoAUmeRAX2sUXj4F2d3TY1T8
Yrj3AKwwHQYDVR0OBBYEFKcvpXO4MrbndGJweHXaZZhIJBHiMA4GA1UdDwEB/wQE
AwIFoDAMBgNVHRMBAf8EAjAAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcD
AjBQBgNVHSAESTBHMDsGCysGAQQBsjEBAgIHMCwwKgYIKwYBBQUHAgEWHmh0dHA6
Ly93d3cucG9zaXRpdmVzc2wuY29tL0NQUzAIBgZngQwBAgEwOwYDVR0fBDQwMjAw
oC6gLIYqaHR0cDovL2NybC5jb21vZG9jYS5jb20vUG9zaXRpdmVTU0xDQTIuY3Js
MGwGCCsGAQUFBwEBBGAwXjA2BggrBgEFBQcwAoYqaHR0cDovL2NydC5jb21vZG9j
YS5jb20vUG9zaXRpdmVTU0xDQTIuY3J0MCQGCCsGAQUFBzABhhhodHRwOi8vb2Nz
cC5jb21vZG9jYS5jb20wOwYDVR0RBDQwMoIQd3d3Lmh1bWJ1Z2hxLmNvbYIQYXBp
Lmh1bWJ1Z2hxLmNvbYIMaHVtYnVnaHEuY29tMA0GCSqGSIb3DQEBBQUAA4IBAQBN
UcbNU/VgDwvQ9BsDL9RM3Nad/muUgc3VF9KF4n0AwzsOxjE1l3toGo9da4MBnUCG
2dYntzCGGcbosiqQZl+3UEk8ny+2fW8BhXG0/4uKRQrSYAQOFgH6fr2OQqW1qT6o
wi4leXLA+Et+bKvDUYRQ8f9rGgPYIogqkioUp4KDuZsx2EKoVkrVtaL8e4n+xDMz
/hEMRMicCtrbzWec0wZZp0MfDpwbhLkD7KA7lfSy3E9Cx+BkOu4kFsHYhYIpWCZV
cSsfHDPABm5xawMq6HVK4EPkkAN4aQnRi+min3CInSQ73SaDVnxAS12NXyPgorbY
gzgt5befNJuv0nyYLiJa
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIE5TCCA82gAwIBAgIQB28SRoFFnCjVSNaXxA4AGzANBgkqhkiG9w0BAQUFADBv
MQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFk
ZFRydXN0IEV4dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBF
eHRlcm5hbCBDQSBSb290MB4XDTEyMDIxNjAwMDAwMFoXDTIwMDUzMDEwNDgzOFow
czELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxGTAXBgNV
BAMTEFBvc2l0aXZlU1NMIENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
AoIBAQDo6jnjIqaqucQA0OeqZztDB71Pkuu8vgGjQK3g70QotdA6voBUF4V6a4Rs
NjbloyTi/igBkLzX3Q+5K05IdwVpr95XMLHo+xoD9jxbUx6hAUlocnPWMytDqTcy
Ug+uJ1YxMGCtyb1zLDnukNh1sCUhYHsqfwL9goUfdE+SNHNcHQCgsMDqmOK+ARRY
FygiinddUCXNmmym5QzlqyjDsiCJ8AckHpXCLsDl6ez2PRIHSD3SwyNWQezT3zVL
yOf2hgVSEEOajBd8i6q8eODwRTusgFX+KJPhChFo9FJXb/5IC1tdGmpnc5mCtJ5D
YD7HWyoSbhruyzmuwzWdqLxdsC/DAgMBAAGjggF3MIIBczAfBgNVHSMEGDAWgBSt
vZh6NLQm9/rEJlTvA73gJMtUGjAdBgNVHQ4EFgQUmeRAX2sUXj4F2d3TY1T8Yrj3
AKwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwEQYDVR0gBAow
CDAGBgRVHSAAMEQGA1UdHwQ9MDswOaA3oDWGM2h0dHA6Ly9jcmwudXNlcnRydXN0
LmNvbS9BZGRUcnVzdEV4dGVybmFsQ0FSb290LmNybDCBswYIKwYBBQUHAQEEgaYw
gaMwPwYIKwYBBQUHMAKGM2h0dHA6Ly9jcnQudXNlcnRydXN0LmNvbS9BZGRUcnVz
dEV4dGVybmFsQ0FSb290LnA3YzA5BggrBgEFBQcwAoYtaHR0cDovL2NydC51c2Vy
dHJ1c3QuY29tL0FkZFRydXN0VVROU0dDQ0EuY3J0MCUGCCsGAQUFBzABhhlodHRw
Oi8vb2NzcC51c2VydHJ1c3QuY29tMA0GCSqGSIb3DQEBBQUAA4IBAQCcNuNOrvGK
u2yXjI9LZ9Cf2ISqnyFfNaFbxCtjDei8d12nxDf9Sy2e6B1pocCEzNFti/OBy59L
dLBJKjHoN0DrH9mXoxoR1Sanbg+61b4s/bSRZNy+OxlQDXqV8wQTqbtHD4tc0azC
e3chUN1bq+70ptjUSlNrTa24yOfmUlhNQ0zCoiNPDsAgOa/fT0JbHtMJ9BgJWSrZ
6EoYvzL7+i1ki4fKWyvouAt+vhcSxwOCKa9Yr4WEXT0K3yNRw82vEL+AaXeRCk/l
uuGtm87fM04wO+mPZn+C+mv626PAcwDj1hKvTfIPWhRRH224hoFiB85ccsJP81cq
cdnUl4XmGFO3
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEU
MBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFs
IFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290
MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFowbzELMAkGA1UEBhMCU0Ux
FDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRUcnVzdCBFeHRlcm5h
bCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0EgUm9v
dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvt
H7xsD821+iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9
uMq/NzgtHj6RQa1wVsfwTz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzX
mk6vBbOmcZSccbNQYArHE504B4YCqOmoaSYYkKtMsE8jqzpPhNjfzp/haW+710LX
a0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy2xSoRcRdKn23tNbE7qzN
E0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv77+ldU9U0
WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYD
VR0PBAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0
Jvf6xCZU7wO94CTLVBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRU
cnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsx
IjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJvb3SCAQEwDQYJKoZIhvcN
AQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZlj7DYd7usQWxH
YINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5
6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvC
Nr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEX
c4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5a
mnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ=
-----END CERTIFICATE-----

View File

@@ -0,0 +1,30 @@
-----BEGIN CERTIFICATE-----
MIIFGzCCBAOgAwIBAgIQJMWnZBA8pItLin6/RwqFKzANBgkqhkiG9w0BAQUFADBz
MQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYD
VQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01PRE8gQ0EgTGltaXRlZDEZMBcGA1UE
AxMQUG9zaXRpdmVTU0wgQ0EgMjAeFw0xNDAxMTcwMDAwMDBaFw0xNTAxMTcyMzU5
NTlaMGExITAfBgNVBAsTGERvbWFpbiBDb250cm9sIFZhbGlkYXRlZDEhMB8GA1UE
CxMYUG9zaXRpdmVTU0wgTXVsdGktRG9tYWluMRkwFwYDVQQDExB3d3cuaHVtYnVn
aHEuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvhrAmjW7Om0e
AgdDCdjQER9CTKF7AlRxwn09ePWq6WaAH/bOHJlIKnv6l5e43odR2+VLQEYXITTE
f6aBV/Q3e96k1XwxL7QElns6bBAAdyiUIiEo1Mi/McUQIIGH+QF7SdkM2h6EN7EJ
OuZVbmqweGkMBQfkrG3bVHQ0xwIJyd6fFc+HBY7rNp/xFvrXeXO+Fe2OpwI/8MPM
oEUXQL3xph2vOGRxLvsQiOXJ19O9OISREw379RC4Nue0ZoOaW8B304UhrOSlr+wE
KqS4PsDUQ/7OSztaOswdc06InXKvB2g9v4Ut6AEFIm8kkY4nkxxNSVNbnqo359IK
6wqaEo4KwwIDAQABo4IBuzCCAbcwHwYDVR0jBBgwFoAUmeRAX2sUXj4F2d3TY1T8
Yrj3AKwwHQYDVR0OBBYEFKcvpXO4MrbndGJweHXaZZhIJBHiMA4GA1UdDwEB/wQE
AwIFoDAMBgNVHRMBAf8EAjAAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcD
AjBQBgNVHSAESTBHMDsGCysGAQQBsjEBAgIHMCwwKgYIKwYBBQUHAgEWHmh0dHA6
Ly93d3cucG9zaXRpdmVzc2wuY29tL0NQUzAIBgZngQwBAgEwOwYDVR0fBDQwMjAw
oC6gLIYqaHR0cDovL2NybC5jb21vZG9jYS5jb20vUG9zaXRpdmVTU0xDQTIuY3Js
MGwGCCsGAQUFBwEBBGAwXjA2BggrBgEFBQcwAoYqaHR0cDovL2NydC5jb21vZG9j
YS5jb20vUG9zaXRpdmVTU0xDQTIuY3J0MCQGCCsGAQUFBzABhhhodHRwOi8vb2Nz
cC5jb21vZG9jYS5jb20wOwYDVR0RBDQwMoIQd3d3Lmh1bWJ1Z2hxLmNvbYIQYXBp
Lmh1bWJ1Z2hxLmNvbYIMaHVtYnVnaHEuY29tMA0GCSqGSIb3DQEBBQUAA4IBAQBN
UcbNU/VgDwvQ9BsDL9RM3Nad/muUgc3VF9KF4n0AwzsOxjE1l3toGo9da4MBnUCG
2dYntzCGGcbosiqQZl+3UEk8ny+2fW8BhXG0/4uKRQrSYAQOFgH6fr2OQqW1qT6o
wi4leXLA+Et+bKvDUYRQ8f9rGgPYIogqkioUp4KDuZsx2EKoVkrVtaL8e4n+xDMz
/hEMRMicCtrbzWec0wZZp0MfDpwbhLkD7KA7lfSy3E9Cx+BkOu4kFsHYhYIpWCZV
cSsfHDPABm5xawMq6HVK4EPkkAN4aQnRi+min3CInSQ73SaDVnxAS12NXyPgorbY
gzgt5befNJuv0nyYLiJa
-----END CERTIFICATE-----

View File

@@ -0,0 +1,116 @@
-----BEGIN CERTIFICATE-----
MIIGTjCCBTagAwIBAgIDCxnHMA0GCSqGSIb3DQEBBQUAMIGMMQswCQYDVQQGEwJJ
TDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0
YWwgQ2VydGlmaWNhdGUgU2lnbmluZzE4MDYGA1UEAxMvU3RhcnRDb20gQ2xhc3Mg
MSBQcmltYXJ5IEludGVybWVkaWF0ZSBTZXJ2ZXIgQ0EwHhcNMTMwNzEyMDc0NDM5
WhcNMTQwNzEzMTMzNTA0WjBlMRkwFwYDVQQNExBwSkVlSTRDd1F1Q2E0MTZrMQsw
CQYDVQQGEwJVUzEWMBQGA1UEAxMNd3d3Lnp1bGlwLmNvbTEjMCEGCSqGSIb3DQEJ
ARYUaG9zdG1hc3RlckB6dWxpcC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
ggEKAoIBAQC+GsCaNbs6bR4CB0MJ2NARH0JMoXsCVHHCfT149arpZoAf9s4cmUgq
e/qXl7jeh1Hb5UtARhchNMR/poFX9Dd73qTVfDEvtASWezpsEAB3KJQiISjUyL8x
xRAggYf5AXtJ2QzaHoQ3sQk65lVuarB4aQwFB+SsbdtUdDTHAgnJ3p8Vz4cFjus2
n/EW+td5c74V7Y6nAj/ww8ygRRdAvfGmHa84ZHEu+xCI5cnX0704hJETDfv1ELg2
57Rmg5pbwHfThSGs5KWv7AQqpLg+wNRD/s5LO1o6zB1zToidcq8HaD2/hS3oAQUi
bySRjieTHE1JU1ueqjfn0grrCpoSjgrDAgMBAAGjggLdMIIC2TAJBgNVHRMEAjAA
MAsGA1UdDwQEAwIDqDATBgNVHSUEDDAKBggrBgEFBQcDATAdBgNVHQ4EFgQUpy+l
c7gytud0YnB4ddplmEgkEeIwHwYDVR0jBBgwFoAU60I00Jiwq5/0G2sI98xkLu8O
LEUwIwYDVR0RBBwwGoINd3d3Lnp1bGlwLmNvbYIJenVsaXAuY29tMIIBVgYDVR0g
BIIBTTCCAUkwCAYGZ4EMAQIBMIIBOwYLKwYBBAGBtTcBAgMwggEqMC4GCCsGAQUF
BwIBFiJodHRwOi8vd3d3LnN0YXJ0c3NsLmNvbS9wb2xpY3kucGRmMIH3BggrBgEF
BQcCAjCB6jAnFiBTdGFydENvbSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTADAgEB
GoG+VGhpcyBjZXJ0aWZpY2F0ZSB3YXMgaXNzdWVkIGFjY29yZGluZyB0byB0aGUg
Q2xhc3MgMSBWYWxpZGF0aW9uIHJlcXVpcmVtZW50cyBvZiB0aGUgU3RhcnRDb20g
Q0EgcG9saWN5LCByZWxpYW5jZSBvbmx5IGZvciB0aGUgaW50ZW5kZWQgcHVycG9z
ZSBpbiBjb21wbGlhbmNlIG9mIHRoZSByZWx5aW5nIHBhcnR5IG9ibGlnYXRpb25z
LjA1BgNVHR8ELjAsMCqgKKAmhiRodHRwOi8vY3JsLnN0YXJ0c3NsLmNvbS9jcnQx
LWNybC5jcmwwgY4GCCsGAQUFBwEBBIGBMH8wOQYIKwYBBQUHMAGGLWh0dHA6Ly9v
Y3NwLnN0YXJ0c3NsLmNvbS9zdWIvY2xhc3MxL3NlcnZlci9jYTBCBggrBgEFBQcw
AoY2aHR0cDovL2FpYS5zdGFydHNzbC5jb20vY2VydHMvc3ViLmNsYXNzMS5zZXJ2
ZXIuY2EuY3J0MCMGA1UdEgQcMBqGGGh0dHA6Ly93d3cuc3RhcnRzc2wuY29tLzAN
BgkqhkiG9w0BAQUFAAOCAQEArJy0N4Z3huyZQNoWxLMdvplo14L13HcxyyNtFQTG
zjLHyM0oQ2OT0wc1XzPl5kZGfopXztgFDdbdc31A8QyawxxeuOHtETM67pioM5xA
9lBinx7oYkB0FYtBdU3XdcHZyP569puCeDHmtk7Snrl6IofTYLytehtWojsdwYQc
ml3z5RPcHF8eFeazbWLAzfG1ejsdUSm5lAHdow8cA2B0m1Dg5ko5dcJ4wEtazCgX
+gSIZDClQMXsixWbBRIjw1KJ//8bzADbzKBEAO8XP/GHFxJFy1dINh1lj5pSSeg5
FUqw/3vEE49Ty5ggltF3/iIBxOb6YdTw0ZpclvZK9ocytg==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIGNDCCBBygAwIBAgIBGDANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEW
MBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwg
Q2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNh
dGlvbiBBdXRob3JpdHkwHhcNMDcxMDI0MjA1NDE3WhcNMTcxMDI0MjA1NDE3WjCB
jDELMAkGA1UEBhMCSUwxFjAUBgNVBAoTDVN0YXJ0Q29tIEx0ZC4xKzApBgNVBAsT
IlNlY3VyZSBEaWdpdGFsIENlcnRpZmljYXRlIFNpZ25pbmcxODA2BgNVBAMTL1N0
YXJ0Q29tIENsYXNzIDEgUHJpbWFyeSBJbnRlcm1lZGlhdGUgU2VydmVyIENBMIIB
IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtonGrO8JUngHrJJj0PREGBiE
gFYfka7hh/oyULTTRwbw5gdfcA4Q9x3AzhA2NIVaD5Ksg8asWFI/ujjo/OenJOJA
pgh2wJJuniptTT9uYSAK21ne0n1jsz5G/vohURjXzTCm7QduO3CHtPn66+6CPAVv
kvek3AowHpNz/gfK11+AnSJYUq4G2ouHI2mw5CrY6oPSvfNx23BaKA+vWjhwRRI/
ME3NO68X5Q/LoKldSKqxYVDLNM08XMML6BDAjJvwAwNi/rJsPnIO7hxDKslIDlc5
xDEhyBDBLIf+VJVSH1I8MRKbf+fAoKVZ1eKPPvDVqOHXcDGpxLPPr21TLwb0pwID
AQABo4IBrTCCAakwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD
VR0OBBYEFOtCNNCYsKuf9BtrCPfMZC7vDixFMB8GA1UdIwQYMBaAFE4L7xqkQFul
F2mHMMo0aEPQQa7yMGYGCCsGAQUFBwEBBFowWDAnBggrBgEFBQcwAYYbaHR0cDov
L29jc3Auc3RhcnRzc2wuY29tL2NhMC0GCCsGAQUFBzAChiFodHRwOi8vd3d3LnN0
YXJ0c3NsLmNvbS9zZnNjYS5jcnQwWwYDVR0fBFQwUjAnoCWgI4YhaHR0cDovL3d3
dy5zdGFydHNzbC5jb20vc2ZzY2EuY3JsMCegJaAjhiFodHRwOi8vY3JsLnN0YXJ0
c3NsLmNvbS9zZnNjYS5jcmwwgYAGA1UdIAR5MHcwdQYLKwYBBAGBtTcBAgEwZjAu
BggrBgEFBQcCARYiaHR0cDovL3d3dy5zdGFydHNzbC5jb20vcG9saWN5LnBkZjA0
BggrBgEFBQcCARYoaHR0cDovL3d3dy5zdGFydHNzbC5jb20vaW50ZXJtZWRpYXRl
LnBkZjANBgkqhkiG9w0BAQUFAAOCAgEAIQlJPqWIbuALi0jaMU2P91ZXouHTYlfp
tVbzhUV1O+VQHwSL5qBaPucAroXQ+/8gA2TLrQLhxpFy+KNN1t7ozD+hiqLjfDen
xk+PNdb01m4Ge90h2c9W/8swIkn+iQTzheWq8ecf6HWQTd35RvdCNPdFWAwRDYSw
xtpdPvkBnufh2lWVvnQce/xNFE+sflVHfXv0pQ1JHpXo9xLBzP92piVH0PN1Nb6X
t1gW66pceG/sUzCv6gRNzKkC4/C2BBL2MLERPZBOVmTX3DxDX3M570uvh+v2/miI
RHLq0gfGabDBoYvvF0nXYbFFSF87ICHpW7LM9NfpMfULFWE7epTj69m8f5SuauNi
YpaoZHy4h/OZMn6SolK+u/hlz8nyMPyLwcKmltdfieFcNID1j0cHL7SRv7Gifl9L
WtBbnySGBVFaaQNlQ0lxxeBvlDRr9hvYqbBMflPrj0jfyjO1SPo2ShpTpjMM0InN
SRXNiTE8kMBy12VLUjWKRhFEuT2OKGWmPnmeXAhEKa2wNREuIU640ucQPl2Eg7PD
wuTSxv0JS3QJ3fGz0xk+gA2iCxnwOOfFwq/iI9th4p1cbiCJSS4jarJiwUW0n6+L
p/EiO/h94pDQehn7Skzj0n1fSoMD7SfWI55rjbRZotnvbIIp3XUZPD9MEI3vu3Un
0q6Dp6jOW6c=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIHyTCCBbGgAwIBAgIBATANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEW
MBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwg
Q2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNh
dGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0NjM2WhcNMzYwOTE3MTk0NjM2WjB9
MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMi
U2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3Rh
cnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUA
A4ICDwAwggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZk
pMyONvg45iPwbm2xPN1yo4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rf
OQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/C
Ji/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/deMotHweXMAEtcnn6RtYT
Kqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt2PZE4XNi
HzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMM
Av+Z6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w
+2OqqGwaVLRcJXrJosmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+
Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3
Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVcUjyJthkqcwEKDwOzEmDyei+B
26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT37uMdBNSSwID
AQABo4ICUjCCAk4wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAa4wHQYDVR0OBBYE
FE4L7xqkQFulF2mHMMo0aEPQQa7yMGQGA1UdHwRdMFswLKAqoCiGJmh0dHA6Ly9j
ZXJ0LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMCugKaAnhiVodHRwOi8vY3Js
LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMIIBXQYDVR0gBIIBVDCCAVAwggFM
BgsrBgEEAYG1NwEBATCCATswLwYIKwYBBQUHAgEWI2h0dHA6Ly9jZXJ0LnN0YXJ0
Y29tLm9yZy9wb2xpY3kucGRmMDUGCCsGAQUFBwIBFilodHRwOi8vY2VydC5zdGFy
dGNvbS5vcmcvaW50ZXJtZWRpYXRlLnBkZjCB0AYIKwYBBQUHAgIwgcMwJxYgU3Rh
cnQgQ29tbWVyY2lhbCAoU3RhcnRDb20pIEx0ZC4wAwIBARqBl0xpbWl0ZWQgTGlh
YmlsaXR5LCByZWFkIHRoZSBzZWN0aW9uICpMZWdhbCBMaW1pdGF0aW9ucyogb2Yg
dGhlIFN0YXJ0Q29tIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFBvbGljeSBhdmFp
bGFibGUgYXQgaHR0cDovL2NlcnQuc3RhcnRjb20ub3JnL3BvbGljeS5wZGYwEQYJ
YIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilTdGFydENvbSBGcmVlIFNT
TCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQUFAAOCAgEAFmyZ
9GYMNPXQhV59CuzaEE44HF7fpiUFS5Eyweg78T3dRAlbB0mKKctmArexmvclmAk8
jhvh3TaHK0u7aNM5Zj2gJsfyOZEdUauCe37Vzlrk4gNXcGmXCPleWKYK34wGmkUW
FjgKXlf2Ysd6AgXmvB618p70qSmD+LIU424oh0TDkBreOKk8rENNZEXO3SipXPJz
ewT4F+irsfMuXGRuczE6Eri8sxHkfY+BUZo7jYn0TZNmezwD7dOaHZrzZVD1oNB1
ny+v8OqCQ5j4aZyJecRDjkZy42Q2Eq/3JR44iZB3fsNrarnDy0RLrHiQi+fHLB5L
EUTINFInzQpdn4XBidUaePKVEFMy3YCEZnXZtWgo+2EuvoSoOMCZEoalHmdkrQYu
L6lwhceWD3yJZfWOQ1QOq92lgDmUYMA0yZZwLKMS9R9Ie70cfmu3nZD0Ijuu+Pwq
yvqCUqDvr0tVk+vBtfAii6w0TiYiBKGHLHVKt+V9E9e4DGTANtLJL4YSjCMJwRuC
O3NJo2pXh5Tl1njFmUNj403gdy3hZZlyaQQaRwnmDwFWJPsfvw55qVguucQJAX6V
um0ABj6y6koQOdjQK/W/7HW/lwLFCRsI3FU34oH7N4RDYiDK51ZLZer+bMEkkySh
NOsF/5oirpt9P/FlUQqmMGqz9IgcgA38corog14=
-----END CERTIFICATE-----

Some files were not shown because too many files have changed in this diff Show More