Heim Entwicklungswerkzeuge composer Sie können Komponisten schnell lernen!

Sie können Komponisten schnell lernen!

Jul 04, 2020 pm 01:21 PM
composer

Die folgende Tutorial-Kolumne von Composer zeigt Ihnen, wie man Composer lernt. Ich hoffe, dass es für Freunde hilfreich ist, die es brauchen!

Sie können Komponisten schnell lernen!

Wenn das System über verschiedene Webanwendungen verfügt, diese aber benötigt werden geteilt werden Was mit viel Code zu tun ist
Wenn das System eine erweiterte Funktion benötigt und jemand im Internet zufällig bereitgestellt hat, wie man sie verwendet
Wie man PHP-Code aktualisiert, herabstuft und zurücksetzt
Wie wie man Aufgaben verteilt und wie man mehrere Ingenieure zusammenarbeiten lässt. Entwicklungsaufgaben

Ich kam 2011 mit PHP in Kontakt, als V5.3.5 gerade veröffentlicht wurde. Auf sprachlicher Ebene glaube ich nicht, dass PHP allzu offensichtliche Mängel aufweist. Auf der Grundlage unserer umfangreichen weborientierten Funktionsbibliothek verfügen wir auch über Klassen, SPL, anonyme Funktionen usw. Diese Funktionen (überhaupt nicht „besonders“) reichen aus, um die Codierungsanforderungen eines großen Projekts zu unterstützen.

Sie können Komponisten schnell lernen!
PHP5.3

Wenn wir jedoch tatsächlich Code in PHP entwickeln und schreiben wollen, stoßen wir oft auf einige verrückte Probleme, diese Probleme haben nichts damit zu tun mit PHP machen. Aber es bereitet immer noch Kopfschmerzen. Wenn wir eine Website schreiben möchten, benötigen wir möglicherweise einen Bestätigungscode, aber in den meisten Fällen möchte ich selbst keinen Bestätigungscode schreiben. Es gibt so viele Arten von Bestätigungscodes im Internet, dass ich sie natürlich direkt verwenden möchte. Aber wenn ich es direkt verwenden möchte, muss ich Folgendes tun:

  1. Gehen Sie zur Suchmaschine, um zu suchen, und prüfen Sie dann, ob in jedem Ergebnis ein geeigneter Code vorhanden ist, der verwendet werden kann Mich.
  2. Ich habe eine Klasse gefunden. Jetzt muss ich diese Klasse in mein Projekt einfügen. Wie lade ich automatisch? Hängt es von irgendwelchen Erweiterungen ab? Muss es auf einer höheren PHP-Version verwendet werden, als ich derzeit verwende? Das sind alles Probleme, die ich lösen möchte.
  3. Wenn ich alle unter 2 genannten Probleme lösen möchte, warum schreibe ich dann nicht einfach eines?
  4. Scheiß drauf

Auch wenn ich meinen eigenen Code verwende, wenn ich mehrere Webanwendungen habe (Computerseite, WAP-Seite, API-Schnittstelle ist normal), natürlich ich Ich hoffe, dass sie sich nicht in einem Projekt (Verzeichnis) befinden, wodurch es für mich schwieriger wird, die angegebenen Dateien anzuzeigen, und dadurch auch meine Wartungskosten steigen. Aber als ich diese Webanwendungen trennte, gab es so viele gemeinsame Codes (Modell, Logik, Authentifizierung ...), wie soll ich mit diesen Codes umgehen, wenn ich eine kleine Logik einer Webanwendung ändere? Bei anderen Anwendungen kann ich mich entweder nicht daran erinnern, oder selbst die kleinste Änderung löst in mir den Wunsch aus, den Computer kaputt zu machen, meinen Job zu kündigen oder rauszugehen, um mich zu entspannen.

Okay, ich werde diese Codes aufteilen und sie durch automatisches Laden miteinander verwenden. Dadurch können auch mehr Leute an der Entwicklung teilnehmen, aber die Online-Situation ist so kompliziert, falls es ein Problem damit gibt Codestück, falls es eine spezielle Webanwendung gibt und der neue Code nicht darauf anwendbar ist. Auch die Wartung stellt ein Problem dar, wenn Sie eine Webanwendung übernehmen, die auf vielen anderen Projekten basiert, kann es zu großen Problemen kommen, wenn Sie den Code geringfügig ändern, da der Autoload-Code es für Benutzer schwierig macht, intuitiv zu verstehen, wie die Webanwendung funktioniert Welcher Code für welche anderen Projekte verwendet wird.

Aber wenn es um PHP geht, möchte ich es nicht kaputt machen, weil es so bequem zu schreiben ist. Ich möchte der Falle noch nicht entkommen. Wenn die oben genannten Probleme jedoch nicht gelöst werden, ist das Schreiben von PHP meiner Meinung nach immer noch eine sehr frustrierende Sache. Mal sehen, wie andere Sprachen dieses Problem lösen. Der natürliche Verpackungsmechanismus von JAVA ermöglicht die Verwendung von Maven, Node's NPM und sogar Perl, das älter als PHP ist, verfügt über CPAN. Sollte PHP nicht über einen Paketverwaltungsmechanismus verfügen?

Glücklicherweise begleiteten diese Probleme meine PHP-Zeit nicht allzu lange, denn bald hatte PHP Composer und die Sonne dämmerte.

Composer ist ein Abhängigkeitsmanagement-Tool für PHP. Sie können damit Codebibliotheken deklarieren, von denen Ihr Projekt abhängt, und diese für Sie in Ihrem Projekt installieren.

Dies ist die Einführung der offiziellen chinesischen Website von Composer.

Ich versuche diesen Satz aus meiner Erfahrung zu erklären.

Es ermöglicht Ihnen, die Codebasis zu deklarieren, von der das Projekt abhängt. Das bedeutet, dass Sie den Code nicht mehr selbst kopieren müssen, sondern ihn einfach durch eine Deklaration mitteilen können Sie müssen dem Koch nicht beibringen, wie man es zubereitet, geschweige denn selbst kochen, und Sie müssen den Teller nicht selbst servieren und essen. Sagen Sie stattdessen dem Kellner, was Sie möchten Essen Sie, sagen Sie ihm einfach, dass ich heute Magenbeschwerden habe. Bitte kochen Sie mir etwas Leichteres. Ich bestelle sowieso nie welches Gericht Sie essen möchten und den genauen Namen des Gerichts. Das ist der Unterschied zur vorherigen Suche nach Code in einer Suchmaschine. Sie können Composer nicht über Schlüsselwörter informieren, sondern müssen ihm den Namen der gewünschten Codebibliothek mitteilen. Wie kann ich den Namen des Codes erfahren? Es ist für niemanden möglich, den Namen der Codes anderer Personen zu kennen, es sei denn, es gibt einen Ort, der alle Codes enthält und eine Suchfunktion bietet, mit der wir sie finden und ihre Namen kennen können 🎜>packagist.org macht das. Dies. Wir sind nicht mehr auf Glück angewiesen, um in verschiedenen Suchmaschinen zu suchen. Bei der Suche nach Schlüsselwörtern werden hier keine Anzeigen geschaltet, weder Putian noch JD.

Es wird sie für Sie in Ihrem Projekt installieren: Nachdem Sie es Composer mitgeteilt haben, hilft uns Composer natürlich dabei, das Geschirr zu bringen. Das ist etwas, das jeder verstehen kann, der Code, den wir wollen. Wir wissen nicht, um welchen Server es sich handelt aktiviert, aber Composer hilft uns beim lokalen Herunterladen. Hier stellt sich jedoch noch die Frage, wie man es nach dem Herunterladen verwendet. Wenn Sie eine Datei in PHP verwenden möchten, müssen Sie diese einbinden oder benötigen Bereiten Sie Ihre eigenen Schüsseln und Essstäbchen vor? Glücklicherweise gibt es eine andere gute Sache namens PHP-FIG. Diese Sache erzeugt keinen Code und bietet keine Lösungen für praktische Probleme. Das Einzige, was er tut, ist Grillen, also worüber grillt er? Wie ich oben sagte, ist es für die PHP-Entwicklung aufgrund des Fehlens einiger grundlegender Tools (z. B. Composer) schwierig, einige Standards zu haben, z. B. Codierungsstandards, z. B. die Verzeichnisstruktur, z. B. das automatische Laden von Klassen, z Wie wird protokolliert, wie wird beispielsweise der Cache verwendet? Wozu führt das? Verschiedene Unternehmen und verschiedene PHP-Programmierer werden beginnen, ihre magischen Kräfte zu zeigen. Kurzfristig wird dies natürlich keine Rolle spielen, aber auf lange Sicht werden die Entwicklungskosten und Wartungskosten steigen, wenn wir zu einem anderen Unternehmen wechseln Wenn wir ein Projekt übernehmen, müssen wir den Code von Grund auf verstehen. Selbst im Team erhöhen wir die Kommunikationskosten, weil es keine Standards gibt. PHP-FIG macht also genau das: setzt Standards. Zu den von ihm formulierten Standards gehören:

    Codierungsspezifikationen (
  1. psr-1)psr-2
  2. Auto-Loading-Spezifikationen (
  3. )psr-4
  4. Einige gemeinsame Schnittstellenprotokolle (
  5. ) Cache(psr-3) http(psr-6)psr-7
Diese Standards werden auf der offiziellen Website ausführlich beschrieben. Was wir hier besprechen werden, ist PSR-4. Ich werde hier auf der Grundlage meines eigenen Verständnisses und meiner Erfahrung näher darauf eingehen: Das automatische Laden von psr-4 basiert auf Ordnern und Namespaces. Wir müssen angeben, dass ein Root-Namespace einem Root-Namespace entspricht und Klassennamen außerhalb des Namespace, um diese PHP-Datei im Stammordner zu finden und

#根文件夹 lib#根命名空间 model#file lib/A.phpnamespace model;class A {}#file lib/entity/B.phpnamespace mode\entity;class B{}#file demo.php$a = new \model\A();$b = new \model\entity\B();
Nach dem Login kopieren
zu laden. Der Composer kann erkennen, dass sie auf bestimmten Standards (z. B.

) und Zuordnungsbeziehungen (z. B. in) basieren kann Code lib->model), um die Funktion zum automatischen Laden von Klassen zu generieren. Tatsächlich stellt Composer diese Standards bereit: psr-4

Dateien geben den Pfad zur PHP-Datei an. Diese Methode lädt diese Dateien bei jeder Anforderung, geeignet für PHP-Dateien einiger gängiger Funktionen

Classmap ist intelligenter Als Dateien kann ein Ordner oder eine Datei für das automatische Laden angegeben werden. Der Nachteil besteht darin, dass Composer die Autoload-Datei neu generieren muss, selbst wenn ein Ordner angegeben ist -4-Klassen oder Klassenbibliotheken, z. B. ein Schnittstellen-Client eines Drittanbieters. Dieser Client existierte möglicherweise bereits vor dem Erscheinen der psr-4-Regeln, daher möchten wir ihn weiterhin mit Composer verwalten, damit wir diese Methode verwenden können

Der Vorgänger von psr-0 war vorher veraltet, tun Sie einfach so, als hätte ich es nicht gesagt psr-4
Wie ich oben bereits erwähnt habe, erfordert das Hinzufügen einer oder mehrerer Dateien auf diese Weise keine Neugenerierungpsr-4 Datei weil es entsprechend der Zuordnung zwischen Namespace und Ordner geladen wird. autoload

Was sind also die Vorteile, wenn Composer dies implementiert?

Wir müssen selbst keine Autoload-Dateien schreiben. Gleichzeitig ist dieser Standard leicht zu verstehen und zu akzeptieren, und auch die Kosten für die Wartung und das Erlernen des Codes werden reduziert

Solange Die von uns benötigten Bibliotheken von Drittanbietern verwenden Composer auch zum automatischen Laden. Wir benötigen nur dieses Paket, dann verarbeitet Composer auch den Code, der diese Bibliothek von Drittanbietern lädt. Wir haben eine superleistungsfähige Autoload-Datei

Was wir also tun müssen, ist zu lernen, mit Composer umzugehen und dann anfangen, Code von Entwicklern aus der ganzen Welt zu genießen.

就像上面描述的,Composer就像一个机器猫,你要什么它就给什么,那么交互的方式就类似于SQL语句那样,告诉它你要什么然后它给你结果。所以我们要做的就是描述需求,也就是当产品经理,好过瘾。

{
    "name": "fmw/test",
    "description": "fmw test",
    "authors": [
        {
            "name": "zzc",
            "email": "2272713550@qq.com"
        }
    ],
    "repositories": [
        {
            "type": "composer",
            "url": "http://package.fmw.com"
        }
    ],
    "version":"1.0.106",
    "require": {
        "fmw/other-layer":"1.*",
        "fmw/common":"1.*"
    },
    "require-dev":{
        "php-console/php-console": "^3.1",
        "phpdocumentor/phpdocumentor": "2.*"
    },
    "autoload":{
        "psr-4":{
            "model\\":"src/"
        }
    }
}
Nach dem Login kopieren

以上代码是一个我用过的composer配置文件,可以看出这是一个标准的json。我们来看一下这段json的每个key:

name和description是你给这个php项目起的名字,当这个项目仅仅是一个web项目,这两个其实不是很重要,但是这个项目其实是一个向外发布的代码库,就很关键了,name需要独一无二,description需要一句话来描述这个包的作用。

authors就是相当于宣布一下主权,可以有多个

repositories相当于你需要下载的代码库所在的仓库,默认会有一个全局的仓库,具体是什么就不在这里说了,上面的某个网址有介绍,在这里添加一个是因为如果你有个私人的仓库(有些代码不太适合放在公开的仓库吧),则可以在这里声明

version是版本号,这个是跨时代的功能啊,有了这个,PHP程序员也可以刷版本号了啊!

require则是上面阐述了很多的功能,解决了我说的那些痛点,通过“name”:"version"声明,可以有多个,require以后使用composer install命令composer会下载代码并自动加载
require-dev用法一致,但是功能不同,是用来声明一些在开发时候才用到的包,比如测试、文档等等

autoload 上面有介绍,就不废话

上面工作做完以后,执行composer install我们可以看到和composer.json同级的文件夹下生成了一个vendor文件夹,我们新建一个php文件引入vendor下的autoload.php文件就可以使用包和我们自己声明的autoload的php文件了
#index.php

include ‘./vendor/autoload.php’;

到这里,我们就算会用了composer,至于如何使用composer的功能就不拾人牙慧了,但是还有一些问题想讨论一下。

比如有些代码不太适合放在公开的仓库,但是我们还是希望包的形式来使用,毕竟这样的话,一个公司内部就很容易分工了,每一个PHP程序员维护若干个包,多方便,所以建立一个内部的代码仓库是很重要的。这时候Composer官方提供的工具satis就可以发挥作用了。

Simple static Composer repository generator

这是它的介绍,一个简单的Composer仓库生成器。使用它的步骤如下:

在合适的目录执行 php composer.phar create-project composer/satis --stability=dev --keep-vcs(前提是你已经按照Composer)
新建一个satis.json 实例如下

{
    "name": "My Repository",
    "homepage": "http://packages.dev.com",
    "repositories": [
        {"type": "vcs", "url": "http://git.dev.com/maxincai/package1.git"},
        {"type": "vcs", "url": "http://git.dev.com/maxincai/package1.git"},
    ],
    "require": {
        "maxincai/package1": "*",
        "maxincai/package2": "*",
    }
}
Nach dem Login kopieren

执行 php bin/satis build satis.json public/(public就是所有包的存放目录)
将public目录作为一个web服务对外发布就好了

使用的时候只需要在repositories多加一项(就像我在上面的composer.json做的那样),然后引入包就好了

关于Composer,上面就是我目前要说的了,通过Composer我们可以将业务逻辑、通用函数、逻辑拆分成不同的包,再也不需要做拷贝代码的蠢事了。

Das obige ist der detaillierte Inhalt vonSie können Komponisten schnell lernen!. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn

Heiße KI -Werkzeuge

Undresser.AI Undress

Undresser.AI Undress

KI-gestützte App zum Erstellen realistischer Aktfotos

AI Clothes Remover

AI Clothes Remover

Online-KI-Tool zum Entfernen von Kleidung aus Fotos.

Undress AI Tool

Undress AI Tool

Ausziehbilder kostenlos

Clothoff.io

Clothoff.io

KI-Kleiderentferner

AI Hentai Generator

AI Hentai Generator

Erstellen Sie kostenlos Ai Hentai.

Heißer Artikel

R.E.P.O. Energiekristalle erklärten und was sie tun (gelber Kristall)
4 Wochen vor By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Beste grafische Einstellungen
4 Wochen vor By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. So reparieren Sie Audio, wenn Sie niemanden hören können
4 Wochen vor By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25: Wie man alles in Myrise freischaltet
1 Monate vor By 尊渡假赌尊渡假赌尊渡假赌

Heiße Werkzeuge

Notepad++7.3.1

Notepad++7.3.1

Einfach zu bedienender und kostenloser Code-Editor

SublimeText3 chinesische Version

SublimeText3 chinesische Version

Chinesische Version, sehr einfach zu bedienen

Senden Sie Studio 13.0.1

Senden Sie Studio 13.0.1

Leistungsstarke integrierte PHP-Entwicklungsumgebung

Dreamweaver CS6

Dreamweaver CS6

Visuelle Webentwicklungstools

SublimeText3 Mac-Version

SublimeText3 Mac-Version

Codebearbeitungssoftware auf Gottesniveau (SublimeText3)

Erweiterte Funktionen von Composer: Aliase, Skripte und Konfliktlösung Erweiterte Funktionen von Composer: Aliase, Skripte und Konfliktlösung Jun 03, 2024 pm 12:37 PM

Composer bietet erweiterte Funktionen, darunter: 1. Aliase: Definieren Sie praktische Namen für Pakete zur wiederholten Bezugnahme. 2. Skripte: Führen Sie benutzerdefinierte Befehle aus, wenn Sie Pakete installieren/aktualisieren, die zum Erstellen von Datenbanktabellen oder zum Kompilieren von Ressourcen verwendet werden , Zufriedenheitsbeschränkungen und Paketaliase lösen die unterschiedlichen Anforderungen mehrerer Pakete für dieselbe Abhängigkeitsversion auf, um Installationskonflikte zu vermeiden.

Agile Entwicklung und Betrieb der PHP-Microservice-Containerisierung Agile Entwicklung und Betrieb der PHP-Microservice-Containerisierung May 08, 2024 pm 02:21 PM

Antwort: PHP-Microservices werden mit HelmCharts für eine agile Entwicklung bereitgestellt und mit DockerContainer für Isolation und Skalierbarkeit in Containern verpackt. Detaillierte Beschreibung: Verwenden Sie HelmCharts, um PHP-Microservices automatisch bereitzustellen, um eine agile Entwicklung zu erreichen. Docker-Images ermöglichen eine schnelle Iteration und Versionskontrolle von Microservices. Der DockerContainer-Standard isoliert Microservices und Kubernetes verwaltet die Verfügbarkeit und Skalierbarkeit der Container. Verwenden Sie Prometheus und Grafana, um die Leistung und den Zustand von Microservices zu überwachen und Alarme und automatische Reparaturmechanismen zu erstellen.

Was sind die gängigen Methoden zum Konvertieren von Arrays in Objekte in PHP? Was sind die gängigen Methoden zum Konvertieren von Arrays in Objekte in PHP? Apr 28, 2024 pm 10:54 PM

So konvertieren Sie ein PHP-Array in ein Objekt: Verwenden Sie die Klasse stdClass, verwenden Sie die Funktion json_decode(), verwenden Sie eine Bibliothek eines Drittanbieters (z. B. die Klasse ArrayObject, die Bibliothek Hydrator).

PHP-Code-Versionskontrolle und Zusammenarbeit PHP-Code-Versionskontrolle und Zusammenarbeit May 07, 2024 am 08:54 AM

PHP-Code-Versionskontrolle: Es gibt zwei Versionskontrollsysteme (VCS), die üblicherweise in der PHP-Entwicklung verwendet werden: Git: verteiltes VCS, bei dem Entwickler Kopien der Codebasis lokal speichern, um die Zusammenarbeit und Offline-Arbeit zu erleichtern. Subversion: Zentralisiertes VCS, die einzige Kopie der Codebasis wird auf einem zentralen Server gespeichert und bietet so mehr Kontrolle. VCS hilft Teams, Änderungen zu verfolgen, zusammenzuarbeiten und auf frühere Versionen zurückzusetzen.

Die Rolle von PHP CI/CD in DevOps-Projekten Die Rolle von PHP CI/CD in DevOps-Projekten May 08, 2024 pm 09:09 PM

PHPCI/CD ist eine Schlüsselpraxis in DevOps-Projekten, die die Erstellungs-, Test- und Bereitstellungsprozesse automatisiert und dadurch die Entwicklungseffizienz und Softwarequalität verbessert. Eine typische PHPCI/CD-Pipeline besteht aus den folgenden Phasen: 1) Kontinuierliche Integration: Immer wenn sich der Code ändert, wird der Code automatisch erstellt und getestet. 2) Kontinuierliche Bereitstellung: Beschleunigen Sie die Bereitstellung, indem Sie getesteten und integrierten Code automatisch in der Produktionsumgebung bereitstellen. Durch die Implementierung der PHPCI/CD-Pipeline können Sie die Entwicklungseffizienz steigern, die Softwarequalität verbessern, die Markteinführungszeit verkürzen und die Zuverlässigkeit verbessern.

Visualisierungstechnologie der PHP-Datenstruktur Visualisierungstechnologie der PHP-Datenstruktur May 07, 2024 pm 06:06 PM

Es gibt drei Haupttechnologien zur Visualisierung von Datenstrukturen in PHP: Graphviz: ein Open-Source-Tool, das grafische Darstellungen wie Diagramme, gerichtete azyklische Diagramme und Entscheidungsbäume erstellen kann. D3.js: JavaScript-Bibliothek zum Erstellen interaktiver, datengesteuerter Visualisierungen, zum Generieren von HTML und Daten aus PHP und zum anschließenden Visualisieren auf der Clientseite mithilfe von D3.js. ASCIIFlow: Eine Bibliothek zur Erstellung textueller Darstellungen von Datenflussdiagrammen, geeignet zur Visualisierung von Prozessen und Algorithmen.

Wie verwende ich PHP CI/CD für eine schnelle Iteration? Wie verwende ich PHP CI/CD für eine schnelle Iteration? May 08, 2024 pm 10:15 PM

Antwort: Verwenden Sie PHPCI/CD, um eine schnelle Iteration zu erreichen, einschließlich der Einrichtung von CI/CD-Pipelines sowie automatisierten Test- und Bereitstellungsprozessen. Richten Sie eine CI/CD-Pipeline ein: Wählen Sie ein CI/CD-Tool aus, konfigurieren Sie das Code-Repository und definieren Sie die Build-Pipeline. Automatisierte Tests: Schreiben Sie Unit- und Integrationstests und verwenden Sie Test-Frameworks, um das Testen zu vereinfachen. Praktischer Fall: Verwendung von TravisCI: Installieren Sie TravisCI, definieren Sie die Pipeline, aktivieren Sie die Pipeline und sehen Sie sich die Ergebnisse an. Implementieren Sie Continuous Delivery: Wählen Sie Bereitstellungstools aus, definieren Sie Bereitstellungspipelines und automatisieren Sie die Bereitstellung. Vorteile: Verbessern Sie die Entwicklungseffizienz, reduzieren Sie Fehler und verkürzen Sie die Lieferzeit.

Wie verwende ich den Redis-Cache bei der PHP-Array-Paginierung? Wie verwende ich den Redis-Cache bei der PHP-Array-Paginierung? May 01, 2024 am 10:48 AM

Durch die Verwendung des Redis-Cache kann die Leistung des PHP-Array-Pagings erheblich optimiert werden. Dies kann durch die folgenden Schritte erreicht werden: Installieren Sie den Redis-Client. Stellen Sie eine Verbindung zum Redis-Server her. Erstellen Sie Cache-Daten und speichern Sie jede Datenseite in einem Redis-Hash mit dem Schlüssel „page:{page_number}“. Rufen Sie Daten aus dem Cache ab und vermeiden Sie teure Vorgänge auf großen Arrays.

See all articles