internlm/SWE-Fixer-Train-110K huggingface dataset:
Repository: interlegis/sapl

Issue:
Expediente Diversos da Sessão Plenária sem informação mas não permite ser excluído
Apagados todos os dados de uma sessão plenária ainda assim não é permitido excluí-la, pois alega referenciamento ao Expediente Diversos onde foram apagados todos os dados e salvo.
Sugestão: incluir botão de exclusão do Expediente Diversos.








Discussion:

Resolving patch:
diff --git a/sapl/sessao/views.py b/sapl/sessao/views.py
--- a/sapl/sessao/views.py
+++ b/sapl/sessao/views.py
@@ -1448,6 +1448,11 @@ def post(self, request, *args, **kwargs):
         self.object = self.get_object()
         form = ExpedienteForm(request.POST)
 
+        if 'apagar-expediente' in request.POST:
+            ExpedienteSessao.objects.filter(
+                sessao_plenaria_id=self.object.id).delete()
+            return self.form_valid(form)
+
         if form.is_valid():
             list_tipo = request.POST.getlist('tipo')
             list_conteudo = request.POST.getlist('conteudo')


Test patch:
Repository: interlegis/sapl

Issue:
Relatória de matéria [composição de comissão]
Ao adicionar a relatória a uma matéria legislativa, a composição de uma comissão não retorna a mais recente composição da comissão (ordenada em ordem por período de composição).


Discussion:

Resolving patch:
diff --git a/sapl/materia/views.py b/sapl/materia/views.py
--- a/sapl/materia/views.py
+++ b/sapl/materia/views.py
@@ -937,7 +937,8 @@ def get_context_data(self, **kwargs):
             except ObjectDoesNotExist:
                 pass
             else:
-                composicao = comissao.composicao_set.last()
+                composicao = comissao.composicao_set.order_by(
+                    '-periodo__data_inicio').first()
                 participacao = Participacao.objects.filter(
                     composicao=composicao)
 


Test patch:
Repository: interlegis/sapl

