O que é MVC, realmente?


202

Como programador sério, como você responde à pergunta O que é MVC?

Na minha opinião, o MVC é um tópico meio nebuloso - e, por esse motivo, se seu público é um aprendiz, você é livre para descrevê-lo em termos gerais que dificilmente serão controversos.

No entanto, se você estiver falando com um público experiente, especialmente um entrevistador, é difícil pensar em uma direção a seguir que não arrisque uma reação de "bem, isso não está certo! ...". Todos nós temos experiências diferentes no mundo real e nunca encontrei o mesmo padrão de implementação MVC duas vezes.

Especificamente, parece haver divergências quanto ao rigor, definição de componentes, separação de peças (qual peça se encaixa onde), etc.

Então, como devo explicar o MVC de maneira correta, concisa e incontroversa?


4
Nota: Se você estiver trabalhando no ASP.NET, o MVC terá um segundo significado não nebuloso: ASP.NET MVC
Brian

MVC foi bem explicado aqui codespeaker.com/blogs/…
smzapp 19/18

Respostas:


156

MVC é uma arquitetura de software - a estrutura do sistema - que separa a lógica do domínio / aplicativo / negócio (o que você preferir) do restante da interface do usuário. Isso é feito separando o aplicativo em três partes: o modelo, a visualização e o controlador.

O modelo gerencia comportamentos e dados fundamentais do aplicativo. Ele pode responder a pedidos de informações, responder a instruções para alterar o estado de suas informações e até mesmo notificar observadores em sistemas controlados por eventos quando as informações mudam. Pode ser um banco de dados ou qualquer número de estruturas de dados ou sistemas de armazenamento. Em resumo, são os dados e o gerenciamento de dados do aplicativo.

A visualização fornece efetivamente o elemento da interface com o usuário do aplicativo. Ele renderizará os dados do modelo em um formulário adequado para a interface do usuário.

O controlador recebe entrada do usuário e faz chamadas para modelar objetos e a visualização para executar ações apropriadas.

Em suma, esses três componentes trabalham juntos para criar os três componentes básicos do MVC.


7
Eu realmente prefiro pensar no MVC como uma arquitetura de três (ou mais) padrões do que como um padrão de design. Não há implementação canônica, simplesmente não é tão pequena e todas as implementações terão muito mais do que os componentes principais implícitos.
perfil completo

51
Embora esta resposta tenha 21 votos positivos, acho a frase "Pode ser um banco de dados ou qualquer número de estruturas de dados ou sistemas de armazenamento. (Tl; dr: são os dados e o gerenciamento de dados do aplicativo)" horrível. O modelo é a lógica pura de negócios / domínio. E isso pode e deve ser muito mais que o gerenciamento de dados de um aplicativo. Também diferencio entre lógica de domínio e lógica de aplicação. Um controlador nunca deve conter lógica de negócios / domínio ou conversar diretamente com um banco de dados.
Falcon

9
Não posso discordar mais dessa resposta simplesmente porque ela afirma que o mvc é racional fora da camada de apresentação. O restante da resposta está ok. O MVC deve começar e terminar na sua camada de apresentação e absolutamente não deve ter sua lógica de negócios e repositório nela. Isso efetivamente coloca todo o aplicativo em sua camada de apresentação e não disponibiliza API que permita acesso direto à lógica de negócios ou a dados puros sem que ele tenha sido projetado para o aplicativo de origem. Isso não está aberto para extensibilidade; os modelos o aproximam, mas você ainda está perdendo o acoplamento frouxo
Jimmy Hoffa

6
@ Jimmy: Em muitas construções do MVC, os modelos podem ser reutilizados nas APIs porque eles não têm dependências na interface do usuário - a separação entre exibição e modelo cuida disso. Mas isso depende, é claro, de como você escolhe definir 'modelo'. Se você for fazer um julgamento sobre o MVC, primeiro explique qual interpretação do MVC você está usando.
Owen S.

5
@ Yannis: Isso apenas levanta a questão: o que é uma arquitetura de padrões? Por que você não chamaria isso de apenas outro padrão de design? A própria definição de padrão de design no GoF (e Alexander) deixa bem claro que os padrões não devem prescrever uma implementação canônica (embora a popularidade de ambos os livros prejudique um pouco essa noção).
Owen S.

136

Analogia

Expliquei o MVC ao meu pai assim:

MVC (Model, View, Controller) é um padrão para organizar o código em um aplicativo para melhorar a capacidade de manutenção.

Imagine um fotógrafo com sua câmera em um estúdio. Um cliente pede que ele tire uma foto de uma caixa.

A caixa é o modelo , o fotógrafo é o controlador e a câmera é a vista .

Como a caixa não conhece a câmera ou o fotógrafo, é completamente independente. Essa separação permite ao fotógrafo andar pela caixa e apontar a câmera para qualquer ângulo para obter a foto / visão que deseja.

Arquiteturas não MVC tendem a ser fortemente integradas. Se a caixa, o controlador e a câmera fossem o mesmo objeto, teríamos que nos separar e reconstruir a caixa e a câmera sempre que desejássemos obter uma nova visualização. Além disso, tirar a foto sempre seria como tirar uma selfie - e isso nem sempre é muito fácil.


Explicação detalhada

Foi só depois de ler a seguinte pergunta / resposta maillist que eu senti que tinha entendido o MVC. Citação: https://mail.python.org/pipermail/python-list/2006-January/394968.html

bwaha escreveu:

O autor se refere ao mvctree.py no wxPython como um exemplo de design do MVC. No entanto, ainda sou muito verde, então acho esse exemplo específico muito complexo e não estou entendendo a separação que o autor está recomendando.

MVC é tudo sobre separação de preocupações.

O Modelo é responsável pelo gerenciamento dos dados do programa (dados privados e do cliente). O View / Controller é responsável por fornecer ao mundo externo os meios para interagir com os dados do cliente do programa.

O Modelo fornece uma interface interna (API) para permitir que outras partes do programa interajam com ele. O View / Controller fornece uma interface externa (GUI / CLI / formulário da web / IPC de alto nível / etc.) Para permitir que tudo o que o programa comunique com ele.

O Modelo é responsável por manter a integridade dos dados do programa, porque se isso for corrompido, o jogo terminará para todos. O View / Controller é responsável por manter a integridade da interface do usuário, garantindo que todas as exibições de texto estejam exibindo valores atualizados, desativando itens de menu que não se aplicam ao foco atual, etc.

O modelo não contém código de visualização / controlador; sem classes de widget da GUI, sem código para colocar caixas de diálogo ou receber entrada do usuário. O View / Controller não contém código de modelo; nenhum código para validar URLs ou executar consultas SQL e também nenhum estado original: quaisquer dados mantidos pelos widgets são apenas para fins de exibição e apenas um reflexo dos dados verdadeiros armazenados no Modelo.

Agora, aqui está o teste de um verdadeiro projeto MVC: o programa deve, em essência, ser totalmente funcional, mesmo sem um View / Controller conectado. OK, o mundo externo terá problemas para interagir com ele dessa forma, mas desde que se conheça os encantamentos apropriados da API de modelo, o programa manterá e manipulará os dados normalmente.

Por que isso é possível? Bem, a resposta simples é que tudo isso se deve ao baixo acoplamento entre as camadas Model e View / Controller. No entanto, esta não é a história completa. A chave para todo o padrão MVC é a direção na qual essas conexões vão: TODAS as instruções fluem da View / Controller para o Model. O modelo NUNCA diz ao View / Controller o que fazer.

Por quê? Porque no MVC, enquanto o View / Controller tem permissão para conhecer um pouco sobre o Model (especificamente, a API do Model), mas o Model não tem permissão para saber nada sobre o View / Controller.

Por quê? Porque o MVC é sobre a criação de uma clara separação de preocupações.

Por quê? Para ajudar a impedir que a complexidade do programa fique fora de controle e enterre você, o desenvolvedor, sob ele. Quanto maior o programa, maior o número de componentes nesse programa. E quanto mais conexões existirem entre esses componentes, mais difícil será para os desenvolvedores manter / estender / substituir componentes individuais ou apenas seguir como o sistema inteiro funciona. Pergunte a si mesmo: ao olhar para um diagrama da estrutura do programa, você prefere ver uma árvore ou o berço de um gato? O padrão MVC evita o último, impedindo conexões circulares: B pode conectar-se a A, mas A não pode conectar-se a B. Nesse caso, A é o modelo e B é o View / Controller.

BTW, se você for perspicaz, notará um problema com a restrição 'unidirecional' descrita: como o Modelo pode informar o View / Controller sobre alterações nos dados do usuário do Modelo quando ele nem sequer tem permissão para sabe que o View / Controller, não importa enviar mensagens para ele? Mas não se preocupe: existe uma solução para isso, e é bastante elegante, mesmo que pareça um pouco indireta no começo. Voltaremos a isso em um momento.

Em termos práticos, então, um objeto View / Controller pode, através da API do Modelo, 1. dizer ao Modelo para fazer as coisas (executar comandos) e 2. Diga ao Modelo para dar as coisas (retornar dados). A camada View / Controller envia instruções para a camada Model e extrai informações da camada Model.

E é aí que o seu primeiro exemplo MyCoolListControl der errado, porque a API para essa classe requer que as informações sejam empurrados para ele, então você está de volta a ter um acoplamento de duas vias entre as camadas, violando as regras MVC e despejar-lo de volta para o arquitetura do berço do gato que você estava [presumivelmente] tentando evitar em primeiro lugar.

Em vez disso, a classe MyCoolListControl deve seguir o fluxo, puxando os dados necessários da camada abaixo, quando necessário. No caso de um widget de lista, isso geralmente significa perguntar quantos valores existem e, em seguida, solicitar cada um desses itens, porque essa é a maneira mais simples e mais simples de fazê-lo e, portanto, mantém o mínimo de acoplamento. E se o widget quiser, digamos, apresentar esses valores ao usuário em boa ordem alfabética, então isso é perogativo; e sua responsabilidade, é claro.

Agora, um último enigma, como sugeri anteriormente: como você mantém a exibição da interface do usuário sincronizada com o estado do modelo em um sistema baseado em MVC?

Aqui está o problema: muitos objetos View são stateful, por exemplo, uma caixa de seleção pode estar marcada ou desmarcada, um campo de texto pode conter algum texto editável. No entanto, o MVC determina que todos os dados do usuário sejam armazenados na camada Modelo, portanto, quaisquer dados mantidos por outras camadas para fins de exibição (o estado da caixa de seleção, o texto atual do campo de texto) devem, portanto, ser uma cópia subsidiária desses dados primários do Modelo. Mas se o estado do modelo mudar, a cópia desse estado não será mais precisa e precisará ser atualizada.

Mas como? O padrão MVC impede que o Modelo envie uma cópia nova dessas informações para a camada Visualizar. Caramba, ele nem sequer permite que o Modelo envie uma mensagem para a View dizendo que seu estado mudou.

Bem, quase. Ok, a camada Model não pode falar diretamente com outras camadas, pois isso exigiria que ele soubesse algo sobre essas camadas, e as regras do MVC evitam isso. No entanto, se uma árvore cai em uma floresta e ninguém está por perto para ouvi-la, ela soa?

A resposta, você vê, é configurar um sistema de notificações, fornecendo à camada Model um local que ela pode anunciar a ninguém em particular que acabou de fazer algo interessante. Outras camadas podem postar ouvintes com esse sistema de notificação para ouvir os anúncios nos quais eles realmente estão interessados. A camada Model não precisa saber nada sobre quem está ouvindo (ou mesmo se alguém está ouvindo!); apenas publica um anúncio e depois esquece. E se alguém ouvir esse anúncio e sentir vontade de fazer algo depois - como pedir ao modelo novos dados para que ele possa atualizar sua exibição na tela -, então ótimo. O Modelo apenas lista quais notificações ele envia como parte de sua definição de API; e o que mais alguém faz com esse conhecimento depende deles.

O MVC é preservado e todos estão felizes. Sua estrutura de aplicativos pode muito bem fornecer um sistema de notificações embutido ou você pode escrever seu próprio, se não (consulte o 'padrão de observador').

...

Enfim, espero que ajude. Depois de entender as motivações por trás do MVC, as razões pelas quais as coisas são feitas da maneira que são começam a fazer sentido, mesmo quando - à primeira vista - elas parecem mais complexas do que o necessário.

Felicidades,

tem


Que tal o MVVM e o MVCS, ouvi sua resposta do MVC em softwareengineering.stackexchange.com/questions/184396/…
dengApro

86

MVC é principalmente um chavão.

Costumava ser considerado um padrão, mas sua definição original de 1979 foi embotada, repassada, mal interpretada, tirada do contexto original. Foi mal redefinido a ponto de parecer uma religião e, embora isso certamente ajude seus cultistas de carga a defendê-la, seu nome não se associa mais a um conjunto sólido de diretrizes . Como tal, não pode mais ser considerado um padrão.

O MVC nunca foi concebido para descrever aplicativos da web.
Nem sistemas operacionais modernos, nem idiomas.
(alguns dos quais realmente redundaram a definição de 1979)

Foi feito para. E não deu certo.

Agora lidamos com um híbrido obscuro de web-mvc que, com seu status de palavra-chave horrível, má definição e tendo programadores semi-analfabetos como um público-alvo, faz uma publicidade muito ruim aos padrões de software em geral.

O MVC, portanto, tornou-se uma separação de preocupações destiladas para pessoas que realmente não querem pensar muito sobre isso.

  • O modelo de dados é tratado de uma maneira,
  • a visão em outro,
  • o resto é apenas nomeado "controlador" e deixado a critério do leitor.

Os sites / aplicativos da web nos anos 90 realmente não costumavam aplicar a separação de preocupações.

Eles eram pedaços horríveis de código de espaguete misturado.
As alterações na interface, os reprojetos e os rearranjos de dados foram incrivelmente difíceis, caros, longos, deprimente e malfadados.

Tecnologias da Web como ASP, JSP e PHP tornam muito fácil misturar as preocupações de exibição com os dados e as preocupações de aplicativos. Os recém-chegados ao campo geralmente emitem bolas de código inextricáveis, como nos velhos tempos.

Assim, um número crescente de pessoas começou a repetir "use MVC" em loops intermináveis ​​em fóruns de suporte. O número de pessoas expandiu-se a ponto de incluir gerentes e profissionais de marketing (para alguns o termo já era familiar, desde os tempos da programação da GUI, na qual o padrão fazia sentido) e que se tornou o gigante de um chavão que devemos enfrentar agora .

Tal como está, é senso comum , não uma metodologia .
É um ponto de partida , não uma solução .
É como dizer às pessoas para respirar ar ou fazer abdominais , não uma cura para o câncer .


22
Certamente não é principalmente um chavão. É verdade que o MVC tende a ser mais difundido e menos distinto do que outros padrões de design; portanto, você pode pensar nisso como um princípio ou paradigma de organização. Mas como você chama, é um conceito fundamental em várias estruturas bem-orientadas a objetos de muito sucesso. Fingir que é apenas uma palavra da moda, ou seja, uma frase da moda que não significa muito, é prestar um desserviço ao OP.
Caleb #

23
It's a fancy word for pre-existing concepts that didn't really need one.E qual padrão / arquitetura de design não se encaixa nessa descrição?
yannis

8
+1 Francamente, a maioria dessas coisas é óbvia quando você tem uma noção dos fundamentos (coesão, acoplamento, legibilidade, ortogonalidade etc.) e combina isso com os recursos das linguagens modernas.
Lorean

12
The data model is handled one way, the view in another, the rest is just named "controller"+1
c69

33
-1. Eu gostaria de poder -10 por todos os comentários idiotas de +1. Como isso é "óbvio", dados os princípios básicos de acoplamento e coesão? As arquiteturas de interface do usuário são abundantes, incluindo o modelo MVC, MVP, MVVM, Forms e Smalltalk. Algumas empresas também levam a arquitetura de aplicativos compostos ao extremo, como no WS-CAF. Dizer que o "senso comum" automaticamente leva você ao CVM detém tanta água quanto a chamada prova de Deus de Descartes. É obviamente o que você sabe, mas sua resposta demonstra uma ignorância de outros métodos ou uma incapacidade de expandir seus próprios horizontes.
Aaronaught 21/10/12

39

A melhor maneira de defini-lo é ir aos escritos originais de Trygve Reenskaug , que o inventou: http://heim.ifi.uio.no/~trygver/themes/mvc/mvc-index.html

Este artigo, em particular, é geralmente considerado o texto de definição: http://heim.ifi.uio.no/~trygver/1979/mvc-2/1979-12-MVC.pdf

MODELOS

Modelos representam conhecimento. Um modelo pode ser um único objeto (bastante desinteressante) ou pode ser alguma estrutura de objetos ...

Deveria haver uma correspondência individual entre o modelo e suas partes, por um lado, e o mundo representado como percebido pelo proprietário do modelo, por outro. Os nós de um modelo devem, portanto, representar uma parte identificável do problema.

Os nós de um modelo devem estar todos no mesmo nível de problema, é confuso e considerado de má forma misturar nós orientados a problemas (por exemplo, compromissos do calendário) com detalhes de implementação (por exemplo, parágrafos).

VISUALIZAÇÕES

Uma visão é uma representação (visual) do seu modelo. Normalmente, destacaria certos atributos do modelo e suprimia outros. Está, portanto, atuando como um filtro de apresentação .

Uma visualização é anexada ao seu modelo (ou parte do modelo) e obtém os dados necessários para a apresentação do modelo, fazendo perguntas. Também pode atualizar o modelo enviando mensagens apropriadas. Todas essas perguntas e mensagens devem estar na terminologia do modelo; portanto, a visualização precisa conhecer a semântica dos atributos do modelo que ele representa. (Pode, por exemplo, solicitar o identificador do modelo e esperar uma instância de Text, pode não assumir que o modelo seja da classe Text.)

CONTROLADORES

Um controlador é o link entre um usuário e o sistema. Ele fornece informações ao usuário, organizando exibições relevantes para se apresentarem nos locais apropriados na tela. Ele fornece meios para a saída do usuário, apresentando ao usuário menus ou outros meios de fornecer comandos e dados. O controlador recebe essa saída do usuário, converte-a nas mensagens apropriadas e passa essas mensagens para. Para uma ou mais visualizações.

Um controlador nunca deve complementar as vistas, por exemplo, nunca deve conectar as vistas dos nós desenhando setas entre eles.

Por outro lado, uma exibição nunca deve saber sobre a entrada do usuário, como operações do mouse e pressionamentos de teclas. Sempre deve ser possível escrever um método em um controlador que envie mensagens para visualizações que reproduzem exatamente qualquer sequência de comandos do usuário.

EDITORES

Um controlador está conectado a todos os seus pontos de vista, eles são chamados de partes do controlador. Algumas visualizações fornecem um controlador especial, um editor , que permite ao usuário modificar as informações apresentadas pela visualização. Esses editores podem ser unidos no caminho entre o controlador e sua visualização, e atuarão como uma extensão do controlador. Após a conclusão do processo de edição, o editor é removido do caminho e descartado.

Observe que um editor se comunica com o usuário através das metáforas da visualização conectada; portanto, o editor está intimamente associado à visualização. Um controlador se apossará de um editor solicitando a visualização - não há outra fonte apropriada.


11

MVC é um padrão de design usado para isolar a lógica de negócios da apresentação.

Difere de muitos outros padrões de design pelo fato de geralmente não ser implementado de forma sucinta, mas é a base de uma estrutura.

Embora um aplicativo que implemente um padrão de estratégia seja apenas um pequeno detalhe, dizer que um aplicativo da web usa o padrão de design do MVC é muito definidor de sua arquitetura .


2
Isso não é estritamente útil, existem requisitos muito específicos para implementar o padrão MVC que o diferenciam do MVP, MP, MVVM. Ele também tem um público-alvo diferente daqueles outros padrões de apresentação.
31411 Ian

8

MVC é um design de software que separa os seguintes componentes de um sistema ou subsistema:

  1. Modelo - Dados sobre o estado do aplicativo ou seus componentes. Pode incluir rotinas para modificação ou acesso.
  2. View - Uma interpretação dos dados (modelo). Isso é limitado apenas a uma representação visual, mas pode ser informações derivadas de áudio (por exemplo, estatísticas canalizadas para outro objeto de modelo), etc. Além disso, um único modelo pode ter várias visualizações.
  3. Controle - Lida com a entrada externa no sistema, invocando modificações no modelo. O controle / exibição pode estar intimamente relacionado (no caso de uma interface do usuário). No entanto, outras entradas externas (como comandos de rede) podem ser processadas e são completamente independentes da exibição.

6

Eu diria que MVC é um conceito ou uma família de padrões semelhantes.

Acho que vale a pena ler este artigo. Arquiteturas de GUI por Martin Fowler


5
Esse artigo da Fowler é excelente e todo mundo que usa o termo MVC deve lê-lo. Dois pontos que considero particularmente interessantes são que o uso original do termo MVC em GUIs é bastante diferente do uso em estruturas da web e que, nas GUIs, a separação entre view e controller foi menos útil do que o previsto.
Tom Anderson

3

Primeiro, você precisa determinar quem é o autor da pergunta e que tipo de resposta ele está procurando. Você responde a essa pergunta com outra pergunta, como "Em que sentido?"

Você pode perguntar se eles estão se referindo ao MVC em geral, uma implementação específica do MVC (por exemplo, asp.net MVC, spring MVC, smalltalk MVC, etc.), o que é tecnicamente, o que é filisoficamente (sim, tem um filosofia também), etc.

Se essa é uma pergunta em um teste e você não pode pedir ao solicitante que esclareça, precisará adivinhar com base no contexto.

Uma resposta boa e simples é:

MVC é uma arquitetura de interface de usuário de software usada para separar preocupações estruturais e comportamentais, a fim de facilitar um software mais sustentável.

Você também pode dizer:

Ao separar a Visão do Controlador do Modelo, ele incentiva o isolamento de componentes com base em suas responsabilidades. Em teoria, e geralmente na prática, isso ajuda a melhorar a capacidade de manutenção, impedindo que as diferentes partes do sistema se misturem e criando sistemas mais complexos.

Mas, no final, você será julgado se dará a resposta que eles esperam. A única solução para o problema é descobrir que tipo de resposta eles estão esperando.


2

Aqui está o que eu diria sobre isso. Eu tentaria explicá-lo em termos de aplicativos móveis, porque é com isso que estou mais familiarizado e porque acho que não o entendi completamente antes de começar a fazer aplicativos móveis.
Vamos pegar o Android, por exemplo.
Camada de apresentação, ie. A interface do usuário pode (na maioria das vezes é) ser especificada inteiramente em xml. Para simplificar, digamos que um arquivo xml descreva uma tela no aplicativo. O arquivo XML especifica controles, layout dos controles, posicionamento, cores, tamanho, rótulos de strings ... tudo relacionado à apresentação. No entanto, não sabe nada sobre quando será chamado, quando será colocado na tela. Será um layout independente ou parte de um layout maior? Aí está: sua visão perfeita .

Agora, obviamente, a visualização precisa ser colocada na tela em algum momento, então como deve ser feito? Seu CONTROLADOR , no Android, chamado Atividade. Como o nome diz, atividade faz alguma atividade. Mesmo que seu único objetivo seja exibir a vista definida na etapa 1, ele executará alguma ação. Portanto, a atividade busca uma exibição e a exibe na tela. Como a view não sabe nada sobre atividade, da mesma forma a atividade não sabe nada sobre a apresentação real. Nós (os programadores) podemos reorganizar o layout da exibição várias vezes, sem alterar nem uma linha de código em nossa atividade.

Agora, não há muita utilidade em apresentar seu layout xml brilhante e bem definido sem realmente fazer algo. Digamos que queremos armazenar os dados inseridos pelo usuário. A atividade precisa enfrentar esse processo, desde os dados do usuário até os repassar para outra pessoa para lidar com eles (processar, armazenar e excluir). Para quem vai passar? Bem, para um MODELO . Eu gosto de pensar em um modelo como puro. classe java que não sabe nada sobre o contexto de aplicativos em que vive. (Na prática, quase nunca será esse o caso).

Digamos que eu tenho uma classe Pessoa que possui três propriedades: nome, endereço, idade. Meu layout definido em XML possui 3 campos para entrada do usuário: nome, endereço, idade. Minha atividade pega os três valores da entrada do usuário, cria um novo objeto Person e chama algum método nele que sabe como lidar com alguma lógica específica de Person. Aí está. Controlador de visualização de modelo.


1

Eu sempre começo dizendo a eles que o padrão não é novidade e existe há muitos anos ... é nesse ponto que eles me dão uma aparência inquisitiva e BAM !, eles são viciados:

E então eu falava sobre os vários pontos, como as respostas anteriores, mas acho importante também ser contextual, como JB King disse, ASP.NET MVC etc,

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.