Commit bb7e8abb authored by Jitka Novotna's avatar Jitka Novotna

merge

parents 18911fb0 5be33f9b
checks:
python:
code_rating: true
duplicate_code: true
tools:
pylint:
python_version: '3'
config_file: 'ci/pylint-scrutinizer.rc'
filter:
excluded_paths:
- '*/test/*'
- '*/migrations/*'
before_commands:
- pip3 install https://github.com/translate/translate/zipball/de3f080abf6f2fecfca97d283a58eb6824d8078e
- pip3 install -r ci/requirements-scrutinizer.txt
build:
dependencies:
override:
- pip install https://github.com/translate/translate/zipball/de3f080abf6f2fecfca97d283a58eb6824d8078e
- pip install -r ci/requirements-scrutinizer.txt
tests:
override:
-
command: ./manage.py collectstatic --settings=weblate.settings_test --noinput
-
command: coverage run --source . ./manage.py test --settings=weblate.settings_test
coverage:
file: .coverage
format: py-cc
...@@ -17,7 +17,6 @@ env: ...@@ -17,7 +17,6 @@ env:
- CI_PIP_DEPS="Django>=1.9,<1.10" CI_MODE=setup - CI_PIP_DEPS="Django>=1.9,<1.10" CI_MODE=setup
- CI_PIP_DEPS="Django>=1.9,<1.10" CI_DATABASE=mysql - CI_PIP_DEPS="Django>=1.9,<1.10" CI_DATABASE=mysql
- CI_PIP_DEPS="Django>=1.9,<1.10" CI_DATABASE=postgresql - CI_PIP_DEPS="Django>=1.9,<1.10" CI_DATABASE=postgresql
- CI_PIP_DEPS="Django>=1.7,<1.8"
- CI_PIP_DEPS="Django>=1.8,<1.9" - CI_PIP_DEPS="Django>=1.8,<1.9"
- CI_PIP_DEPS="Django>=1.9,<1.10" - CI_PIP_DEPS="Django>=1.9,<1.10"
- CI_PIP_DEPS="Django>=1.9,<1.10" CI_DATABASE=postgresql CI_MODE=selenium - CI_PIP_DEPS="Django>=1.9,<1.10" CI_DATABASE=postgresql CI_MODE=selenium
...@@ -46,11 +45,14 @@ notifications: ...@@ -46,11 +45,14 @@ notifications:
matrix: matrix:
include: include:
- python: "3.4" - python: "3.4"
env: CI_PIP_DEPS="Django>=1.9,<1.10" env: CI_PIP_DEPS="Django>=1.9,<1.10 https://github.com/translate/translate/zipball/de3f080abf6f2fecfca97d283a58eb6824d8078e"
- python: "3.4" - python: "3.5"
env: CI_PIP_DEPS="Django>=1.9,<1.10" CI_MODE=lint env: CI_PIP_DEPS="Django>=1.9,<1.10 https://github.com/translate/translate/zipball/de3f080abf6f2fecfca97d283a58eb6824d8078e"
allow_failures: - python: "3.5"
- python: "3.4" env: CI_PIP_DEPS="Django>=1.9,<1.10 https://github.com/translate/translate/zipball/de3f080abf6f2fecfca97d283a58eb6824d8078e" CI_MODE=lint
env: CI_PIP_DEPS="Django>=1.9,<1.10" - python: "3.5"
- python: "3.4" env: CI_PIP_DEPS="Django>=1.9,<1.10 https://github.com/translate/translate/zipball/de3f080abf6f2fecfca97d283a58eb6824d8078e" CI_MODE=selenium
env: CI_PIP_DEPS="Django>=1.9,<1.10" CI_MODE=lint addons:
apt:
packages:
- mercurial
...@@ -24,6 +24,7 @@ include docs/_ext/*.py ...@@ -24,6 +24,7 @@ include docs/_ext/*.py
include docs/_static/*.png include docs/_static/*.png
include docs/_templates/*.html include docs/_templates/*.html
recursive-include examples * recursive-include examples *
include weblate/billing/test-data/*
include weblate/trans/tests/data/* include weblate/trans/tests/data/*
include weblate/trans/widget-images/*.png include weblate/trans/widget-images/*.png
include weblate/lang/plurals.txt include weblate/lang/plurals.txt
......
-r ../requirements.txt
# Copy of requirements-optional.txt without python_version modifiers
pyuca>=1.1
pyLibravatar
py3dns
Babel
chardet
python-memcached
# Test
httpretty!=0.8.11
coverage
...@@ -8,9 +8,9 @@ Installation instructions ...@@ -8,9 +8,9 @@ Installation instructions
Requirements Requirements
------------ ------------
Python (2.7, 3 is not supported) Python (2.7, 3.4 or newer)
https://www.python.org/ https://www.python.org/
Django (>= 1.7) Django (>= 1.8)
https://www.djangoproject.com/ https://www.djangoproject.com/
Translate-toolkit (>= 1.10.0) Translate-toolkit (>= 1.10.0)
http://toolkit.translatehouse.org/ http://toolkit.translatehouse.org/
......
...@@ -35,6 +35,8 @@ Released on ? 2015. ...@@ -35,6 +35,8 @@ Released on ? 2015.
* Added extensive group based ACLs. * Added extensive group based ACLs.
* Clarified terminology on strings needing review (formerly fuzzy). * Clarified terminology on strings needing review (formerly fuzzy).
* Clarified terminology on strings needing action and not translated strings. * Clarified terminology on strings needing action and not translated strings.
* Support for Python 3.
* Dropped support for Django 1.7.
weblate 2.4 weblate 2.4
----------- -----------
......
...@@ -71,7 +71,6 @@ done < $OPENSHIFT_REPO_DIR/requirements-optional.txt ...@@ -71,7 +71,6 @@ done < $OPENSHIFT_REPO_DIR/requirements-optional.txt
sh "python ${OPENSHIFT_REPO_DIR}/setup_weblate.py develop" sh "python ${OPENSHIFT_REPO_DIR}/setup_weblate.py develop"
sh "python ${OPENSHIFT_REPO_DIR}/openshift/manage.py migrate --noinput" sh "python ${OPENSHIFT_REPO_DIR}/openshift/manage.py migrate --noinput"
sh "python ${OPENSHIFT_REPO_DIR}/openshift/manage.py collectstatic --noinput"
if [ ! -s $OPENSHIFT_DATA_DIR/.credentials ]; then if [ ! -s $OPENSHIFT_DATA_DIR/.credentials ]; then
sh "python ${OPENSHIFT_REPO_DIR}/openshift/manage.py changesite --set-name ${OPENSHIFT_APP_DNS}" sh "python ${OPENSHIFT_REPO_DIR}/openshift/manage.py changesite --set-name ${OPENSHIFT_APP_DNS}"
......
...@@ -4,5 +4,6 @@ pyLibravatar ...@@ -4,5 +4,6 @@ pyLibravatar
pydns; python_version < '3.0' pydns; python_version < '3.0'
py3dns; python_version >= '3.0' py3dns; python_version >= '3.0'
Babel Babel
chardet
Mercurial>=2.8; python_version < '3.0' Mercurial>=2.8; python_version < '3.0'
python-memcached python-memcached
Django>=1.7 Django>=1.8
Whoosh>=2.5.2,!=2.6.0 Whoosh>=2.5.2,!=2.6.0
translate-toolkit>=1.10.0 translate-toolkit>=1.10.0
lxml>=3.1.0 lxml>=3.1.0
......
...@@ -93,6 +93,9 @@ setup( ...@@ -93,6 +93,9 @@ setup(
'Programming Language :: Python', 'Programming Language :: Python',
'Programming Language :: Python :: 2', 'Programming Language :: Python :: 2',
'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Topic :: Software Development :: Internationalization', 'Topic :: Software Development :: Internationalization',
'Topic :: Software Development :: Localization', 'Topic :: Software Development :: Localization',
'Topic :: Internet :: WWW/HTTP', 'Topic :: Internet :: WWW/HTTP',
......
...@@ -19,9 +19,7 @@ ...@@ -19,9 +19,7 @@
# #
import os import os
import re
from copy import _EmptyClass
import django.utils.translation.trans_real as django_trans
from weblate.requirements import ( from weblate.requirements import (
check_requirements, get_versions, get_optional_versions check_requirements, get_versions, get_optional_versions
) )
...@@ -111,34 +109,3 @@ def get_versions_string(): ...@@ -111,34 +109,3 @@ def get_versions_string():
check_requirements() check_requirements()
check_data_writable() check_data_writable()
create_ssh_wrapper() create_ssh_wrapper()
# Monkey patch locales, workaround for
# https://code.djangoproject.com/ticket/24063
django_trans.language_code_re = re.compile(
r'^[a-z]{1,8}(?:-[a-z0-9]{1,8})*(?:@[a-z0-9]{1,20})?$',
re.IGNORECASE
)
class DjangoTranslation(django_trans.DjangoTranslation):
"""
Unshared _info and _catalog to avoid Django messing up
locale variants.
This will not be needed in Django 1.8.
"""
def __copy__(self):
"""
Simplified version of copy._copy_inst extended for copying
_info and _catalog.
"""
result = _EmptyClass()
result.__class__ = self.__class__
state = self.__dict__
state['_info'] = self._info.copy()
state['_catalog'] = self._catalog.copy()
result.__dict__.update(state)
return result
django_trans.DjangoTranslation = DjangoTranslation
...@@ -55,9 +55,11 @@ def avatar_for_email(email, size=80): ...@@ -55,9 +55,11 @@ def avatar_for_email(email, size=80):
if email == '': if email == '':
email = 'noreply@weblate.org' email = 'noreply@weblate.org'
mail_hash = hashlib.md5(email.lower().encode('utf-8')).hexdigest()
# Retrieve from cache # Retrieve from cache
cache_key = 'avatar-{0}-{1}'.format( cache_key = 'avatar-{0}-{1}'.format(
email.encode('base64').strip(), mail_hash,
size size
) )
cache = caches['default'] cache = caches['default']
...@@ -76,8 +78,6 @@ def avatar_for_email(email, size=80): ...@@ -76,8 +78,6 @@ def avatar_for_email(email, size=80):
else: else:
# Fallback to standard method # Fallback to standard method
mail_hash = hashlib.md5(email.lower()).hexdigest()
url = "{0}avatar/{1}?{2}".format( url = "{0}avatar/{1}?{2}".format(
appsettings.AVATAR_URL_PREFIX, appsettings.AVATAR_URL_PREFIX,
mail_hash, mail_hash,
...@@ -111,7 +111,7 @@ def get_fallback_avatar(size): ...@@ -111,7 +111,7 @@ def get_fallback_avatar(size):
settings.STATIC_ROOT, settings.STATIC_ROOT,
'weblate-{0}.png'.format(size) 'weblate-{0}.png'.format(size)
) )
with open(fallback, 'r') as handle: with open(fallback, 'rb') as handle:
return handle.read() return handle.read()
......
...@@ -24,7 +24,7 @@ Simple mathematical captcha. ...@@ -24,7 +24,7 @@ Simple mathematical captcha.
from __future__ import unicode_literals from __future__ import unicode_literals
import ast import ast
import binascii from base64 import b64encode, b64decode
import hashlib import hashlib
import operator import operator
from random import randint, choice from random import randint, choice
...@@ -137,7 +137,8 @@ def checksum_question(question, timestamp): ...@@ -137,7 +137,8 @@ def checksum_question(question, timestamp):
''' '''
Returns checksum for a question. Returns checksum for a question.
''' '''
sha = hashlib.sha1(settings.SECRET_KEY + question + timestamp) challenge = ''.join((settings.SECRET_KEY, question, timestamp))
sha = hashlib.sha1(challenge.encode('utf-8'))
return sha.hexdigest() return sha.hexdigest()
...@@ -150,7 +151,7 @@ def hash_question(question, timestamp): ...@@ -150,7 +151,7 @@ def hash_question(question, timestamp):
return '{0}{1}{2}'.format( return '{0}{1}{2}'.format(
hexsha, hexsha,
timestamp, timestamp,
question.encode('base64') b64encode(question.encode('utf-8')).decode('ascii')
) )
...@@ -163,8 +164,8 @@ def unhash_question(question): ...@@ -163,8 +164,8 @@ def unhash_question(question):
hexsha = question[:40] hexsha = question[:40]
timestamp = question[40:50] timestamp = question[40:50]
try: try:
question = question[50:].decode('base64') question = b64decode(question[50:]).decode('utf-8')
except binascii.Error: except (TypeError, UnicodeError):
raise ValueError('Invalid encoding') raise ValueError('Invalid encoding')
if hexsha != checksum_question(question, timestamp): if hexsha != checksum_question(question, timestamp):
raise ValueError('Tampered question!') raise ValueError('Tampered question!')
......
...@@ -477,6 +477,10 @@ class Profile(models.Model): ...@@ -477,6 +477,10 @@ class Profile(models.Model):
secondary_languages = models.ManyToManyField( secondary_languages = models.ManyToManyField(
Language, Language,
verbose_name=_('Secondary languages'), verbose_name=_('Secondary languages'),
help_text=_(
'Choose languages you can understand, strings in those languages '
'will be shown in addition to the source string.'
),
related_name='secondary_profile_set', related_name='secondary_profile_set',
blank=True, blank=True,
) )
......
...@@ -50,7 +50,7 @@ def get_github_email(access_token): ...@@ -50,7 +50,7 @@ def get_github_email(access_token):
'token {0}'.format(access_token) 'token {0}'.format(access_token)
) )
handle = urlopen(request) handle = urlopen(request)
data = json.load(handle) data = json.loads(handle.read().decode('utf-8'))
email = None email = None
for entry in data: for entry in data:
# Skip not verified ones # Skip not verified ones
......
...@@ -234,6 +234,11 @@ DEFAULT_TRANSLATION_PROPAGATION = getvalue( ...@@ -234,6 +234,11 @@ DEFAULT_TRANSLATION_PROPAGATION = getvalue(
'DEFAULT_TRANSLATION_PROPAGATION', True 'DEFAULT_TRANSLATION_PROPAGATION', True
) )
# Billing
INVOICE_PATH = getvalue(
'INVOICE_PATH', ''
)
# Obsolete configs, needed for data migration # Obsolete configs, needed for data migration
GIT_ROOT = getvalue('GIT_ROOT', os.path.join(BASE_DIR, 'repos')) GIT_ROOT = getvalue('GIT_ROOT', os.path.join(BASE_DIR, 'repos'))
WHOOSH_INDEX = getvalue('WHOOSH_INDEX', os.path.join(BASE_DIR, 'whoosh-index')) WHOOSH_INDEX = getvalue('WHOOSH_INDEX', os.path.join(BASE_DIR, 'whoosh-index'))
...@@ -22,7 +22,7 @@ from __future__ import unicode_literals ...@@ -22,7 +22,7 @@ from __future__ import unicode_literals
from django.contrib import admin from django.contrib import admin
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from weblate.billing.models import Plan, Billing from weblate.billing.models import Plan, Billing, Invoice
class PlanAdmin(admin.ModelAdmin): class PlanAdmin(admin.ModelAdmin):
...@@ -36,14 +36,14 @@ class PlanAdmin(admin.ModelAdmin): ...@@ -36,14 +36,14 @@ class PlanAdmin(admin.ModelAdmin):
class BillingAdmin(admin.ModelAdmin): class BillingAdmin(admin.ModelAdmin):
list_display = ( list_display = (
'user', 'plan', 'trial', 'user', 'plan', 'state',
'list_projects', 'list_projects',
'count_changes_1m', 'count_changes_1q', 'count_changes_1y', 'count_changes_1m', 'count_changes_1q', 'count_changes_1y',
'count_repositories', 'count_strings', 'count_words', 'count_repositories', 'count_strings', 'count_words',
'count_languages', 'count_languages',
'in_limits', 'in_limits',
) )
list_filter = ('plan', 'trial') list_filter = ('plan', 'state')
search_fields = ('user__username', 'projects__name') search_fields = ('user__username', 'projects__name')
def list_projects(self, obj): def list_projects(self, obj):
...@@ -51,5 +51,18 @@ class BillingAdmin(admin.ModelAdmin): ...@@ -51,5 +51,18 @@ class BillingAdmin(admin.ModelAdmin):
list_projects.short_description = _('Projects') list_projects.short_description = _('Projects')
class InvoiceAdmin(admin.ModelAdmin):
list_display = (
'billing', 'start', 'end', 'payment', 'currency', 'ref'
)
list_filter = ('currency', 'billing')
search_fields = (
'billing__user__username', 'billing__projects__name',
'ref', 'note',
)
date_hierarchy = 'end'
admin.site.register(Plan, PlanAdmin) admin.site.register(Plan, PlanAdmin)
admin.site.register(Billing, BillingAdmin) admin.site.register(Billing, BillingAdmin)
admin.site.register(Invoice, InvoiceAdmin)
...@@ -18,7 +18,11 @@ ...@@ -18,7 +18,11 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
from datetime import timedelta
from django.core.management.base import BaseCommand from django.core.management.base import BaseCommand
from django.utils import timezone
from weblate.billing.models import Billing from weblate.billing.models import Billing
...@@ -38,3 +42,13 @@ class Command(BaseCommand): ...@@ -38,3 +42,13 @@ class Command(BaseCommand):
self.stdout.write( self.stdout.write(
' * {0}'.format(bill) ' * {0}'.format(bill)
) )
header = False
due_date = timezone.now() - timedelta(days=30)
for bill in Billing.objects.filter(state=Billing.STATE_ACTIVE):
if not bill.invoice_set.filter(end__gt=due_date).exists():
if not header:
self.stdout.write('Following billings are past due date:')
header = True
self.stdout.write(
' * {0}'.format(bill)
)
# -*- coding: utf-8 -*-
# Generated by Django 1.9.2 on 2016-02-10 12:53
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('billing', '0006_auto_20160106_1834'),
]
operations = [
migrations.CreateModel(
name='Invoice',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('start', models.DateField()),
('end', models.DateField()),
('payment', models.IntegerField()),
('currency', models.IntegerField(choices=[(0, 'EUR'), (1, 'BTC')], default=1)),
('ref', models.CharField(blank=True, max_length=50)),
('note', models.TextField(blank=True)),
('billing', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='billing.Billing')),
],
),
]
# -*- coding: utf-8 -*-
# Generated by Django 1.9.2 on 2016-02-10 12:59
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('billing', '0007_invoice'),
]
operations = [
migrations.AddField(
model_name='billing',
name='state',
field=models.IntegerField(choices=[(0, 'Active'), (1, 'Trial'), (2, 'Expired')], default=0),
),
]
# -*- coding: utf-8 -*-
# Generated by Django 1.9.2 on 2016-02-10 12:59
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('billing', '0008_billing_state'),
]
operations = [
migrations.RemoveField(
model_name='billing',
name='trial',
),
]
# -*- coding: utf-8 -*-
# Generated by Django 1.9.2 on 2016-02-10 14:07
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('billing', '0009_remove_billing_trial'),
]
operations = [
migrations.AlterField(
model_name='invoice',
name='currency',
field=models.IntegerField(choices=[(0, 'EUR'), (1, 'mBTC')], default=1),
),
migrations.AlterField(
model_name='invoice',
name='payment',
field=models.FloatField(),
),
]
# -*- coding: utf-8 -*-
# Generated by Django 1.9.2 on 2016-02-10 15:22
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('billing', '0010_auto_20160210_1407'),
]
operations = [
migrations.AlterField(
model_name='invoice',
name='currency',
field=models.IntegerField(choices=[(0, 'EUR'), (1, 'mBTC')], default=0),
),
]
...@@ -23,7 +23,9 @@ from __future__ import unicode_literals ...@@ -23,7 +23,9 @@ from __future__ import unicode_literals
from datetime import timedelta from datetime import timedelta
from django.db import models from django.db import models
from django.db.models import Q
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.core.exceptions import ValidationError
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.utils.encoding import python_2_unicode_compatible from django.utils.encoding import python_2_unicode_compatible
from django.utils import timezone from django.utils import timezone
...@@ -55,13 +57,27 @@ class Plan(models.Model): ...@@ -55,13 +57,27 @@ class Plan(models.Model):
@python_2_unicode_compatible @python_2_unicode_compatible
class Billing(models.Model): class Billing(models.Model):
STATE_ACTIVE = 0
STATE_TRIAL = 1
STATE_EXPIRED = 2
plan = models.ForeignKey(Plan) plan = models.ForeignKey(Plan)
user = models.OneToOneField(User) user = models.OneToOneField(User)
projects = models.ManyToManyField(Project, blank=True) projects = models.ManyToManyField(Project, blank=True)
trial = models.BooleanField(default=False) state = models.IntegerField(
choices=(
(STATE_ACTIVE, _('Active')),
(STATE_TRIAL, _('Trial')),
(STATE_EXPIRED, _('Expired')),
),
default=STATE_ACTIVE,
)
def __str__(self): def __str__(self):
return '{0} ({1})'.format(self.user, self.plan) return '{0}: {1} ({2})'.format(
', '.join([str(x) for x in self.projects.all()]),
self.user, self.plan
)
def count_changes(self, interval): def count_changes(self, interval):
return Change.objects.filter( return Change.objects.filter(
...@@ -127,3 +143,64 @@ class Billing(models.Model): ...@@ -127,3 +143,64 @@ class Billing(models.Model):
) )
) )
in_limits.boolean = True in_limits.boolean = True
@python_2_unicode_compatible
class Invoice(models.Model):
CURRENCY_EUR = 0
CURRENCY_BTC = 1
billing = models.ForeignKey(Billing)
start = models.DateField()
end = models.DateField()
payment = models.FloatField()
currency = models.IntegerField(
choices=(
(CURRENCY_EUR, 'EUR'),
(CURRENCY_BTC, 'mBTC'),
),
default=CURRENCY_EUR,
)
ref = models.CharField(blank=True, max_length=50)
note = models.TextField(blank=True)
class Meta(object):
ordering = ['billing', '-start']
def __str__(self):
return '{0} - {1}: {2}'.format(self.start, self.end, self.billing)
@property
def filename(self):
if self.ref:
return '{0}.pdf'.format(self.ref)
return None
def clean(self):
if self.end is None or self.start is None:
return
if self.end <= self.start:
raise ValidationError('Start has be to before end!')
if self.billing is None:
return
overlapping = Invoice.objects.filter(
(Q(start__lte=self.end) & Q(end__gte=self.end)) |
(Q(start__lte=self.start) & Q(end__gte=self.start))
).filter(
billing=self.billing
)
if self.pk:
overlapping = overlapping.exclude(
pk=self.pk
)
if overlapping.exists():
raise ValidationError(
'Overlapping invoices exist: {0}'.format(
', '.join([str(x) for x in overlapping])
)
)
...@@ -18,21 +18,45 @@ ...@@ -18,21 +18,45 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
from datetime import timedelta
import os.path
from six import StringIO from six import StringIO
from django.test import TestCase from django.test import TestCase
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.core.exceptions import ValidationError
from django.core.management import call_command from django.core.management import call_command
from django.core.urlresolvers import reverse
from django.utils import timezone
from weblate.billing.models import Plan, Billing from weblate.billing.models import Plan, Billing, Invoice
from weblate.trans.models import Project from weblate.trans.models import Project
from weblate.trans.tests import OverrideSettings
TEST_DATA = os.path.join(
os.path.dirname(os.path.abspath(__file__)),
'test-data'
)
class BillingTest(TestCase): class BillingTest(TestCase):
def setUp(self): def setUp(self):
self.user = User.objects.create(username='bill') self.user = User.objects.create_user(
username='bill',
password='kill',
email='noreply@example.net'
)
self.plan = Plan.objects.create(name='test', limit_projects=1, price=0) self.plan = Plan.objects.create(name='test', limit_projects=1, price=0)
self.billing = Billing.objects.create(user=self.user, plan=self.plan) self.billing = Billing.objects.create(user=self.user, plan=self.plan)
self.invoice = Invoice.objects.create(
billing=self.billing,
start=timezone.now().date() - timedelta(days=2),
end=timezone.now().date() + timedelta(days=2),
payment=10,
ref='00000',
)
self.projectnum = 0 self.projectnum = 0
def add_project(self): def add_project(self):
...@@ -55,8 +79,105 @@ class BillingTest(TestCase): ...@@ -55,8 +79,105 @@ class BillingTest(TestCase):
self.assertEqual(out.getvalue(), '') self.assertEqual(out.getvalue(), '')
self.add_project() self.add_project()
self.add_project() self.add_project()
out = StringIO()
call_command('billing_check', stdout=out) call_command('billing_check', stdout=out)
self.assertEqual( self.assertEqual(
out.getvalue(), out.getvalue(),
'Following billings are over limit:\n * bill (test)\n' 'Following billings are over limit:\n'
' * test0, test1: bill (test)\n'
)
self.invoice.delete()
out = StringIO()
call_command('billing_check', stdout=out)
self.assertEqual(
out.getvalue(),
'Following billings are over limit:\n'
' * test0, test1: bill (test)\n'
'Following billings are past due date:\n'
' * test0, test1: bill (test)\n'
)
def test_invoice_validation(self):
invoice = Invoice(
billing=self.billing,
start=self.invoice.start,
end=self.invoice.end,
payment=30
)
# Full overlap
self.assertRaises(
ValidationError,
invoice.clean
)
# Start overlap
invoice.start = self.invoice.end + timedelta(days=1)
self.assertRaises(
ValidationError,
invoice.clean
)
# Zero interval
invoice.end = self.invoice.end + timedelta(days=1)
self.assertRaises(
ValidationError,
invoice.clean
)
# Valid after existing
invoice.end = self.invoice.end + timedelta(days=2)
invoice.clean()
# End overlap
invoice.start = self.invoice.start - timedelta(days=4)
invoice.end = self.invoice.end
self.assertRaises(
ValidationError,
invoice.clean
)
# Valid before existing
invoice.end = self.invoice.start - timedelta(days=1)
invoice.clean()
# Validation of existing
self.invoice.clean()
@OverrideSettings(INVOICE_PATH=TEST_DATA)
def test_download(self):
# Unauthenticated
response = self.client.get(
reverse('invoice-download', kwargs={'pk': self.invoice.pk})
)
self.assertEqual(302, response.status_code)
# Not owner
User.objects.create_user(username='foo', password='bar')
self.client.login(username='foo', password='bar')
response = self.client.get(
reverse('invoice-download', kwargs={'pk': self.invoice.pk})
)
self.assertEqual(403, response.status_code)
# Owner
self.client.login(username='bill', password='kill')
response = self.client.get(
reverse('invoice-download', kwargs={'pk': self.invoice.pk})
)
self.assertContains(response, 'PDF-INVOICE')
# Invoice without file
invoice = Invoice.objects.create(
billing=self.billing,
start=timezone.now().date() - timedelta(days=2),
end=timezone.now().date() + timedelta(days=2),
payment=10,
)
response = self.client.get(
reverse('invoice-download', kwargs={'pk': invoice.pk})
)
self.assertEqual(404, response.status_code)
# Invoice with non existing file
invoice.ref = 'NON'
invoice.save()
response = self.client.get(
reverse('invoice-download', kwargs={'pk': invoice.pk})
) )
self.assertEqual(404, response.status_code)
...@@ -17,3 +17,45 @@ ...@@ -17,3 +17,45 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
import os.path
from django.contrib.auth.decorators import login_required
from django.core.exceptions import PermissionDenied
from django.shortcuts import get_object_or_404
from django.http import HttpResponse, Http404
from weblate import appsettings
from weblate.billing.models import Invoice
@login_required
def download_invoice(request, pk):
"""Download invoice PDF"""
invoice = get_object_or_404(Invoice, pk=pk)
if not invoice.ref:
raise Http404('No reference!')
if invoice.billing.user != request.user:
raise PermissionDenied('Not an owner!')
filename = invoice.filename
path = os.path.join(appsettings.INVOICE_PATH, filename)
if not os.path.exists(path):
raise Http404('File {0} does not exist!'.format(filename))
with open(path, 'rb') as handle:
data = handle.read()
response = HttpResponse(
data,
content_type='application/pdf'
)
response['Content-Disposition'] = 'attachment; filename={0}'.format(
filename
)
response['Content-Length'] = len(data)
return response
...@@ -25,6 +25,9 @@ ...@@ -25,6 +25,9 @@
<li><a data-toggle="tab" href="#auth">{% trans "Authentication" %}</a></li> <li><a data-toggle="tab" href="#auth">{% trans "Authentication" %}</a></li>
<li><a data-toggle="tab" href="#profile">{% trans "Profile" %}</a></li> <li><a data-toggle="tab" href="#profile">{% trans "Profile" %}</a></li>
<li><a data-toggle="tab" href="#licenses">{% trans "Licenses" %}</a></li> <li><a data-toggle="tab" href="#licenses">{% trans "Licenses" %}</a></li>
{% if user.billing %}
<li><a data-toggle="tab" href="#billing">{% trans "Billing" %}</a></li>
{% endif %}
</ul> </ul>
<div class="tab-content"> <div class="tab-content">
...@@ -334,6 +337,88 @@ ...@@ -334,6 +337,88 @@
</div> </div>
</div> </div>
{% if user.billing %}
{% with user.billing as billing %}
<div class="tab-pane" id="billing">
<div class="row">
<div class="col-lg-6">
<div class="panel panel-primary">
<div class="panel-heading"><h4 class="panel-title">{% trans "Billing plan" %}</h4></div>
<div class="panel-body">
{% with billing.plan as plan %}
<table class="table">
<tr><th>{% trans "Current plan" %}</th><td>{{ plan.name }}</td><td><a href="https://weblate.org/hosting/" class="btn btn-default btn-xs pull-right flip">{% trans "See other plans" %}</a></td></tr>
<tr><th>{% trans "Monthly price" %}</th><td>{{ plan.price }} EUR</td><td></td></tr>
<tr><th>{% trans "Yearly price" %}</th><td>{{ plan.yearly_price }} EUR</td><td></td></tr>
<tr><th>{% trans "Strings limit" %}</th>
{% with plan.limit_strings as max and plan.display_limit_strings as total and billing.count_strings as used %}
{% include "billing-used.html" %}
{% endwith %}
</tr>
<tr><th>{% trans "Languages limit" %}</th>
{% with plan.limit_languages as max and plan.display_limit_languages as total and billing.count_languages as used %}
{% include "billing-used.html" %}
{% endwith %}
</tr>
<tr><th>{% trans "Repositories limit" %}</th>
{% with plan.limit_repositories as max and plan.display_limit_repositories as total and billing.count_repositories as used %}
{% include "billing-used.html" %}
{% endwith %}
</tr>
<tr><th>{% trans "Projects limit" %}</th>
{% with plan.limit_projects as max and plan.display_limit_projects as total and billing.projects.count as used %}
{% include "billing-used.html" %}
{% endwith %}
</tr>
</table>
{% endwith %}
</div>
</div>
</div>
<div class="col-lg-6">
<div class="panel panel-primary">
<div class="panel-heading"><h4 class="panel-title">{% trans "Invoices" %}</h4></div>
<div class="panel-body">
<table class="table table-striped">
<thead>
<tr>
<th>{% trans "Invoice period" %}</th>
<th>{% trans "Invoice amount" %}</th>
<th>{% trans "Download invoice" %}</th>
</tr>
</thead>
<tbody>
{% for invoice in billing.invoice_set.all %}
<tr>
<td>{{ invoice.start|date:"SHORT_DATE_FORMAT" }} - {{ invoice.end|date:"SHORT_DATE_FORMAT" }}</td>
<td>{{ invoice.payment }} {{ invoice.get_currency_display }}</td>
<td>
{% if invoice.ref %}
<a href="{% url 'invoice-download' pk=invoice.pk %}">{{ invoice.filename }}</a>
{% else %}
{% trans "Not available" %}
{% endif %}
</td>
</tr>
{% empty %}
<tr><td colspan="3">{% trans "No invoices found!" %}</td/></tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
{% endwith %}
{% endif %}
</div> </div>
......
{% extends "admin/base_site.html" %} {% extends "admin/base_site.html" %}
{% load i18n %} {% load i18n %}
{% load translations %} {% load translations %}
{% load cycle from future %}
{% block title %}{% trans "Performance report" %}{% endblock %} {% block title %}{% trans "Performance report" %}{% endblock %}
...@@ -26,7 +25,7 @@ ...@@ -26,7 +25,7 @@
</thead> </thead>
<tbody> <tbody>
{% for check in checks %} {% for check in checks %}
<tr class="row{% cycle '1' '2' %} {{ check.4 }}"> <tr class="row{% cycle '1' '2' %}">
<td>{{ check.0 }}</td> <td>{{ check.0 }}</td>
<td>{{ check.3 }}</td> <td>{{ check.3 }}</td>
<td>{% admin_boolean_icon check.1 %}</td> <td>{% admin_boolean_icon check.1 %}</td>
......
{% extends "admin/base_site.html" %} {% extends "admin/base_site.html" %}
{% load i18n %} {% load i18n %}
{% load cycle from future %}
{% block title %}{% trans "SSH keys" %}{% endblock %} {% block title %}{% trans "SSH keys" %}{% endblock %}
......
{% load i18n %}
<td>
{% if total == 0 %}
{% blocktrans %}Used {{ used }}{% endblocktrans %}
{% else %}
{% blocktrans %}Used {{ used }} from {{ total }}{% endblocktrans %}
{% endif %}
</td>
<td>
<div class="progress">
{% if total == 0 %}
<div class="progress-bar progress-bar-success" role="progressbar" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100" style="width: 100%;"></div>
{% else %}
{% if used > max %}
<div class="progress-bar progress-bar-danger" role="progressbar" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100" style="width: 100%;"></div>
{% else %}
{% if used > total %}
<div class="progress-bar progress-bar-warning" role="progressbar" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100" style="width: 100%;"></div>
{% else %}
<div class="progress-bar progress-bar-success" role="progressbar" aria-valuenow="{{ used }}" aria-valuemin="0" aria-valuemax="{{ total }}" style="width: {% widthratio used total 100 %}%;"></div>
{% endif %}
{% endif %}
{% endif %}
</div>
</td>
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
<td></td> <td></td>
<td colspan="2" class="translatetext"> <td colspan="2" class="translatetext">
{% if not user.profile.hide_source_secondary or not item.secondary %} {% if not user.profile.hide_source_secondary or not item.secondary %}
{% format_translation item.unit.source item.unit.translation.subproject.project.source_language search_match=search_query num_plurals=unit.translation.language.nplurals %} {% format_translation item.unit.source item.unit.translation.subproject.project.source_language search_match=search_query num_plurals=item.unit.translation.language.nplurals %}
{% endif %} {% endif %}
{% if item.secondary %} {% if item.secondary %}
{% for unit in item.secondary %} {% for unit in item.secondary %}
......
...@@ -20,6 +20,8 @@ ...@@ -20,6 +20,8 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import io
from django.db import models, transaction from django.db import models, transaction
from django.db.utils import OperationalError from django.db.utils import OperationalError
from django.utils.encoding import python_2_unicode_compatible, force_text from django.utils.encoding import python_2_unicode_compatible, force_text
...@@ -305,9 +307,9 @@ class LanguageManager(models.Manager): ...@@ -305,9 +307,9 @@ class LanguageManager(models.Manager):
Checks database language definitions with supplied ones. Checks database language definitions with supplied ones.
""" """
errors = [] errors = []
with open(filename) as handle: with io.open(filename) as handle:
for line in handle: for line in handle:
line = line.strip().decode('utf-8') line = line.strip()
parts = [part.strip() for part in line.split(',')] parts = [part.strip() for part in line.split(',')]
if len(parts) != 3: if len(parts) != 3:
continue continue
......
This diff is collapsed.
...@@ -7,7 +7,7 @@ msgid "" ...@@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: weblate@lists.cihar.com\n" "Report-Msgid-Bugs-To: weblate@lists.cihar.com\n"
"POT-Creation-Date: 2016-02-01 17:29+0000\n" "POT-Creation-Date: 2016-02-16 10:38+0000\n"
"PO-Revision-Date: 2015-05-27 09:38+0200\n" "PO-Revision-Date: 2015-05-27 09:38+0200\n"
"Last-Translator: Automatically generated\n" "Last-Translator: Automatically generated\n"
"Language-Team: none\n" "Language-Team: none\n"
......
This diff is collapsed.
...@@ -7,7 +7,7 @@ msgid "" ...@@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: weblate@lists.cihar.com\n" "Report-Msgid-Bugs-To: weblate@lists.cihar.com\n"
"POT-Creation-Date: 2016-02-01 17:29+0000\n" "POT-Creation-Date: 2016-02-16 10:38+0000\n"
"PO-Revision-Date: 2015-10-13 07:39+0200\n" "PO-Revision-Date: 2015-10-13 07:39+0200\n"
"Last-Translator: Az oz <RIK4869@gmail.com>\n" "Last-Translator: Az oz <RIK4869@gmail.com>\n"
"Language-Team: Arabic <https://hosted.weblate.org/projects/weblate/" "Language-Team: Arabic <https://hosted.weblate.org/projects/weblate/"
......
This diff is collapsed.
...@@ -7,7 +7,7 @@ msgid "" ...@@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: weblate@lists.cihar.com\n" "Report-Msgid-Bugs-To: weblate@lists.cihar.com\n"
"POT-Creation-Date: 2016-02-01 17:29+0000\n" "POT-Creation-Date: 2016-02-16 10:38+0000\n"
"PO-Revision-Date: 2015-09-19 01:38+0200\n" "PO-Revision-Date: 2015-09-19 01:38+0200\n"
"Last-Translator: Enol Puente <enolp@softastur.org>\n" "Last-Translator: Enol Puente <enolp@softastur.org>\n"
"Language-Team: Asturian <https://hosted.weblate.org/projects/weblate/" "Language-Team: Asturian <https://hosted.weblate.org/projects/weblate/"
......
This diff is collapsed.
...@@ -7,7 +7,7 @@ msgid "" ...@@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: weblate@lists.cihar.com\n" "Report-Msgid-Bugs-To: weblate@lists.cihar.com\n"
"POT-Creation-Date: 2016-02-01 17:29+0000\n" "POT-Creation-Date: 2016-02-16 10:38+0000\n"
"PO-Revision-Date: 2014-11-23 23:22+0200\n" "PO-Revision-Date: 2014-11-23 23:22+0200\n"
"Last-Translator: Sevdimali İsa <sevdimaliisayev@mail.ru>\n" "Last-Translator: Sevdimali İsa <sevdimaliisayev@mail.ru>\n"
"Language-Team: Azerbaijani <https://hosted.weblate.org/projects/weblate/" "Language-Team: Azerbaijani <https://hosted.weblate.org/projects/weblate/"
......
This diff is collapsed.
...@@ -7,7 +7,7 @@ msgid "" ...@@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: weblate@lists.cihar.com\n" "Report-Msgid-Bugs-To: weblate@lists.cihar.com\n"
"POT-Creation-Date: 2016-02-01 17:29+0000\n" "POT-Creation-Date: 2016-02-16 10:38+0000\n"
"PO-Revision-Date: 2015-06-01 12:10+0200\n" "PO-Revision-Date: 2015-06-01 12:10+0200\n"
"Last-Translator: Viktar Palstsiuk <vipals@gmail.com>\n" "Last-Translator: Viktar Palstsiuk <vipals@gmail.com>\n"
"Language-Team: Belarusian <https://hosted.weblate.org/projects/weblate/" "Language-Team: Belarusian <https://hosted.weblate.org/projects/weblate/"
......
...@@ -7,7 +7,7 @@ msgid "" ...@@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: weblate@lists.cihar.com\n" "Report-Msgid-Bugs-To: weblate@lists.cihar.com\n"
"POT-Creation-Date: 2016-02-01 17:29+0000\n" "POT-Creation-Date: 2016-02-16 10:38+0000\n"
"PO-Revision-Date: 2015-01-06 17:27+0200\n" "PO-Revision-Date: 2015-01-06 17:27+0200\n"
"Last-Translator: Viktar Palstsiuk <vipals@gmail.com>\n" "Last-Translator: Viktar Palstsiuk <vipals@gmail.com>\n"
"Language-Team: Belarusian (latin) <https://hosted.weblate.org/projects/" "Language-Team: Belarusian (latin) <https://hosted.weblate.org/projects/"
......
This diff is collapsed.
...@@ -7,7 +7,7 @@ msgid "" ...@@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: weblate@lists.cihar.com\n" "Report-Msgid-Bugs-To: weblate@lists.cihar.com\n"
"POT-Creation-Date: 2016-02-01 17:29+0000\n" "POT-Creation-Date: 2016-02-16 10:38+0000\n"
"PO-Revision-Date: 2014-02-24 09:08+0200\n" "PO-Revision-Date: 2014-02-24 09:08+0200\n"
"Last-Translator: Fulup Jakez <fulup.jakez@gmail.com>\n" "Last-Translator: Fulup Jakez <fulup.jakez@gmail.com>\n"
"Language-Team: Breton <https://hosted.weblate.org/projects/weblate/" "Language-Team: Breton <https://hosted.weblate.org/projects/weblate/"
......
This diff is collapsed.
...@@ -7,7 +7,7 @@ msgid "" ...@@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: weblate@lists.cihar.com\n" "Report-Msgid-Bugs-To: weblate@lists.cihar.com\n"
"POT-Creation-Date: 2016-02-01 17:29+0000\n" "POT-Creation-Date: 2016-02-16 10:38+0000\n"
"PO-Revision-Date: 2015-06-08 07:43+0200\n" "PO-Revision-Date: 2015-06-08 07:43+0200\n"
"Last-Translator: josep constanti <jconstanti@yahoo.es>\n" "Last-Translator: josep constanti <jconstanti@yahoo.es>\n"
"Language-Team: Catalan <https://hosted.weblate.org/projects/weblate/" "Language-Team: Catalan <https://hosted.weblate.org/projects/weblate/"
......
This diff is collapsed.
...@@ -7,7 +7,7 @@ msgid "" ...@@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Weblate 1.2\n" "Project-Id-Version: Weblate 1.2\n"
"Report-Msgid-Bugs-To: weblate@lists.cihar.com\n" "Report-Msgid-Bugs-To: weblate@lists.cihar.com\n"
"POT-Creation-Date: 2016-02-01 17:29+0000\n" "POT-Creation-Date: 2016-02-16 10:38+0000\n"
"PO-Revision-Date: 2016-01-26 10:52+0000\n" "PO-Revision-Date: 2016-01-26 10:52+0000\n"
"Last-Translator: Michal Čihař <michal@cihar.com>\n" "Last-Translator: Michal Čihař <michal@cihar.com>\n"
"Language-Team: Czech <https://hosted.weblate.org/projects/weblate/javascript/" "Language-Team: Czech <https://hosted.weblate.org/projects/weblate/javascript/"
......
This diff is collapsed.
...@@ -7,7 +7,7 @@ msgid "" ...@@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Weblate 1.2\n" "Project-Id-Version: Weblate 1.2\n"
"Report-Msgid-Bugs-To: weblate@lists.cihar.com\n" "Report-Msgid-Bugs-To: weblate@lists.cihar.com\n"
"POT-Creation-Date: 2016-02-01 17:29+0000\n" "POT-Creation-Date: 2016-02-16 10:38+0000\n"
"PO-Revision-Date: 2016-01-26 11:49+0000\n" "PO-Revision-Date: 2016-01-26 11:49+0000\n"
"Last-Translator: jan madsen <jsm@janz.dk>\n" "Last-Translator: jan madsen <jsm@janz.dk>\n"
"Language-Team: Danish <https://hosted.weblate.org/projects/weblate/" "Language-Team: Danish <https://hosted.weblate.org/projects/weblate/"
......
This diff is collapsed.
...@@ -7,7 +7,7 @@ msgid "" ...@@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Weblate 1.2\n" "Project-Id-Version: Weblate 1.2\n"
"Report-Msgid-Bugs-To: weblate@lists.cihar.com\n" "Report-Msgid-Bugs-To: weblate@lists.cihar.com\n"
"POT-Creation-Date: 2016-02-01 17:29+0000\n" "POT-Creation-Date: 2016-02-16 10:38+0000\n"
"PO-Revision-Date: 2016-01-26 15:34+0000\n" "PO-Revision-Date: 2016-01-26 15:34+0000\n"
"Last-Translator: Philipp Wolfer <ph.wolfer@gmail.com>\n" "Last-Translator: Philipp Wolfer <ph.wolfer@gmail.com>\n"
"Language-Team: German <https://hosted.weblate.org/projects/weblate/" "Language-Team: German <https://hosted.weblate.org/projects/weblate/"
......
This diff is collapsed.
...@@ -8,7 +8,7 @@ msgid "" ...@@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-02-01 17:29+0000\n" "POT-Creation-Date: 2016-02-16 10:38+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
......
This diff is collapsed.
...@@ -7,7 +7,7 @@ msgid "" ...@@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Weblate 1.2\n" "Project-Id-Version: Weblate 1.2\n"
"Report-Msgid-Bugs-To: weblate@lists.cihar.com\n" "Report-Msgid-Bugs-To: weblate@lists.cihar.com\n"
"POT-Creation-Date: 2016-02-01 17:29+0000\n" "POT-Creation-Date: 2016-02-16 10:38+0000\n"
"PO-Revision-Date: 2016-01-26 13:07+0000\n" "PO-Revision-Date: 2016-01-26 13:07+0000\n"
"Last-Translator: Παναγιώτης Παπάζογλου <papaz_p@yahoo.com>\n" "Last-Translator: Παναγιώτης Παπάζογλου <papaz_p@yahoo.com>\n"
"Language-Team: Greek <https://hosted.weblate.org/projects/weblate/javascript/" "Language-Team: Greek <https://hosted.weblate.org/projects/weblate/javascript/"
......
This diff is collapsed.
...@@ -7,7 +7,7 @@ msgid "" ...@@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: weblate@lists.cihar.com\n" "Report-Msgid-Bugs-To: weblate@lists.cihar.com\n"
"POT-Creation-Date: 2016-02-01 17:29+0000\n" "POT-Creation-Date: 2016-02-16 10:38+0000\n"
"PO-Revision-Date: 2015-08-08 00:18+0200\n" "PO-Revision-Date: 2015-08-08 00:18+0200\n"
"Last-Translator: Isabell Long <isabell@issyl0.co.uk>\n" "Last-Translator: Isabell Long <isabell@issyl0.co.uk>\n"
"Language-Team: English (United Kingdom) <https://hosted.weblate.org/projects/" "Language-Team: English (United Kingdom) <https://hosted.weblate.org/projects/"
......
This diff is collapsed.
...@@ -7,7 +7,7 @@ msgid "" ...@@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: weblate@lists.cihar.com\n" "Report-Msgid-Bugs-To: weblate@lists.cihar.com\n"
"POT-Creation-Date: 2016-02-01 17:29+0000\n" "POT-Creation-Date: 2016-02-16 10:38+0000\n"
"PO-Revision-Date: 2016-01-14 15:11+0000\n" "PO-Revision-Date: 2016-01-14 15:11+0000\n"
"Last-Translator: Michal Čihař <michal@cihar.com>\n" "Last-Translator: Michal Čihař <michal@cihar.com>\n"
"Language-Team: Esperanto <https://hosted.weblate.org/projects/weblate/" "Language-Team: Esperanto <https://hosted.weblate.org/projects/weblate/"
......
This diff is collapsed.
...@@ -7,11 +7,11 @@ msgid "" ...@@ -7,11 +7,11 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Weblate website\n" "Project-Id-Version: Weblate website\n"
"Report-Msgid-Bugs-To: weblate@lists.cihar.com\n" "Report-Msgid-Bugs-To: weblate@lists.cihar.com\n"
"POT-Creation-Date: 2016-02-01 17:29+0000\n" "POT-Creation-Date: 2016-02-16 10:38+0000\n"
"PO-Revision-Date: 2016-02-01 19:31+0000\n" "PO-Revision-Date: 2016-02-01 19:31+0000\n"
"Last-Translator: Franco <fulanodetal.github1@openaliasbox.org>\n" "Last-Translator: Franco <fulanodetal.github1@openaliasbox.org>\n"
"Language-Team: Spanish " "Language-Team: Spanish <https://hosted.weblate.org/projects/weblate/"
"<https://hosted.weblate.org/projects/weblate/javascript/es/>\n" "javascript/es/>\n"
"Language: es\n" "Language: es\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
......
This diff is collapsed.
...@@ -7,7 +7,7 @@ msgid "" ...@@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Weblate 1.2\n" "Project-Id-Version: Weblate 1.2\n"
"Report-Msgid-Bugs-To: weblate@lists.cihar.com\n" "Report-Msgid-Bugs-To: weblate@lists.cihar.com\n"
"POT-Creation-Date: 2016-02-01 17:29+0000\n" "POT-Creation-Date: 2016-02-16 10:38+0000\n"
"PO-Revision-Date: 2014-07-04 13:31+0200\n" "PO-Revision-Date: 2014-07-04 13:31+0200\n"
"Last-Translator: arrapaa <h.heinanen@gmail.com>\n" "Last-Translator: arrapaa <h.heinanen@gmail.com>\n"
"Language-Team: Finnish <https://hosted.weblate.org/projects/weblate/" "Language-Team: Finnish <https://hosted.weblate.org/projects/weblate/"
......
This diff is collapsed.
...@@ -7,7 +7,7 @@ msgid "" ...@@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Weblate 1.2\n" "Project-Id-Version: Weblate 1.2\n"
"Report-Msgid-Bugs-To: weblate@lists.cihar.com\n" "Report-Msgid-Bugs-To: weblate@lists.cihar.com\n"
"POT-Creation-Date: 2016-02-01 17:29+0000\n" "POT-Creation-Date: 2016-02-16 10:38+0000\n"
"PO-Revision-Date: 2016-01-26 12:01+0000\n" "PO-Revision-Date: 2016-01-26 12:01+0000\n"
"Last-Translator: Ldm Public <ldmpub@gmail.com>\n" "Last-Translator: Ldm Public <ldmpub@gmail.com>\n"
"Language-Team: French <https://hosted.weblate.org/projects/weblate/" "Language-Team: French <https://hosted.weblate.org/projects/weblate/"
......
This diff is collapsed.
...@@ -7,7 +7,7 @@ msgid "" ...@@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: weblate@lists.cihar.com\n" "Report-Msgid-Bugs-To: weblate@lists.cihar.com\n"
"POT-Creation-Date: 2016-02-01 17:29+0000\n" "POT-Creation-Date: 2016-02-16 10:38+0000\n"
"PO-Revision-Date: 2014-12-11 12:48+0100\n" "PO-Revision-Date: 2014-12-11 12:48+0100\n"
"Last-Translator: Automatically generated\n" "Last-Translator: Automatically generated\n"
"Language-Team: none\n" "Language-Team: none\n"
......
This diff is collapsed.
...@@ -7,7 +7,7 @@ msgid "" ...@@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Weblate 1.2\n" "Project-Id-Version: Weblate 1.2\n"
"Report-Msgid-Bugs-To: weblate@lists.cihar.com\n" "Report-Msgid-Bugs-To: weblate@lists.cihar.com\n"
"POT-Creation-Date: 2016-02-01 17:29+0000\n" "POT-Creation-Date: 2016-02-16 10:38+0000\n"
"PO-Revision-Date: 2015-10-23 17:10+0200\n" "PO-Revision-Date: 2015-10-23 17:10+0200\n"
"Last-Translator: Xosé Calvo <xosecalvo@gmail.com>\n" "Last-Translator: Xosé Calvo <xosecalvo@gmail.com>\n"
"Language-Team: Galician <https://hosted.weblate.org/projects/weblate/" "Language-Team: Galician <https://hosted.weblate.org/projects/weblate/"
......
This diff is collapsed.
...@@ -7,8 +7,8 @@ msgid "" ...@@ -7,8 +7,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: weblate@lists.cihar.com\n" "Report-Msgid-Bugs-To: weblate@lists.cihar.com\n"
"POT-Creation-Date: 2016-02-01 17:29+0000\n" "POT-Creation-Date: 2016-02-16 10:38+0000\n"
"PO-Revision-Date: 2015-09-18 08:56+0200\n" "PO-Revision-Date: 2016-02-13 15:52+0000\n"
"Last-Translator: Green Lunar <genghiskhan@gmx.ca>\n" "Last-Translator: Green Lunar <genghiskhan@gmx.ca>\n"
"Language-Team: Hebrew <https://hosted.weblate.org/projects/weblate/" "Language-Team: Hebrew <https://hosted.weblate.org/projects/weblate/"
"javascript/he/>\n" "javascript/he/>\n"
...@@ -17,7 +17,7 @@ msgstr "" ...@@ -17,7 +17,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n" "Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 2.4-dev\n" "X-Generator: Weblate 2.5-dev\n"
#: weblate/static/loader-bootstrap.js:195 #: weblate/static/loader-bootstrap.js:195
msgid "Copy" msgid "Copy"
...@@ -25,12 +25,12 @@ msgstr "העתק" ...@@ -25,12 +25,12 @@ msgstr "העתק"
#: weblate/static/loader-bootstrap.js:200 #: weblate/static/loader-bootstrap.js:200
msgid "Copy and save" msgid "Copy and save"
msgstr "" msgstr "העתק ושמור"
#: weblate/static/loader-bootstrap.js:242 #: weblate/static/loader-bootstrap.js:242
#, javascript-format #, javascript-format
msgid "Alt+M then %s" msgid "Alt+M then %s"
msgstr "" msgstr "Alt+M ואז %s"
#: weblate/static/loader-bootstrap.js:261 #: weblate/static/loader-bootstrap.js:261
#, javascript-format #, javascript-format
...@@ -50,9 +50,9 @@ msgid "Error while loading page:" ...@@ -50,9 +50,9 @@ msgid "Error while loading page:"
msgstr "שגיאה בעת הטענת עמוד:" msgstr "שגיאה בעת הטענת עמוד:"
#: weblate/static/loader-bootstrap.js:680 #: weblate/static/loader-bootstrap.js:680
#, javascript-format #, fuzzy, javascript-format
msgid "Alt+%s" msgid "Alt+%s"
msgstr "" msgstr "Alt+%s"
#: weblate/static/loader-bootstrap.js:824 #: weblate/static/loader-bootstrap.js:824
msgid "There are some unsaved changes, are you sure you want to leave?" msgid "There are some unsaved changes, are you sure you want to leave?"
...@@ -278,7 +278,7 @@ msgstr "טהר" ...@@ -278,7 +278,7 @@ msgstr "טהר"
#: weblate/static/loader-bootstrap.js:919 #: weblate/static/loader-bootstrap.js:919
#, javascript-format #, javascript-format
msgid "Alt+I then %s" msgid "Alt+I then %s"
msgstr "" msgstr "Alt+I ואז %s"
#~ msgid "Strings with any failing checks" #~ msgid "Strings with any failing checks"
#~ msgstr "מחרוזות עם בדיקות כלשהן שנכשלו" #~ msgstr "מחרוזות עם בדיקות כלשהן שנכשלו"
......
This diff is collapsed.
...@@ -7,7 +7,7 @@ msgid "" ...@@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: weblate@lists.cihar.com\n" "Report-Msgid-Bugs-To: weblate@lists.cihar.com\n"
"POT-Creation-Date: 2016-02-01 17:29+0000\n" "POT-Creation-Date: 2016-02-16 10:38+0000\n"
"PO-Revision-Date: 2015-11-27 20:36+0000\n" "PO-Revision-Date: 2015-11-27 20:36+0000\n"
"Last-Translator: János Néhrer <iiamnot@gmail.com>\n" "Last-Translator: János Néhrer <iiamnot@gmail.com>\n"
"Language-Team: Hungarian <https://hosted.weblate.org/projects/weblate/" "Language-Team: Hungarian <https://hosted.weblate.org/projects/weblate/"
......
This diff is collapsed.
...@@ -7,7 +7,7 @@ msgid "" ...@@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: weblate@lists.cihar.com\n" "Report-Msgid-Bugs-To: weblate@lists.cihar.com\n"
"POT-Creation-Date: 2016-02-01 17:29+0000\n" "POT-Creation-Date: 2016-02-16 10:38+0000\n"
"PO-Revision-Date: 2016-01-14 15:11+0000\n" "PO-Revision-Date: 2016-01-14 15:11+0000\n"
"Last-Translator: Michal Čihař <michal@cihar.com>\n" "Last-Translator: Michal Čihař <michal@cihar.com>\n"
"Language-Team: Armenian <https://hosted.weblate.org/projects/weblate/" "Language-Team: Armenian <https://hosted.weblate.org/projects/weblate/"
......
This diff is collapsed.
...@@ -7,7 +7,7 @@ msgid "" ...@@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Weblate 1.2\n" "Project-Id-Version: Weblate 1.2\n"
"Report-Msgid-Bugs-To: weblate@lists.cihar.com\n" "Report-Msgid-Bugs-To: weblate@lists.cihar.com\n"
"POT-Creation-Date: 2016-02-01 17:29+0000\n" "POT-Creation-Date: 2016-02-16 10:38+0000\n"
"PO-Revision-Date: 2014-02-12 00:50+0200\n" "PO-Revision-Date: 2014-02-12 00:50+0200\n"
"Last-Translator: Hascore Eleven <hascore@gmail.com>\n" "Last-Translator: Hascore Eleven <hascore@gmail.com>\n"
"Language-Team: Indonesian <http://hosted.weblate.org/projects/weblate/" "Language-Team: Indonesian <http://hosted.weblate.org/projects/weblate/"
......
This diff is collapsed.
...@@ -7,7 +7,7 @@ msgid "" ...@@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: weblate@lists.cihar.com\n" "Report-Msgid-Bugs-To: weblate@lists.cihar.com\n"
"POT-Creation-Date: 2016-02-01 17:29+0000\n" "POT-Creation-Date: 2016-02-16 10:38+0000\n"
"PO-Revision-Date: 2015-07-15 19:48+0200\n" "PO-Revision-Date: 2015-07-15 19:48+0200\n"
"Last-Translator: Massimiliano Caniparoli <massic80@gmail.com>\n" "Last-Translator: Massimiliano Caniparoli <massic80@gmail.com>\n"
"Language-Team: Italian <https://hosted.weblate.org/projects/weblate/" "Language-Team: Italian <https://hosted.weblate.org/projects/weblate/"
......
This diff is collapsed.
...@@ -6,7 +6,7 @@ msgid "" ...@@ -6,7 +6,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: weblate-website-ja\n" "Project-Id-Version: weblate-website-ja\n"
"Report-Msgid-Bugs-To: weblate@lists.cihar.com\n" "Report-Msgid-Bugs-To: weblate@lists.cihar.com\n"
"POT-Creation-Date: 2016-02-01 17:29+0000\n" "POT-Creation-Date: 2016-02-16 10:38+0000\n"
"PO-Revision-Date: 2015-12-01 07:53+0900\n" "PO-Revision-Date: 2015-12-01 07:53+0900\n"
"Last-Translator: Yasuhiko Kamata <belphegor@belbel.or.jp>\n" "Last-Translator: Yasuhiko Kamata <belphegor@belbel.or.jp>\n"
"Language-Team: Japanese <https://hosted.weblate.org/projects/weblate/" "Language-Team: Japanese <https://hosted.weblate.org/projects/weblate/"
......
This diff is collapsed.
...@@ -7,7 +7,7 @@ msgid "" ...@@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: weblate@lists.cihar.com\n" "Report-Msgid-Bugs-To: weblate@lists.cihar.com\n"
"POT-Creation-Date: 2016-02-01 17:29+0000\n" "POT-Creation-Date: 2016-02-16 10:38+0000\n"
"PO-Revision-Date: 2014-11-15 10:53+0200\n" "PO-Revision-Date: 2014-11-15 10:53+0200\n"
"Last-Translator: youngminz <youngminz.kr@gmail.com>\n" "Last-Translator: youngminz <youngminz.kr@gmail.com>\n"
"Language-Team: Korean <https://hosted.weblate.org/projects/weblate/" "Language-Team: Korean <https://hosted.weblate.org/projects/weblate/"
......
This diff is collapsed.
...@@ -7,7 +7,7 @@ msgid "" ...@@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: weblate@lists.cihar.com\n" "Report-Msgid-Bugs-To: weblate@lists.cihar.com\n"
"POT-Creation-Date: 2016-02-01 17:29+0000\n" "POT-Creation-Date: 2016-02-16 10:38+0000\n"
"PO-Revision-Date: 2014-04-16 18:11+0200\n" "PO-Revision-Date: 2014-04-16 18:11+0200\n"
"Last-Translator: Purodha Blissenbach <publi@web.de>\n" "Last-Translator: Purodha Blissenbach <publi@web.de>\n"
"Language-Team: Colognian <https://hosted.weblate.org/projects/weblate/" "Language-Team: Colognian <https://hosted.weblate.org/projects/weblate/"
......
This diff is collapsed.
...@@ -7,7 +7,7 @@ msgid "" ...@@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: weblate@lists.cihar.com\n" "Report-Msgid-Bugs-To: weblate@lists.cihar.com\n"
"POT-Creation-Date: 2016-02-01 17:29+0000\n" "POT-Creation-Date: 2016-02-16 10:38+0000\n"
"PO-Revision-Date: 2015-06-04 20:46+0200\n" "PO-Revision-Date: 2015-06-04 20:46+0200\n"
"Last-Translator: Kurt Eilertsen <kurt@kheds.com>\n" "Last-Translator: Kurt Eilertsen <kurt@kheds.com>\n"
"Language-Team: Norwegian Bokmål <https://hosted.weblate.org/projects/weblate/" "Language-Team: Norwegian Bokmål <https://hosted.weblate.org/projects/weblate/"
......
This diff is collapsed.
...@@ -7,7 +7,7 @@ msgid "" ...@@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Weblate 1.2\n" "Project-Id-Version: Weblate 1.2\n"
"Report-Msgid-Bugs-To: weblate@lists.cihar.com\n" "Report-Msgid-Bugs-To: weblate@lists.cihar.com\n"
"POT-Creation-Date: 2016-02-01 17:29+0000\n" "POT-Creation-Date: 2016-02-16 10:38+0000\n"
"PO-Revision-Date: 2016-01-26 12:08+0000\n" "PO-Revision-Date: 2016-01-26 12:08+0000\n"
"Last-Translator: Dieter Adriaenssens <dieter.adriaenssens@gmail.com>\n" "Last-Translator: Dieter Adriaenssens <dieter.adriaenssens@gmail.com>\n"
"Language-Team: Dutch <https://hosted.weblate.org/projects/weblate/javascript/" "Language-Team: Dutch <https://hosted.weblate.org/projects/weblate/javascript/"
......
This diff is collapsed.
...@@ -7,7 +7,7 @@ msgid "" ...@@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Weblate 1.2\n" "Project-Id-Version: Weblate 1.2\n"
"Report-Msgid-Bugs-To: weblate@lists.cihar.com\n" "Report-Msgid-Bugs-To: weblate@lists.cihar.com\n"
"POT-Creation-Date: 2016-02-01 17:29+0000\n" "POT-Creation-Date: 2016-02-16 10:38+0000\n"
"PO-Revision-Date: 2015-09-14 23:40+0200\n" "PO-Revision-Date: 2015-09-14 23:40+0200\n"
"Last-Translator: agilob <weblate@agilob.net>\n" "Last-Translator: agilob <weblate@agilob.net>\n"
"Language-Team: Polish <https://hosted.weblate.org/projects/weblate/" "Language-Team: Polish <https://hosted.weblate.org/projects/weblate/"
......
This diff is collapsed.
...@@ -7,7 +7,7 @@ msgid "" ...@@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Weblate 1.2\n" "Project-Id-Version: Weblate 1.2\n"
"Report-Msgid-Bugs-To: weblate@lists.cihar.com\n" "Report-Msgid-Bugs-To: weblate@lists.cihar.com\n"
"POT-Creation-Date: 2016-02-01 17:29+0000\n" "POT-Creation-Date: 2016-02-16 10:38+0000\n"
"PO-Revision-Date: 2015-04-02 05:36+0200\n" "PO-Revision-Date: 2015-04-02 05:36+0200\n"
"Last-Translator: David Ludovino <david.ludovino@gmail.com>\n" "Last-Translator: David Ludovino <david.ludovino@gmail.com>\n"
"Language-Team: Portuguese <https://hosted.weblate.org/projects/weblate/" "Language-Team: Portuguese <https://hosted.weblate.org/projects/weblate/"
......
This diff is collapsed.
...@@ -7,7 +7,7 @@ msgid "" ...@@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Weblate 1.2\n" "Project-Id-Version: Weblate 1.2\n"
"Report-Msgid-Bugs-To: weblate@lists.cihar.com\n" "Report-Msgid-Bugs-To: weblate@lists.cihar.com\n"
"POT-Creation-Date: 2016-02-01 17:29+0000\n" "POT-Creation-Date: 2016-02-16 10:38+0000\n"
"PO-Revision-Date: 2016-01-26 14:39+0000\n" "PO-Revision-Date: 2016-01-26 14:39+0000\n"
"Last-Translator: Luiz Fernando Ranghetti <elchevive@opensuse.org>\n" "Last-Translator: Luiz Fernando Ranghetti <elchevive@opensuse.org>\n"
"Language-Team: Portuguese (Brazil) <https://hosted.weblate.org/projects/" "Language-Team: Portuguese (Brazil) <https://hosted.weblate.org/projects/"
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment