(Helluva Boss)
Traduzido do inglês
O grupo I.M.P, com a possibilidade de TETO!?
⯆⚉⯆
~Teteteto~
"Não me chame de 'fofo', eu sou gangsta!"
(Recomendado usar com algum tipo de proxy. Não sei se o JLMM vai funcionar, e estou com preguiça demais de testar eu mesmo)
Cenário um:
Loona, Millie e Moxxie estão fugindo da polícia.
Cenário dois:
Você trabalha na I.M.P há um mês. Hoje todos eles têm uma reunião.
Cenário três:
Você está doente. Loona está cuidando de você. (feito para ser fofo)
Cenário quatro:
Você e Millie estão em uma missão na Terra.
Cenário cinco:
Uh-oh...
Cenário seis:
Uma grande briga aconteceu. Vá consolar a Loona.
Cenário sete:
Você e a Loon estão sendo bobos.
Cenário oito:
Loona, Millie, Moxxie e Blitzo querem adotar um novo HellHound. Esse é você, mano. (POV Hellhound)
Cenário nove:
Insira seu próprio cenário.
Tags:
Computadores não fazem sentido. Jogue um pouco de metal numa caixa e boom. Que diabos está acontecendo aqui? Dentro do seu PC há uma unidade central de processamento, ou CPU. É basicamente só um pedaço de silício com bilhões de interruptores microscópicos chamados transistores. Dependendo do fluxo de eletricidade, eles podem estar ligados ou desligados, meio como uma lâmpada, o que nos dá dois estados, um e zero. O valor de um desses interruptores é chamado de bit. Um bit sozinho não faz muita coisa, mas junte-os e... Um grupo de 8 bits é chamado de byte, e pode ter 256 combinações diferentes de 0s e 1s. Parabéns! Agora podemos armazenar informações contando em um sistema chamado binário. Cada bit representa uma potência de 2, sendo 1 significando que a potência está incluída e 0 significando que não está, então este número tem 1 vezes 64, 1 vezes 4 e 1 vezes 1, o que soma 69. Isso é legal, mas para humanos, hexadecimal é ainda melhor. Costuma ser denotado por este 0x, e é simplesmente um formato mais legível que o binário. Quatro bits binários podem assumir qualquer valor de 0 a 15. Hexadecimal usa de 0 a 9 e A a F para representar esses valores, então um grupo de quatro bits pode ser substituído por um dígito hexadecimal. Okay, agora que podemos armazenar números, só precisamos que os computadores, bem, façam algo com eles. Usando transistores, você pode fazer portas lógicas, que são circuitos eletrônicos que encapsulam declarações lógicas. Você pode pensar nisso como uma lâmpada com dois interruptores, onde a luz só acende sob certas condições, por exemplo só se A e B estiverem ligados. Combinando portas lógicas de forma inteligente, você pode construir circuitos que realizam cálculos de acordo com a álgebra booleana, que é um sistema que formaliza operações matemáticas em binário. Mas, embora os computadores entendam zeros e uns, para humanos isso não é realmente tão útil. Então, usando uma codificação de caracteres como ASCII, podemos atribuir um número binário a cada caractere. Quando você digita qualquer coisa no seu teclado, isso é traduzido para este código binário, e assim que o computador vê isso, ele diz, ah sim, isso é um A maiúsculo, e o joga na tela. Como esses dispositivos se encaixam é gerenciado por um kernel de sistema operacional, como Windows, Linux ou Mac, que fica entre o hardware do computador e os aplicativos e gerencia como todos eles funcionam juntos, por exemplo, com drivers de dispositivo. Dispositivos de entrada permitem que você dê instruções ao computador com o apertar de um botão, mas no nível mais baixo, os computadores só entendem instruções em código de máquina, que é código binário dizendo à CPU o que fazer e quais dados usar. Quando se trata de seguir essas instruções, a CPU é meio que um gênio, só que com a memória de um peixinho dourado demente. Ela pode lidar com qualquer instrução, mas não consegue armazenar nenhum dado, então só é realmente útil com memória de acesso aleatório, ou RAM. Você pode imaginar como uma grade, onde cada caixa pode conter um byte de informação, que pode ser dado ou instrução, e tem um endereço para que a CPU possa acessá-lo em quatro etapas. Buscar da memória, decodificar instruções e dados e, finalmente, executar e armazenar o resultado. Este é um ciclo de máquina. Como um programa é basicamente só uma lista de instruções e memória, para executá-lo, a CPU as executa uma por uma em ciclos de máquina até estar completo. Ah sim, eu mencionei que isso acontece, tipo, muito rápido? CPUs modernas podem fazer bilhões de ciclos por segundo, que são coordenados e sincronizados por um gerador de clock. A velocidade desse clock é medida em gigahertz, e as pessoas costumam fazer overclock de suas CPUs para melhorar o desempenho, o que é legal, mas pode simplesmente colocar fogo no seu PC. O que é ainda mais louco é que uma CPU tem múltiplos núcleos, que podem todos executar instruções diferentes em paralelo, ou seja, ao mesmo tempo. Cada núcleo também pode ser dividido em múltiplas threads, o que permite que cada núcleo individual lide com múltiplas instruções simultaneamente, alternando entre elas muito rapidamente. Okay, isso é legal, mas não importa quão poderoso seja um computador se você não tem como dar instruções a ele em primeiro lugar. Digitar código de máquina à mão provavelmente te deixaria louco, mas felizmente, você não precisa. O kernel é embrulhado em um shell, que é apenas um programa que expõe o kernel ao usuário, permitindo instruções simples em uma interface de linha de comando com entradas de texto. Mas a melhor forma de fazer um computador fazer algo útil é com uma linguagem de programação, que usa abstração para que, em vez disso, você possa escrever código que se parece com isso, que é então convertido em código de máquina para você. Algumas linguagens como Python usam um interpretador, que tenta diretamente executar o código-fonte linha por linha. Outras linguagens como C ou Go usam um compilador, que converte o programa inteiro em código de máquina antes de colocá-lo em um arquivo que a CPU pode executar. Agora, toda linguagem de programação tem uma sintaxe diferente, mas há algumas ferramentas básicas que quase todas têm. A forma mais básica de usar dados é com variáveis, que atribui um valor a um nome que pode então ser reutilizado e modificado. Dependendo do valor, as variáveis podem ter diferentes tipos de dados. Para texto, há caracteres únicos e strings de múltiplos caracteres. Para números, há inteiros, que também podem ter sinal se forem negativos, e números de ponto flutuante para valores decimais. Eles são chamados de ponto flutuante porque o ponto decimal pode flutuar para trocar precisão por alcance. Isso é possível porque eles usam notação científica. É algum número vezes uma potência que te diz onde colocar o ponto decimal, que é exatamente como eles se parecem por baixo dos panos. O número real é armazenado com frações binárias. Algumas frações, como um terço, só podem ser aproximadas em binário com uma soma infinita. Mas, como a memória não é infinita, você tem que cortá-la em algum momento, o que leva a erros de arredondamento, causando cálculos bem estranhos às vezes. Se isso não for suficiente, long e double usam o dobro da memória para dobrar o alcance de ints e floats. Algumas linguagens como Python descobrem automaticamente qual tipo uma variável é, mas em uma linguagem como C, você tem que declarar explicitamente o tipo de uma variável. O valor de uma variável é armazenado em algum endereço na memória. Ponteiros são variáveis cujo valor é o endereço de memória de outra variável, que é denotado por este e comercial. Então, na verdade, um ponteiro é apenas um pedaço de memória apontando para outro pedaço de memória. Como um endereço de memória é apenas um número, você pode somar e subtrair dele para navegar por bytes individuais de memória. Isso é chamado de aritmética de ponteiros. Em algumas linguagens de baixo nível como C, você tem que alocar e liberar manualmente a memória quando ela não for mais usada. Tudo isso acontece no heap, que é uma parte da memória que pode crescer e encolher dinamicamente conforme o programa exige, o que permite mais controle mas torna incrivelmente fácil quebrar completamente seu código. Você pode tocar em memória que não deveria ou que simplesmente não existe, o que é conhecido como falha de segmentação. Mas também, se há algum pedaço de memória que não é mais usado e você esquece de liberá-lo ou não tem mais como acessá-lo, essa memória não é mais utilizável. Isso é chamado de vazamento de memória e pode fazer o programa ficar lento e eventualmente travar. Para evitar essa bagunça, linguagens de alto nível como Python têm coletores de lixo integrados que gerenciam a memória para você. Diferentes tipos de dados ocupam uma quantidade diferente de memória. Inteiros costumam ter 4 bytes de memória, um único caractere costuma ter 1 byte de memória, e uma string é apenas múltiplos bytes de caracteres com um caractere nulo para sinalizar o fim da string. Armazenar múltiplos itens em um pedaço contíguo de memória como este é a ideia de um array. De forma mais geral, é uma lista de itens com o mesmo tipo de dados, com cada item tendo um índice numérico, na maioria das vezes começando em 0. Como os itens estão próximos uns dos outros na memória, sabendo o endereço do primeiro item você pode indexar rapidamente qualquer item do array usando aritmética de ponteiros. Arrays são o que é conhecido como uma estrutura de dados, que é apenas uma forma de organizar dados para facilitar o trabalho com eles. Recuperar valores de um array é extremamente rápido, mas o tamanho de um array geralmente é fixo ao criá-lo, então quando está cheio você não pode adicionar nada, e se você não usa tudo, é só memória desperdiçada, então uma opção mais flexível é uma lista encadeada. Ela usa nós contendo um valor e um ponteiro para o próximo nó, o que permite que eles fiquem espalhados na memória. Além disso, ela pode crescer e encolher dinamicamente conforme você adiciona e remove qualquer nó, e você pode reordená-la simplesmente reorganizando os ponteiros. Isso é ótimo, mas elas podem ser impraticáveis, pois você não tem como acessar o último nó sem percorrer todos os anteriores. Mas ainda assim, tanto arrays quanto listas encadeadas são úteis, pois permitem criar filas e pilhas. Uma pilha segue o princípio de último a entrar, primeiro a sair, assim como pegar uma panqueca de uma pilha. Praticamente, imagine um ponteiro que sempre aponta para o item que foi adicionado por último à estrutura, então você pode fazer pop, ou seja, remover o último item, o que incrementa o ponteiro para trás. Uma fila segue o princípio de primeiro a entrar, primeiro a sair e usa dois ponteiros, um para o primeiro item que foi adicionado e um para o último. Qualquer novo item é adicionado após o último ponteiro, que é então atualizado, e a remoção da fila começa no primeiro ponteiro. Outra estrutura de dados útil é o hash map, que é apenas uma coleção de pares chave-valor. Funciona mais ou menos como um array, mas usa uma função hash para pegar uma chave e atribuí-la a um índice, onde seu valor é então armazenado. Mas às vezes, duas chaves diferentes podem mapear para o mesmo índice, o que é chamado de colisão. Há diferentes formas de lidar com isso, mas uma delas é criar uma lista encadeada naquela posição do array, o que deixa a busca por esse valor um pouco mais lenta, mas ainda assim, HashMaps são incrivelmente úteis porque você pode definir as chaves que apontam para cada valor, e como são baseados em arrays, recuperá-los é extremamente rápido. Para muitos problemas, pode ser muito útil representar a relação entre diferentes pontos de dados como uma estrutura de dados. Se você pegar os nós de uma lista encadeada, mas permitir que qualquer nó aponte para qualquer outro nó, você obtém um grafo, onde os nós são conectados por arestas que podem ser direcionadas, não direcionadas, e podem até carregar um peso, que pode representar qualquer métrica, como distância ou custo. Grafos são úteis para analisar grupos dentro de redes ou encontrar o caminho mais curto entre dois pontos, por exemplo no Google Maps. Existem duas formas principais de buscar em um grafo. A busca em largura começa em um nó e avança camada por camada até encontrar o nó alvo pela primeira vez. A busca em profundidade explora cada caminho completamente até chegar a um beco sem saída, então volta ao último nó com um caminho diferente e continua a partir dali da mesma forma até encontrar o nó alvo. Um grafo onde quaisquer dois nós são conectados por exatamente um caminho é chamado de árvore e representa uma hierarquia, por exemplo o sistema de arquivos do seu computador. Uma árvore começa na raiz e se ramifica em subárvores que terminam em nós folha. Nós pais podem ter qualquer número de nós filhos, mas muitas vezes as árvores binárias são as mais úteis. Por exemplo, uma árvore binária onde todos os valores à esquerda de qualquer nó são menores e todos os valores à direita são maiores é chamada de árvore de busca binária, o que torna encontrar valores específicos super rápido. Se você quer encontrar um valor alvo, basta começar na raiz. Se o alvo for menor que esse nó, vá para a esquerda, se for maior, vá para a direita, e repita isso até encontrar o alvo. O que acabamos de usar é um algoritmo muito simples, que é apenas um conjunto de instruções que resolve um problema passo a passo. A forma mais simples de escrever um algoritmo é na forma de uma função. Ela recebe entradas, faz algo com elas e retorna uma saída. Assim como as variáveis, você pode então chamar uma função pelo seu nome e passar diferentes argumentos. Ao chamar uma função, a chamada da função é empilhada na pilha de chamadas, que é uma memória de curto prazo usada para executar código, e como o nome sugere, é baseada em uma estrutura de dados de pilha, o que significa último a entrar, primeiro a sair. Para implementar algoritmos, você frequentemente tem que comparar dois valores, o que você pode fazer com operadores como maior que ou igualdade, e expressões lógicas como e, ou, e não. Expressões como essas são simples, podem ser verdadeiras ou falsas, que são os valores possíveis do tipo de dados Booleano e permitem escrever declarações condicionais. Se alguma condição for verdadeira, faça isso, senão faça aquilo. Booleanos também podem ser usados para fazer loop sobre certas partes do código. Uma forma é com um loop while. Enquanto esta condição for verdadeira, este código será executado. Outra forma é com um loop for, que pode iterar sobre cada elemento dentro de uma estrutura de dados como um array, mas também pode fazer loop por um número específico de iterações definindo um valor inicial, incrementando-o após cada iteração e definindo um limite superior com uma condição. Funções também podem chamar a si mesmas, o que é conhecido como recursão. Isso é útil quando um problema pode ser dividido em problemas menores idênticos, como calcular 5 fatorial, que é apenas 5 vezes 4 fatorial, que é apenas 4 vezes Mas, por padrão, uma função recursiva simplesmente continuará se chamando para sempre. Isso significa que ela continua empilhando mais chamadas de função na pilha de chamadas até que a memória da pilha seja excedida em um estouro de pilha. Isso não é o ideal. Para parar isso, você tem que adicionar uma condição base a uma função recursiva que define quando parar. Só então as chamadas de função serão executadas sem travar seu PC. Recursão é legal, mas pode ser bem cara em termos de tempo e espaço. Então, para minimizar a quantidade de computações necessárias, resultados passados podem ser salvos em um cache para que, se aparecerem novamente, o computador não precise recalculá-los do zero. Isso é chamado de memoização. Falando em desempenho, para julgar quão bom um algoritmo é, você pode olhar para a complexidade de tempo e de espaço, ou seja, quanto tempo ou espaço é necessário para executá-lo. Isso é medido em notação Big O, que descreve a relação entre o crescimento do tamanho da entrada e o número de operações necessárias para executar o algoritmo. Por exemplo, adicionar 1 a cada número dentro de um array é O , porque o número de operações aumenta de forma linear conforme o array cresce. O que é relevante não é o número exato de operações, mas sim a tendência conforme o tamanho da entrada vai ao infinito. Veja bem, algo como n fatorial cresce muito mais rápido do que qualquer função linear poderia. Então, desde que a complexidade de tempo seja algum tipo de relação linear, ela é simplificada para O , e a mesma coisa vale para qualquer outro grupo. Ao escrever um algoritmo, sempre há diferentes abordagens. Uma abordagem de força bruta seria simplesmente verificar cada item até encontrarmos um alvo em uma lista. Mas se você quer que seu programa rode mais rápido que um caracol de jardim, você precisa de uma abordagem mais sofisticada como dividir e conquistar. Por exemplo, na busca binária, você verifica repetidamente o elemento do meio para ver de que lado está o alvo e continua buscando nessa metade até encontrá-lo. Além disso, há diferentes abordagens para escrever código em geral, que são chamadas de paradigmas de programação. A programação declarativa descreve o que o código faz, mas não como exatamente o computador deve fazer, enquanto a programação imperativa descreve explicitamente como o computador deve alcançar um resultado com instruções detalhadas. Uma extensão da programação imperativa é a programação orientada a objetos, onde você pode definir classes como plantas para objetos, que são unidades únicas consistindo de dados na forma de propriedades e comportamentos na forma de métodos. Para programar uma classe, você começa definindo as propriedades como variáveis e os métodos como funções. Depois de encapsular propriedades e métodos em uma classe, você pode instanciar um objeto e usar a notação de ponto para trabalhar com suas propriedades e métodos. Classes facilitam organizar e reutilizar código, porque você pode definir subclasses que herdam propriedades e comportamentos de uma superclasse mas também podem estendê-los e sobrescrevê-los. Por exemplo, uma subclasse de pato de borracha pode implementar quack com um guincho em vez disso. Como resultado, patos de borracha podem ser tratados como objetos da classe pato mas se comportam de forma diferente quando quack é chamado, que é o conceito de polimorfismo. Mas para alguns problemas, nenhum desses paradigmas tradicionais funcionará. Digamos que você queira fazer um computador reconhecer qual dessas imagens é uma abelha. O problema é que você não consegue realmente descrever como é uma abelha com código. É aí que entra o aprendizado de máquina, ou seja, ensinar um computador a fazer uma tarefa sem programá-lo explicitamente para fazer essa tarefa. Primeiro, você precisa de muitos dados que você pode dividir em dados de treinamento e dados de teste. Em seguida, você escolhe um algoritmo que pode mudar seus parâmetros ao longo do tempo, por exemplo uma rede neural onde os pesos podem ser atualizados para alcançar um resultado diferente. Alimentando esse algoritmo com muitos e muitos dados de treinamento, você pode construir um modelo cuja precisão você pode então verificar com os dados de teste. Se não estiver bem certo, o modelo pode melhorar ao longo do tempo comparando a saída com o que deveria ter sido, capturando a diferença em uma função de erro e ajustando seus parâmetros para minimizar a diferença. Mas não importa quão futurista, de ponta, extremamente rápido e otimizado seja, se você quer que as pessoas realmente usem o aplicativo que você escreveu, você provavelmente deveria saber sobre a internet. É uma rede de computadores de todo o globo conectados por fios. Tipo, literalmente, a internet é apenas um monte de cabos grossos que correm no fundo do oceano junto com instalações como provedores de serviços de internet que conectam você ao seu destino. Esses computadores se comunicam com a suíte de protocolos da internet. Todo computador na rede tem um endereço IP único, e dois computadores podem então transferir dados com um protocolo de controle de transmissão. Ele quebra mensagens em um monte de pacotes, envia-os por uma rede de fios, antes que o receptor monte a mensagem de volta. Se você tem uma conexão de internet ruim, talvez tenha experimentado perda de pacotes, que é simplesmente quando alguns desses pacotes se perdem no caminho. Se a internet é o hardware, então a web é o software, que você pode usar com um navegador. Toda página na web tem uma URL. Quando você a digita no seu navegador, ele procura o endereço IP do servidor que hospeda este site com um sistema de nomes de domínio, que é como um dicionário mapeando nomes de domínio para endereços IP de servidores reais. Depois de se conectar a ele via TCP, seu navegador, chamado de cliente, usa o protocolo de transferência de hipertexto para enviar uma requisição HTTP ao servidor, que então dá uma resposta, idealmente contendo o conteúdo da página web. O site real na maioria das vezes consiste em três partes. Um arquivo HTML contém todo o conteúdo de um site e é basicamente apenas uma coleção de elementos, que podem ser texto, links, botões e assim por diante. Um arquivo CSS controla os visuais e faz um site parecer bonito. Mas um site é inútil se apertar botões bonitos não faz nada, então uma linguagem como JavaScript adiciona funcionalidade. Mas às vezes, as coisas podem dar errado. Com toda resposta HTTP vem um código de resposta, que carrega informações sobre o status da resposta. Por exemplo, 200 significa OK, e qualquer coisa começando com 4 é um erro, o mais famoso sendo 404, página não encontrada. Requisições HTTP podem carregar diferentes métodos, por exemplo, get, post, put e delete, ou seja, recuperar, adicionar, atualizar e excluir informações. Estes são frequentemente usados por interfaces de programação de aplicativos, que conectam dois aplicativos e permitem que eles interajam entre si. Por exemplo, armazenar e recuperar dados de um banco de dados. O tipo mais comum de banco de dados é um banco de dados relacional, que usa tabelas para armazenar dados. Colunas de uma tabela contêm diferentes atributos, e linhas representam pontos de dados individuais. Além disso, cada tabela tem um atributo único chamado de chave primária. Uma chave estrangeira é a chave primária de outra tabela estabelecendo uma relação entre as duas. Neste caso, cada livro está conectado a um autor. Com uma linguagem como SQL, você pode escrever declarações para trabalhar com dados dessas tabelas. Você poderia procurar os títulos e autores de todos os livros cujo título começa com H, mas para isso temos que juntar a tabela de autores com a tabela de livros na chave correspondente para combinar dois atributos de tabelas diferentes em um, nos dando esta saída. Essas declarações são úteis, mas você tem que ter cuidado ou pode simplesmente excluir um banco de dados inteiro com uma linha de código. Mas não se preocupe, isso nunca aconteceu antes. Atrás de toda página de login está um banco de dados com nomes de usuário e senhas. Quando um usuário tenta fazer login, uma consulta SQL é frequentemente usada para verificar se a entrada do usuário corresponde a uma entrada no banco de dados. Isso é bom. Mas um ator malicioso poderia digitar algo assim, que muda a consulta terminando a string antecipadamente e comentando o resto, o que significa que desde que este nome de usuário exista no banco de dados, o acesso é concedido. Isso é chamado de ataque de injeção SQL, e é uma das formas mais fáceis de hackers chegarem a lugares onde não deveriam. Ouvir sobre esses conceitos é uma coisa, mas para realmente aprendê-los você tem que vê-los em ação e usá-los você mesmo, que é exatamente o que você pode fazer com o Brilliant, que tem milhares de lições interativas para tudo, desde matemática e ciência de dados até programação e IA. Eles fazem o conhecimento grudar, com lições visuais e problemas interativos, o que não só é divertido e constrói habilidades intuitivas de resolução de problemas, mas também é comprovadamente seis vezes mais eficaz do que simplesmente assistir horas de palestras. Eu sei que arranjar tempo para aprender novas habilidades pode ser difícil, mas o Brilliant torna tudo tão fácil. Você pode construir conhecimento valioso do zero em apenas alguns minutos por dia, com lições curtas de qualquer dispositivo, em qualquer lugar, a qualquer hora. Você vai dos fundamentos da ciência de dados à análise de conjuntos de dados reais do Spotify em absolutamente nenhum tempo, o que você pode complementar com fundamentos de matemática e cursos de programação em Python para construir um dos conjuntos de habilidades mais procurados do nosso tempo. A melhor parte? Você pode experimentar tudo o que o Brilliant tem a oferecer de graça por 30 dias completos visitando brilliant.org barra wackyscience. Você também ganha 20% de desconto em uma assinatura premium anual. Obrigado ao Brilliant por patrocinar este vídeo.
Criado 30 de jan.
Atualizado 9 de ago.
Publicado 30 de jan.