Issue:
Erro  ao protocolar materia legislativa
Ao protocolar uma matéria legislativa no sapl da oficina (cursosapl01.interlegis.leg.br), ocorreu o seguinte erro:
![image](https://user-images.githubusercontent.com/30807716/40398699-d89d7b5c-5e0f-11e8-99c6-779ee960ad5b.png)

grato
Adal


Discussion:

Resolving patch:
diff --git a/sapl/protocoloadm/views.py b/sapl/protocoloadm/views.py
--- a/sapl/protocoloadm/views.py
+++ b/sapl/protocoloadm/views.py
@@ -451,10 +451,11 @@ def form_valid(self, form):
 
         if not protocolo.numero:
             protocolo.numero = (numero['numero__max'] + 1) if numero['numero__max'] else 1
-        if protocolo.numero < (numero['numero__max'] + 1):
-            msg = _('Número de protocolo deve ser maior que {}').format(numero['numero__max'])
-            messages.add_message(self.request, messages.ERROR, msg)
-            return self.render_to_response(self.get_context_data())
+        if numero['numero__max']:
+            if protocolo.numero < (numero['numero__max'] + 1):
+                msg = _('Número de protocolo deve ser maior que {}').format(numero['numero__max'])
+                messages.add_message(self.request, messages.ERROR, msg)
+                return self.render_to_response(self.get_context_data())
         protocolo.ano = timezone.now().year
         protocolo.data = timezone.now().date()
         protocolo.hora = timezone.now().time()


Test patch:
Repository: interlegis/sapl

Issue:
Erro na inclusão de Nome de Comissão acima de 50 caracteres
Ao inserir um Nome de Comissão acima de 50 caracteres aparece a mensagem Error 500. Mas na edição o sistema aceita.
grato


Discussion:
Bom dia,
Foi estipulado anteriormente que o nome deveria ser de até 50 caracteres. Caso necessário os nomes podem ser abreviados e explicados na finalidade da comissão. Iremos restringir para a edição o número de caracteres também.
Positivo! Obrigado

Resolving patch:
diff --git a/sapl/comissoes/forms.py b/sapl/comissoes/forms.py
--- a/sapl/comissoes/forms.py
+++ b/sapl/comissoes/forms.py
@@ -241,6 +241,9 @@ def clean(self):
         if not self.is_valid():
             return self.cleaned_data
 
+        if len(self.cleaned_data['nome']) > 50:
+            msg = _('Nome da Comissão deve ter no máximo 50 caracteres.')
+            raise ValidationError(msg)
         if self.cleaned_data['data_extincao']:
             if (self.cleaned_data['data_extincao'] <
                     self.cleaned_data['data_criacao']):


Test patch:
Repository: interlegis/sapl

Issue:
Impossibilidade de colar tabela do Word em Expediente Diversos e gerar o PDF



Discussion:

Resolving patch:
diff --git a/sapl/relatorios/views.py b/sapl/relatorios/views.py
--- a/sapl/relatorios/views.py
+++ b/sapl/relatorios/views.py
@@ -795,7 +795,8 @@ def relatorio_sessao_plenaria(request, pk):
 
     for idx in range(len(lst_expedientes)):
         txt_expedientes = lst_expedientes[idx]['txt_expediente']
-        txt_expedientes = TrocaTag(txt_expedientes, '<table', 'table>', 6, 6, 'expedientes')
+        txt_expedientes = TrocaTag(txt_expedientes, '<table', 'table>', 6, 6,
+        'expedientes', '</para><blockTable style = "', 'blockTable><para>')
         lst_expedientes[idx]['txt_expediente'] = txt_expedientes
 
     pdf = pdf_sessao_plenaria_gerar.principal(
diff --git a/sapl/utils.py b/sapl/utils.py
--- a/sapl/utils.py
+++ b/sapl/utils.py
@@ -688,7 +688,7 @@ def ExtraiTag(texto, posicao):
             return i + 1
 
 
-def TrocaTag(texto, startTag, endTag, sizeStart, sizeEnd, styleName):
+def TrocaTag(texto, startTag, endTag, sizeStart, sizeEnd, styleName, subinitiTag, subendTag):
     textoSaida = ''
     insideTag = 0
     i = 0
@@ -697,16 +697,19 @@ def TrocaTag(texto, startTag, endTag, sizeStart, sizeEnd, styleName):
     if '<tbody>' in texto:
         texto = texto.replace('<tbody>', '')
         texto = texto.replace('</tbody>', '')
+    if '<p>' in texto:
+        texto = texto.replace('<p>', '')
+        texto = texto.replace('</p>', '')
     while (i < len(texto)):
         shard = texto[i:i + sizeStart]
         if (shard == startTag):
             i = ExtraiTag(texto, i)
-            textoSaida += '</para><blockTable style = "' + styleName + '">'
+            textoSaida += subinitiTag + styleName + '">'
             insideTag = 1
         else:
             if (insideTag == 1):
                 if (texto[i:i + sizeEnd] == endTag):
-                    textoSaida += 'blockTable><para>'
+                    textoSaida += subendTag
                     insideTag = 0
                     i += sizeEnd
                 else:
@@ -735,4 +738,4 @@ def RemoveTag(texto):
     return textoSaida
 
 def remover_acentos(string):
-     return unicodedata.normalize('NFKD', string).encode('ASCII', 'ignore').decode()
\ No newline at end of file
+     return unicodedata.normalize('NFKD', string).encode('ASCII', 'ignore').decode()


Test patch:
Repository: interlegis/sapl

Issue:
Data de filiação é preenchida automaticamente ao editar filiação partidária
olá. Há um problema na tela de Filiação Partidária. Ao se editar uma filiação partidária já existente, o campo Data de Filiação é automaticamente alterado para a data atual, substituindo a data digitada anteriormente.


Discussion:
Bom dia,
Tentei replicar o erro localmente com diversos parlamentares e não consegui. 
Você poderia mandar capturas de tela mostrando isso ocorrer? O ideal seria uma captura da tela da listagem das filiações (antes da edição) e uma captura da tela de edição.
Se possível mandar também os links das telas em que o erro for detectado.
Muito obrigado.
Usando o firefox, editando a filiação, por vezes traz a data atual e por vezes traz a data gravada. Se limpo o cache do navegador, na primeira vez que edito, traz a data gravada, na segunda já é trazida a data atual.
@DtiLegBG aqui no meu firefox não consegui replicar também não, fui nas opções de Network do firefox e desativei o cache e ativei (fiz o teste com os dois estados), em todas ele trazia a data gravada, e em casos de novas filiações ele trás em branco. Será que é algum auto complete do navegador? Tem alguma suspeita?
Testei agora com o Chrome,  mesmo limpando o cache, e traz a data atual. Posso gravar um vídeo se ajudar. Nem imagino o que pode ser . SAPL hospedado local.
vou averiguar se tem algum javascript de preenchimento de data mas tá muito estranho.

Resolving patch:
diff --git a/sapl/parlamentares/forms.py b/sapl/parlamentares/forms.py
--- a/sapl/parlamentares/forms.py
+++ b/sapl/parlamentares/forms.py
@@ -261,6 +261,8 @@ class Meta:
         fields = ['partido',
                   'data',
                   'data_desfiliacao']
+        widgets = {'data': forms.DateInput(attrs={'autocomplete': 'off'}),
+                   'data_desfiliacao': forms.DateInput(attrs={'autocomplete': 'off'})}
 
     def clean(self):
         super(FiliacaoForm, self).clean()


Test patch:
Repository: interlegis/sapl

Issue:
Matéria Legislativa: campo autor traz todos os autores no formulário

Máteria Legislativa
Ao editar uma matéria legislativa esta aparecendo um campo de autor

![image](https://user-images.githubusercontent.com/13314947/41099842-1a29402e-6a36-11e8-81d9-17fb50080f85.png)



Discussion:

Resolving patch:
diff --git a/sapl/materia/forms.py b/sapl/materia/forms.py
--- a/sapl/materia/forms.py
+++ b/sapl/materia/forms.py
@@ -162,6 +162,11 @@ def clean(self):
 
 class MateriaLegislativaForm(ModelForm):
 
+    tipo_autor = ModelChoiceField(label=_('Tipo Autor'),
+                                  required=False,
+                                  queryset=TipoAutor.objects.all(),
+                                  empty_label=_('------'), )
+
     autor = forms.ModelChoiceField(required=False,
                                    empty_label='------',
                                    queryset=Autor.objects.all()
@@ -172,6 +177,15 @@ class Meta:
         exclude = ['texto_articulado', 'autores', 'proposicao',
                    'anexadas', 'data_ultima_atualizacao']
 
+    def __init__(self, *args, **kwargs):
+        super(MateriaLegislativaForm, self).__init__(*args, **kwargs)
+
+        if self.instance and self.instance.pk:
+            self.fields['tipo_autor'] = forms.CharField(required=False,
+                                                        widget=forms.TextInput(attrs={'disabled': 'disabled'}))
+            self.fields['autor'] = forms.CharField(required=False,
+                                                   widget=forms.TextInput(attrs={'disabled': 'disabled'}))
+
     def clean(self):
         super(MateriaLegislativaForm, self).clean()
 
@@ -219,12 +233,17 @@ def clean(self):
         return cleaned_data
 
     def save(self, commit=False):
+        if not self.instance.pk:
+            primeiro_autor = True
+        else:
+            primeiro_autor = False
+            
         materia = super(MateriaLegislativaForm, self).save(commit)
         materia.save()
 
         if self.cleaned_data['autor']:
             autoria = Autoria()
-            autoria.primeiro_autor = True
+            autoria.primeiro_autor = primeiro_autor
             autoria.materia = materia
             autoria.autor = self.cleaned_data['autor']
             autoria.save()


Test patch:
Repository: interlegis/sapl

Issue:
Normas Jurídicas
Está sendo possível criar no sistema normas do mesmo tipo, com a mesma data e o mesmo ano.

Se esse for um comportamento que vai ser permitido, para os relacionamentos terão que ser listadas as normas correspondentes aos dados informados para ser possível escolher a qual norma se deseja criar o vínculo.
@andreagudo @LeandroRoberto  @marciomazza 




Discussion:
Caro Rogério, você está se referindo a normas com números diferentes? Nesse caso, não vejo problema de terem sido criados com o mesmo tipo e data, correto?

Prezado, trata-se de Resoluçoes de mesmo numero e ano, mas com conteudo diferente, pois foram editadas por orgaos diferentes
Tipo, Número, data, ano  iguais.

Resolving patch:
diff --git a/sapl/norma/forms.py b/sapl/norma/forms.py
--- a/sapl/norma/forms.py
+++ b/sapl/norma/forms.py
@@ -125,7 +125,11 @@ def clean(self):
 
         if not self.is_valid():
             return cleaned_data
-
+        norma = NormaJuridica.objects.filter(ano=cleaned_data['ano'],
+                                     numero=cleaned_data['numero'],
+                                     tipo=cleaned_data['tipo']).exists()
+        if norma:
+            raise ValidationError("Já existe uma norma de mesmo Tipo, Ano e Número no sistema")
         if (cleaned_data['tipo_materia'] and
             cleaned_data['numero_materia'] and
                 cleaned_data['ano_materia']):


Test patch:
Repository: interlegis/sapl

Issue:
Sem campos para adicionar matérias na Ordem do Dia
Ao "Adicionar Matérias na Ordem do Dia", não há campos pra preencher.
![captura de tela de 2018-06-08 08-42-08](https://user-images.githubusercontent.com/19169882/41156402-1db0e5ae-6af8-11e8-97dd-45d070f5e7ba.png)



Discussion:

Resolving patch:
diff --git a/sapl/sessao/views.py b/sapl/sessao/views.py
--- a/sapl/sessao/views.py
+++ b/sapl/sessao/views.py
@@ -418,15 +418,14 @@ class CreateView(MasterDetailCrud.CreateView):
         form_class = OrdemDiaForm
 
         def get_initial(self):
-            initial = super(CreateView, self).get_inital()
-            initial['data_ordem'] = SessaoPlenaria.objects.get(
+            self.initial['data_ordem'] = SessaoPlenaria.objects.get(
                 pk=self.kwargs['pk']).data_inicio.strftime('%d/%m/%Y')
             max_numero_ordem = OrdemDia.objects.filter(
                 sessao_plenaria=self.kwargs['pk']).aggregate(
                     Max('numero_ordem'))['numero_ordem__max']
-            initial['numero_ordem'] = (
+            self.initial['numero_ordem'] = (
                 max_numero_ordem if max_numero_ordem else 0) + 1
-            return initial
+            return self.initial
 
         def get_success_url(self):
             return reverse('sapl.sessao:ordemdia_list',


Test patch:
Repository: interlegis/sapl

Issue:
Edição de autor de matéria: opções indisponíveis na tela Início
Na tela Início não é possível editar o autor da matéria legislativa, não aparecem opções.
![captura de tela de 2018-06-11 08-05-26](https://user-images.githubusercontent.com/19169882/41228434-be32b46e-6d4e-11e8-9d64-084ddc1102ee.png)



Discussion:
Bom dia,
Para editar ou acrescentar autoria é necessário ir na aba "Autoria" em "Matéria Legislativa". Estes campos só estão disponíveis na criação da matéria para se acrescentar o primeiro autor.
Ok. Então, o ideal é que tais campos não aparecessem na tela de edição.

Resolving patch:
diff --git a/sapl/materia/forms.py b/sapl/materia/forms.py
--- a/sapl/materia/forms.py
+++ b/sapl/materia/forms.py
@@ -182,9 +182,9 @@ def __init__(self, *args, **kwargs):
 
         if self.instance and self.instance.pk:
             self.fields['tipo_autor'] = forms.CharField(required=False,
-                                                        widget=forms.TextInput(attrs={'disabled': 'disabled'}))
+                                                        widget=forms.HiddenInput())
             self.fields['autor'] = forms.CharField(required=False,
-                                                   widget=forms.TextInput(attrs={'disabled': 'disabled'}))
+                                                   widget=forms.HiddenInput())
 
     def clean(self):
         super(MateriaLegislativaForm, self).clean()


Test patch:
Repository: interlegis/sapl

Issue:
Sessão Plenária: numeração automática em Oradores do Expediente
Implementar numeração automática na ordem dos Oradores do Expediente para evitar falha do operador. Isso ocorreu no caso abaixo, já que o sistema está aceitando repetição do número de ordem.
https://sapl3.agudo.rs.leg.br/sessao/1854/oradorexpediente


Discussion:

Resolving patch:
diff --git a/sapl/sessao/forms.py b/sapl/sessao/forms.py
--- a/sapl/sessao/forms.py
+++ b/sapl/sessao/forms.py
@@ -465,7 +465,6 @@ class OradorExpedienteForm(ModelForm):
 
     def __init__(self, *args, **kwargs):
         super(OradorExpedienteForm, self).__init__(*args, **kwargs)
-
         legislatura_vigente = SessaoPlenaria.objects.get(pk=kwargs['initial']['id_sessao']).legislatura
 
         if legislatura_vigente:
@@ -482,11 +481,13 @@ def clean(self):
             return self.cleaned_data
 
         sessao_id = self.initial['id_sessao']
+        numero = self.initial.get('numero') # Retorna None se inexistente
         ordem = OradorExpediente.objects.filter(
                             sessao_plenaria_id=sessao_id,
                             numero_ordem=cleaned_data['numero_ordem']
                             ).exists()
-        if ordem:
+
+        if ordem and (cleaned_data['numero_ordem'] != numero):
             raise ValidationError(_(
                 'Já existe orador nesta posição da ordem de pronunciamento'))
 
diff --git a/sapl/sessao/views.py b/sapl/sessao/views.py
--- a/sapl/sessao/views.py
+++ b/sapl/sessao/views.py
@@ -385,7 +385,7 @@ def customize_link_materia(context, pk, has_permission, is_expediente):
         context['rows'][i][3] = (resultado, None)
     return context
 
-     
+
 def get_presencas_generic(model, sessao, legislatura):
     presencas = model.objects.filter(
         sessao_plenaria=sessao)
@@ -547,6 +547,14 @@ def get_success_url(self):
                            kwargs={'pk': self.kwargs['pk']})
 
 
+    class UpdateView(MasterDetailCrud.UpdateView):
+        form_class = OradorExpedienteForm
+
+        def get_initial(self):
+            return {'id_sessao': self.object.sessao_plenaria.id,
+                    'numero': self.object.numero_ordem}
+
+
 class OradorCrud(OradorCrud):
     model = Orador
 


Test patch:
Repository: interlegis/sapl

Issue:
Possibilitar visualização de votação nominal em usuário anônimo
"Boa Tarde, Equipe do Interlegis, tudo bem? Na Sessão Plenária Ordinária somente conseguimos visualizar a votação nominal, quando estamos logados."


Discussion:

Resolving patch:
diff --git a/sapl/sessao/views.py b/sapl/sessao/views.py
--- a/sapl/sessao/views.py
+++ b/sapl/sessao/views.py
@@ -329,6 +329,7 @@ def customize_link_materia(context, pk, has_permission, is_expediente):
                                   resultado_descricao,
                                   resultado_observacao))
             else:
+
                 if obj.tipo_votacao == 2:
                     if is_expediente:
                         url = reverse(
@@ -351,12 +352,8 @@ def customize_link_materia(context, pk, has_permission, is_expediente):
                                      (url,
                                       resultado_descricao,
                                       resultado_observacao))
-                else:
-                    resultado = ('%s<br/>%s' %
-                                     (resultado_descricao,
-                                      resultado_observacao))
 
-                if obj.tipo_votacao == 1:
+                elif obj.tipo_votacao == 1:
                     if is_expediente:
                         url = reverse(
                             'sapl.sessao:votacao_simbolica_transparencia',
@@ -375,9 +372,9 @@ def customize_link_materia(context, pk, has_permission, is_expediente):
                               '?&materia=ordem'
 
                     resultado = ('<a href="%s">%s<br/>%s</a>' %
-                                     (url,
-                                      resultado_descricao,
-                                      resultado_observacao))
+                                 (url,
+                                  resultado_descricao,
+                                  resultado_observacao))
                 else:
                     resultado = ('%s<br/>%s' %
                                      (resultado_descricao,


Test patch:
Repository: interlegis/sapl

Issue:
Pesquisa de Relatórios->Atas retorna sem nenhum resultado



Discussion:

Resolving patch:
diff --git a/sapl/base/forms.py b/sapl/base/forms.py
--- a/sapl/base/forms.py
+++ b/sapl/base/forms.py
@@ -528,7 +528,8 @@ class Meta:
     @property
     def qs(self):
         parent = super(RelatorioAtasFilterSet, self).qs
-        return parent.distinct().prefetch_related('tipo').order_by('-ano', 'tipo', 'numero')
+        return parent.distinct().prefetch_related('tipo').exclude(
+            upload_ata='').order_by('-legislatura', 'tipo', 'numero')
 
     def __init__(self, *args, **kwargs):
         super(RelatorioAtasFilterSet, self).__init__(
diff --git a/sapl/base/views.py b/sapl/base/views.py
--- a/sapl/base/views.py
+++ b/sapl/base/views.py
@@ -247,7 +247,6 @@ def get_context_data(self, **kwargs):
         if not self.filterset.form.is_valid():
             return context
 
-        context['object_list'] = context['object_list'].exclude(upload_ata='')
         qr = self.request.GET.copy()
         context['filter_url'] = ('&' + qr.urlencode()) if len(qr) > 0 else ''
 


Test patch:
Repository: interlegis/sapl

Issue:
Relatório Matéria por Autor: ordem
O relatório Matérias por Autor está desordenado. Penso que deveria ser pelo número da matéria.
https://sapl.agudo.rs.leg.br/sistema/relatorios/materia-por-autor?tipo=1&data_apresentacao_0=01%2F01%2F2018&data_apresentacao_1=&autoria__autor=


Discussion:

Resolving patch:
diff --git a/sapl/base/forms.py b/sapl/base/forms.py
--- a/sapl/base/forms.py
+++ b/sapl/base/forms.py
@@ -729,6 +729,11 @@ class RelatorioMateriasPorAutorFilterSet(django_filters.FilterSet):
 
     autoria__autor = django_filters.CharFilter(widget=forms.HiddenInput())
 
+    @property
+    def qs(self):
+        parent = super(RelatorioMateriasPorAutorFilterSet, self).qs
+        return parent.distinct().order_by('-ano', '-numero')
+
     class Meta:
         model = MateriaLegislativa
         fields = ['tipo', 'data_apresentacao']


Test patch:
Repository: interlegis/sapl

Issue:
Painel: não aparece a lista de parlamenteres
Não aparecem os parlamentares presentes, nem à sessão,
![captura de tela de 2018-06-12 14-50-36](https://user-images.githubusercontent.com/19169882/41307584-febc3b66-6e4f-11e8-8a89-098b347cd953.png)
 nem à Ordem do Dia. Testado com a sessão https://sapl.agudo.rs.leg.br/sessao/2051


Discussion:
Eu não consegui replicar o erro aqui. Como está a lista de presença dessa sessão?
Andre, você marcou a presença dos parlamentares  na ordem do dia?
Já vi, estão com presença!
@andreagudo tem como passar para gente um usuário administrador do sistema do seu SAPL para que possamos ver um dado? (passar via Telegram)


Resolving patch:
diff --git a/sapl/painel/views.py b/sapl/painel/views.py
--- a/sapl/painel/views.py
+++ b/sapl/painel/views.py
@@ -315,10 +315,7 @@ def get_presentes(pk, response, materia):
 
     presentes_list = []
     for p in presentes:
-        now_year = timezone.now().year
-        # Recupera a legislatura vigente
-        legislatura = Legislatura.objects.get(data_inicio__year__lte=now_year,
-                                              data_fim__year__gte=now_year)
+        legislatura = sessao.legislatura
         # Recupera os mandatos daquele parlamentar
         mandatos = p.parlamentar.mandato_set.filter(legislatura=legislatura)
 


Test patch:
Repository: interlegis/sapl

Issue:
Adição de várias matérias à Ordem do Dia: mensagem errada
Ao adicionar várias matérias na Ordem do Dia, o sistema o faz corretamente. Mas apresenta advertência que não corresponde à realidade. Ao salvar, deveria retornar à lista de matérias da Ordem do Dia, como ocorre com as Matérias do Expediente.
![captura de tela de 2018-06-18 08-09-07](https://user-images.githubusercontent.com/19169882/41533316-b9bb164c-72d0-11e8-8198-e389ede032de.png)



Discussion:

Resolving patch:
diff --git a/sapl/sessao/views.py b/sapl/sessao/views.py
--- a/sapl/sessao/views.py
+++ b/sapl/sessao/views.py
@@ -2824,7 +2824,8 @@ def post(self, request, *args, **kwargs):
                 ordem_dia.tipo_votacao = tipo_votacao
                 ordem_dia.save()
 
-        return self.get(request, self.kwargs)
+        return HttpResponseRedirect(
+            reverse('sapl.sessao:ordemdia_list', kwargs=self.kwargs))
 
 
 @csrf_exempt


Test patch: