# Path: patchwork/parser.py
# def hash_patch(str):
#     # normalise spaces
#     str = str.replace('\r', '')
#     str = str.strip() + '\n'
# 
#     prefixes = ['-', '+', ' ']
#     hash = hashlib.sha1()
# 
#     for line in str.split('\n'):
# 
#         if len(line) <= 0:
#             continue
# 
#         hunk_match = _hunk_re.match(line)
#         filename_match = _filename_re.match(line)
# 
#         if filename_match:
#             # normalise -p1 top-directories
#             if filename_match.group(1) == '---':
#                 filename = 'a/'
#             else:
#                 filename = 'b/'
#             filename += '/'.join(filename_match.group(2).split('/')[1:])
# 
#             line = filename_match.group(1) + ' ' + filename
# 
#         elif hunk_match:
#             # remove line numbers, but leave line counts
#             def fn(x):
#                 if not x:
#                     return 1
#                 return int(x)
#             line_nos = list(map(fn, hunk_match.groups()))
#             line = '@@ -%d +%d @@' % tuple(line_nos)
# 
#         elif line[0] in prefixes:
#             # if we have a +, - or context line, leave as-is
#             pass
# 
#         else:
#             # other lines are ignored
#             continue
# 
#         hash.update((line + '\n').encode('utf-8'))
# 
#     return hash
# 
# def extract_tags(content, tags):
#     counts = Counter()
# 
#     for tag in tags:
#         regex = re.compile(tag.pattern, re.MULTILINE | re.IGNORECASE)
#         counts[tag] = len(regex.findall(content))
# 
#     return counts


from collections import Counter, OrderedDict
from django.conf import settings
from django.contrib import auth
from django.contrib.auth.models import User
from django.contrib.sites.models import Site
from django.core.urlresolvers import reverse
from django.db import models
from django.db.models import Q
from django.utils.encoding import python_2_unicode_compatible
from django.utils.functional import cached_property
from django.utils.six.moves import filter
from patchwork.fields import HashField
from patchwork.parser import hash_patch, extract_tags
import datetime
import jsonfield
import random
import re
import patchwork.threadlocalrequest as threadlocalrequest
import django.dispatch
                                on_delete=models.CASCADE)
    primary_project = models.ForeignKey(Project, null=True, blank=True,
                                        on_delete=models.CASCADE)
    maintainer_projects = models.ManyToManyField(Project,
             related_name='maintainer_project', blank=True)
    send_email = models.BooleanField(default=False,
             help_text='Selecting this option allows patchwork to send '
             'email on your behalf')
    patches_per_page = models.PositiveIntegerField(
            default=100, null=False, blank=False,
            help_text='Number of patches to display per page')

    def name(self):
        return user_name(self.user)

    def contributor_projects(self):
        submitters = Person.objects.filter(user=self.user)
        return Project.objects.filter(id__in=Patch.objects.filter(
            submitter__in=submitters)
            .values('project_id').query)

    def sync_person(self):
        pass

    def n_todo(self):
        return self.todo_patches().count() + self.todo_series().count()

    def todo_patches(self, project=None):

        # filter on project, if necessary

# Path: patchwork/parser.py
# def hash_patch(str):
#     # normalise spaces
#     str = str.replace('\r', '')
#     str = str.strip() + '\n'
# 
#     prefixes = ['-', '+', ' ']
#     hash = hashlib.sha1()
# 
#     for line in str.split('\n'):
# 
#         if len(line) <= 0:
#             continue
# 
#         hunk_match = _hunk_re.match(line)
#         filename_match = _filename_re.match(line)
# 
#         if filename_match:
#             # normalise -p1 top-directories
#             if filename_match.group(1) == '---':
#                 filename = 'a/'
#             else:
#                 filename = 'b/'
#             filename += '/'.join(filename_match.group(2).split('/')[1:])
# 
#             line = filename_match.group(1) + ' ' + filename
# 
#         elif hunk_match:
#             # remove line numbers, but leave line counts
#             def fn(x):
#                 if not x:
#                     return 1
#                 return int(x)
#             line_nos = list(map(fn, hunk_match.groups()))
#             line = '@@ -%d +%d @@' % tuple(line_nos)
# 
#         elif line[0] in prefixes:
#             # if we have a +, - or context line, leave as-is
#             pass
# 
#         else:
#             # other lines are ignored
#             continue
# 
#         hash.update((line + '\n').encode('utf-8'))
# 
#     return hash
# 
# def extract_tags(content, tags):
#     counts = Counter()
# 
#     for tag in tags:
#         regex = re.compile(tag.pattern, re.MULTILINE | re.IGNORECASE)
#         counts[tag] = len(regex.findall(content))
# 
#     return counts


# Path: patchwork/models.py
from collections import Counter, OrderedDict
from django.conf import settings
from django.contrib import auth
from django.contrib.auth.models import User
from django.contrib.sites.models import Site
from django.core.urlresolvers import reverse
from django.db import models
from django.db.models import Q
from django.utils.encoding import python_2_unicode_compatible
from django.utils.functional import cached_property
from django.utils.six.moves import filter
from patchwork.fields import HashField
from patchwork.parser import hash_patch, extract_tags
import datetime
import jsonfield
import random
import re
import patchwork.threadlocalrequest as threadlocalrequest
import django.dispatch

                                on_delete=models.CASCADE)
    primary_project = models.ForeignKey(Project, null=True, blank=True,
                                        on_delete=models.CASCADE)
    maintainer_projects = models.ManyToManyField(Project,
             related_name='maintainer_project', blank=True)
    send_email = models.BooleanField(default=False,
             help_text='Selecting this option allows patchwork to send '
             'email on your behalf')
    patches_per_page = models.PositiveIntegerField(
            default=100, null=False, blank=False,
            help_text='Number of patches to display per page')

    def name(self):
        return user_name(self.user)

    def contributor_projects(self):
        submitters = Person.objects.filter(user=self.user)
        return Project.objects.filter(id__in=Patch.objects.filter(
            submitter__in=submitters)
            .values('project_id').query)

    def sync_person(self):
        pass

    def n_todo(self):
        return self.todo_patches().count() + self.todo_series().count()

    def todo_patches(self, project=None):

        # filter on project, if necessary

        if project: