mirror of
https://github.com/avinal/avinal.github.io.git
synced 2026-07-03 23:30:09 +05:30
Add part 2 of the redhat blog
Signed-off-by: Avinal Kumar <avinkuma@redhat.com>
This commit is contained in:
@@ -44,7 +44,7 @@ GitHub Actions CI/CD
|
||||
:width: 350
|
||||
|
||||
Since the FOSSology project moved on Github, it has used only the free Travis CI service for OSS projects.
|
||||
At the time of writing the Travis CI has reduced its free tier CI services. GitHub Actions provides faster builds. Since GitHub Actions is a fully managed service by GitHub, we don’t need to know how to scale and operate the infrastructure to run it.
|
||||
At the time of writing Travis CI has reduced its free tier CI services. GitHub Actions provides faster builds. Since GitHub Actions is a fully managed service by GitHub, we don’t need to know how to scale and operate the infrastructure to run it.
|
||||
|
||||
It is straightforward to use with GitHub because when we fork a repository, the actions automatically get forked. This allows you to test and build projects very efficiently and even run them closer to the developer. Also, you have readily available access to the GitHub API, making it more popular among developers.
|
||||
|
||||
@@ -205,8 +205,8 @@ Deliverables
|
||||
|
||||
|
||||
|
||||
How it works and how to use it?
|
||||
-------------------------------
|
||||
How does it work and how to use it?
|
||||
-----------------------------------
|
||||
|
||||
.. raw:: html
|
||||
|
||||
@@ -252,7 +252,7 @@ Each agent is a complete CMake sub-project with its independent configuration fo
|
||||
└── CMakeLists.txt # FOSSology Top-level CMake configuration
|
||||
|
||||
|
||||
The :code:`cmake` directory contains customized CMake modules and templates for FOSSology. This directory is required for all the operations. The general workflow of the new build system as well as how to use it as described below.
|
||||
The :code:`cmake` directory contains customized CMake modules and templates for FOSSology. This directory is required for all the operations. The general workflow of the new build system as well as how to use it is described below.
|
||||
|
||||
1. Since the new build system is still in review. You must fork FOSSology and pull the `#2075 <https://github.com/fossology/fossology/pull/2075>`_ pull request branch. Once you are in FOSSology root, run these commands.
|
||||
|
||||
@@ -331,7 +331,7 @@ The :code:`cmake` directory contains customized CMake modules and templates for
|
||||
ninja install
|
||||
|
||||
|
||||
6. While testing has some issues, but most of the testing is working fine. For now, you must build and run any test from the FOSSology root directory only. You can choose to configure a single agent if you want to test one agent only. See :code:`ctest --help` for controlling test runs.
|
||||
6. While testing has some issues, most of the testing is working fine. For now, you must build and run any test from the FOSSology root directory only. You can choose to configure a single agent if you want to test one agent only. See :code:`ctest --help` for controlling test runs.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
@@ -380,13 +380,13 @@ Although the transition from Makefiles to CMake and Travis CI to GitHub Actions
|
||||
- Running tests locally may require switching to :code:`fossy` user.
|
||||
- While configured for testing, it may give permission errors.
|
||||
- Scheduler, Ununpack, and Delagent unit and functional tests are not working. I have added an issue `#2084 <https://github.com/fossology/fossology/issues/2084>`_ to track the progress on fixing these tests.
|
||||
- CMake doesn't generates uninstall targets. The closest thing to uninstall is `this snippet <https://gitlab.kitware.com/cmake/community/-/wikis/FAQ#can-i-do-make-uninstall-with-cmake>`_. This will be later added to the FOSSology.
|
||||
- CMake doesn't generate uninstall targets. The closest thing to uninstall is `this snippet <https://gitlab.kitware.com/cmake/community/-/wikis/FAQ#can-i-do-make-uninstall-with-cmake>`_. This will be later added to the FOSSology.
|
||||
|
||||
|
||||
Challenges Faced
|
||||
----------------
|
||||
|
||||
While this whole project was challenging, some aspects of it were unforeseen and more challenging. When I decided to go on with this project I just had enough CMake knowledge to write a configuration for a very small project. I had never used CMake on this big scale. On the other side, the FOSSology community is largely unknown to CMake so for all of us it was learn, practice, and implement. With support from mentors, I was able to overcome this challenge with flying colors.
|
||||
While this whole project was challenging, some aspects of it were unforeseen and more challenging. When I decided to go on with this project I just had enough CMake knowledge to write a configuration for a very small project. I had never used CMake on this big scale. On the other side, the FOSSology community is largely unknown to CMake so for all of us it was learned, practiced, and implement. With support from mentors, I was able to overcome this challenge with flying colors.
|
||||
|
||||
The other challenge was to understand the old build system, how they are all connected and what is the flow. The complexity can be imagined by the fact that the most of code and configurations were written in the decade before the last decade and haven't changed much since then.
|
||||
|
||||
@@ -428,5 +428,5 @@ First of all, I want to thank and appreciate my mentors `Gaurav Mishra <https://
|
||||
|
||||
I want to thank my friend and :abbr:`fellow participant (Integrating ScanCode Toolkit to FOSSology)` `Sarita <https://github.com/itssingh>`_. Thank you for being a collaborator, support, and motivation for attempting GSoC.
|
||||
|
||||
Finally, I want to thanks, my family and friends. I got to meet many awesome developers as my fellow participants from around the world, I wish we will do more collaboration in the future.
|
||||
Finally, I want to thank, my family and friends. I got to meet many awesome developers as my fellow participants from around the world, I wish we will do more collaboration in the future.
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
:tags: HRT, hudsonrivertrading, interview, internship
|
||||
:slug: hrt-interview-1
|
||||
:category: blog
|
||||
:summary: I applied for **Systems Internship - Summer 2021** back in December 2020 at `Hudson River Trading <https://www.hudsonrivertrading.com>`_ , New York....Questions were clear and of medium level. But they were designed in such a way that you must know the basics before you could attempt.
|
||||
:summary: I applied for **Systems Internship - Summer 2021** back in December 2020 at `Hudson River Trading <https://www.hudsonrivertrading.com>`_ , New York.....Questions were clear and of medium level. But they were designed in such a way that you must know the basics before you could attempt.
|
||||
|
||||
I applied for **Systems Internship - Summer 2021** back in December 2020 at `Hudson River Trading <https://www.hudsonrivertrading.com>`_ , New York. The internship description was: -
|
||||
|
||||
@@ -24,9 +24,8 @@ I applied for **Systems Internship - Summer 2021** back in December 2020 at `Hud
|
||||
* Data Storage
|
||||
* Large deployment or config management
|
||||
|
||||
The first step was a coding test on Codility platform. If you have used any of the online coding platforms, this is similar. It was a
|
||||
:abbr:`2.5 hrs (90 mins)` test consisting of 3 questions. They let you use :abbr:`online references (documentation, man pages etc.)` but
|
||||
**do not copy the code** as it will highly reduce your chances of qualifying this first stage. You can choose between **C/C++**,
|
||||
The first step was a coding test on the Codility platform. If you have used any of the online coding platforms, this is similar. It was a :abbr:`2.5 hrs (90 mins)` test consisting of 3 questions. They let you use :abbr:`online references (documentation, man pages, etc.)` but
|
||||
**do not copy the code** as it will highly reduce your chances of qualifying for this first stage. You can choose between **C/C++**,
|
||||
**Python** and **Golang** (no Java 😪).
|
||||
|
||||
Questions were clear and of medium level. But they were designed in such a way that you must know the basics before you could attempt.
|
||||
@@ -38,28 +37,28 @@ Also, they expected a clear and concise approach. Two of the most important poin
|
||||
* Please understand that this test is meant to be challenging. A perfect score is not necessary to move on to future interview rounds, so do the best you can!
|
||||
|
||||
|
||||
So, you must be near perfect in your approach as well as on time. I did them kind of quickly. They will show you a summery about your
|
||||
So, you must be near perfect in your approach as well as on time. I did them kind of quickly. They will show you a summary of your
|
||||
submission but not the results. It will take almost 2 weeks to get back to you for further steps.
|
||||
|
||||
Next, I received a mail invitation for a telephonic interview. **This interview will last about 45 minutes and will be technical but will not require coding. Interview topics may include your background, programming languages, and Unix/Linux concepts**. Once you receive this
|
||||
mail you can then decide a time slot for interview.
|
||||
mail you can then decide a time slot for an interview.
|
||||
|
||||
I was not sure what they will ask if this is not a coding interview. The interviewer was very polite, and he was explaining the questions
|
||||
too. Questions were not so tricky but practical and real-life. Since it was **not for SDE role**, the questions were mostly related to
|
||||
Linux/Unix, C++ (mainly pointers and memory), Python/Bash scripting, automation, knowledge of tools (IDEs, Editors, System Administration
|
||||
Tools) and previous experiences. The interview would often explain why he is asking this question, this was very nice. Then some common
|
||||
interview questions, why you want to work for this role? What makes you fit for this role? etc.
|
||||
interview questions, why do you want to work for this role? What makes you fit for this role? etc.
|
||||
|
||||
One thing that I want to point out is that the interviewer was repeatedly checking my resume, and for the most part he did not ask
|
||||
anything that was not on my resume. So, my tip is to create a nice resume with genuine work/tool experiences. And when you are applying
|
||||
for such role, it would be helpful if you mention mathematics or other courses that you have taken. *Do not lie on your resume*. They
|
||||
for such a role, it would be helpful if you mention mathematics or other courses that you have taken. *Do not lie on your resume*. They
|
||||
will easily catch that.
|
||||
|
||||
The other thing is to keep your words short and clear; I was not great at communication, but you can be. If the interviewer allows then
|
||||
use examples for the things you cannot explain. I used nice examples. At last, he gave me a short feedback of how well I performed.
|
||||
use examples for the things you cannot explain. I used nice examples. At last, he gave me short feedback on how well I performed.
|
||||
|
||||
At last, I want to point out things I should not have done. The first is, I did not ask much about the role, you must do this at least
|
||||
once. Second, I am talkative, I do not know if interviewer was not faking his expressions (because he would often discuss in depth),
|
||||
but not all interviewers will be same. So, do not talk too much, neither too less. At last work on your communication skill, mostly how
|
||||
you present things and how to answer technical as well as behavioral questions. I was not fluent, but my way of presentation might
|
||||
once. Second, I am talkative, I do not know if the interviewer was not faking his expressions (because he would often discuss in-depth),
|
||||
but not all interviewers will be the same. So, do not talk too much, nor too less. At last work on your communication skill, mostly how
|
||||
you to present things and how to answer technical as well as behavioral questions. I was not fluent, but my way of presentation might
|
||||
have saved me.
|
||||
|
||||
@@ -12,7 +12,7 @@ My internship at Red Hat |redhat_logo|
|
||||
:slug: i-am-loving-it-redhat
|
||||
:category: development
|
||||
:tags: kubernetes, redhat, docker, golang, tekton, openshift, intern
|
||||
:summary:
|
||||
:summary: I made it to the Red Hat as a DevTools intern. This post is about onboarding and how I prepared myself for working on the actual project.
|
||||
|
||||
|
||||
I have been contributing to open source for the last 3 years and Red Hat was one of the companies that I was very fond of. I must say all my contributions and consistency paid off, and I made it to the Red Hat as a DevTools intern. This post is about onboarding and how I prepared myself for working on the actual project.
|
||||
@@ -21,7 +21,6 @@ I have been contributing to open source for the last 3 years and Red Hat was one
|
||||
On the first day of my internship, I met two amazing teammates `Saytam <https://github.com/>`_ and `Utkarsh <https://github.com/>`_. We were also introduced to a Senior Software Engineer `Piyush Garg <https://github.com>`_ who later mentored us. The initial few meetings were more on the introduction and what to learn topics. Before I jump into more details let me explain first what does a **DevTools Developer/Engineer** do?
|
||||
|
||||
|
||||
|
||||
What does a DevTools Developer/Engineer do?
|
||||
-------------------------------------------
|
||||
|
||||
@@ -37,8 +36,8 @@ Learning on the |golang_logo|
|
||||
There was a lot of learning and still a lot to learn. In a meeting with my manager Pradeepto Bhattacharya, I was told that I will be working on TektonCD or OpenShift Pipelines, and both of them require a sound knowledge of Golang, CI/CD, Containers, Docker, and Kubernetes. I was familiar with CI/CD, containers, and Docker but never used Golang and Kubernetes. We were provided plenty of good resources and my teammates also helped with many awesome resources. I am listing all the resources with their category.
|
||||
|
||||
|
||||
Golang
|
||||
""""""
|
||||
`Golang <https://go.dev/>`_
|
||||
"""""""""""""""""""""""""""
|
||||
|
||||
.. image:: /images/goladder.png
|
||||
:class: float-md-right rounded ml-3
|
||||
@@ -55,8 +54,8 @@ One of Golang’s biggest advantages is that it offers the clarity and ease of u
|
||||
- `The Go Programming Language - Book <https://www.gopl.io/>`_ *for learning advanced level golang*
|
||||
- `Golang Tutorial for Beginners | Full Go Course - TechWorld with Nana <https://youtu.be/yyUHQIec83I>`_ *if you prefer video tutorials, I don't :)*
|
||||
|
||||
Docker
|
||||
""""""
|
||||
`Docker <https://www.docker.com/>`_
|
||||
"""""""""""""""""""""""""""""""""""
|
||||
|
||||
Docker takes away repetitive, mundane configuration tasks and is used throughout the development lifecycle for fast, easy, and portable application development - desktop and cloud. Docker’s comprehensive end-to-end platform includes UIs, CLIs, APIs, and security that are engineered to work together across the entire application delivery lifecycle.
|
||||
|
||||
@@ -69,8 +68,8 @@ Docker takes away repetitive, mundane configuration tasks and is used throughout
|
||||
- `Docker for beginners <https://docker-curriculum.com/>`_
|
||||
- `Docker Tutorial for Beginners | TechWorld with Nana <https://youtu.be/3c-iBn73dDE>`_ *video tutorial*
|
||||
|
||||
Kubernetes
|
||||
""""""""""
|
||||
`Kubernetes <https://kubernetes.io/>`_
|
||||
""""""""""""""""""""""""""""""""""""""
|
||||
|
||||
.. image:: /images/kubernetes-meme.png
|
||||
:width: 200
|
||||
@@ -93,4 +92,5 @@ In late January, we were asked to implement our learnings and deep dive into Kub
|
||||
The application was called **Minimal Tekton Server**. It is a set of three different applications, i.e a server, a CLI, and a dashboard. In short, this application is supposed to *listen to custom resources being created and then transfer the request to Tekton API to create the corresponding resource on the OpenShift/Kubernetes cluster.*
|
||||
|
||||
|
||||
So are you interested in how it went? Please follow up with my next blog.
|
||||
So are you interested in how it went? Please follow up with my `next blog <https://avinal.space/posts/development/lovely-dangerous-things-redhat.html>`_.
|
||||
|
||||
|
||||
@@ -0,0 +1,174 @@
|
||||
.. |redhat_logo| image:: /images/redhat_logo.png
|
||||
:width: 1.5em
|
||||
:align: middle
|
||||
:target: https://redhat.com
|
||||
|
||||
.. |mks_logo| image:: /images/mks_logo.png
|
||||
:width: 1.5em
|
||||
:align: middle
|
||||
:target: https://github.com/MiniTeks
|
||||
|
||||
*******************************************
|
||||
Developing Minimal Tekton Server |mks_logo|
|
||||
*******************************************
|
||||
|
||||
:date: 2022-02-27 20:47
|
||||
:modified: 2022-03-07 22:47
|
||||
:slug: lovely-dangerous-things-redhat
|
||||
:category: development
|
||||
:tags: kubernetes, redhat, docker, golang, tekton, openshift, intern
|
||||
:summary: We will be designing and implementing an application that will be talking to Tekton APIs to create resources on a Kubernetes/OpenShift Cluster.
|
||||
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<p style="border: 2px solid var(--pink);border-radius: 7px;" align=center>This blog is a descreptive account of the development of Minimal Tekton Server. This is highly technical in nature, so please make sure that you have sufficient knowledge about Golang, Docker, Kubernetes and TektonCD. You can refer to my <a href="https://avinal.space/posts/development/i-am-loving-it-redhat.html">previous blog</a> to know about these topics.<p>
|
||||
|
||||
|
||||
As mentioned in my last blog, we were given to implement an application named **Minimal Tekton Server**. The problem statement reads:
|
||||
|
||||
.. epigraph::
|
||||
|
||||
We will be designing and implementing an application that will be talking to Tekton APIs to create resources on a Kubernetes/OpenShift Cluster. The application will expose some fields of the Tekton Resources which the user will provide and then this application will create Tekton resources by talking to Tekton APIs available on the cluster to create the resources based on the user-provided fields.
|
||||
|
||||
|
||||
There are three parts in this project for the application and two more parts for the CI/CD using TektonCD and Kubernetes/OpenShift. I will go through each part descriptively and try to explain what we did.
|
||||
|
||||
|
||||
|
||||
The Architecture of MKS
|
||||
-----------------------
|
||||
|
||||
The first task in the development of the Minimal Tekton Server was creating its architectural diagram. Our first diagram was trash compared to the final diagram. Yeah, we learned. I will be explaining our final(obviously) architectural diagram and try to make some sense out of band-aids and duct tapes.
|
||||
|
||||
.. image:: /images/mks-architecture.png
|
||||
:alt: The MKS Arhitecture
|
||||
:class: img-fluid my-3
|
||||
|
||||
Let me start with explaining **What are MKS Resources?**. I hope you know at least tidbits about Kubernetes and by the definition: *A resource is an endpoint in the Kubernetes API that stores a collection of API objects of a certain kind; for example, the built-in :code:`pods` resource contains a collection of Pod objects.* But developers soon realized that these in-built resources were not enough for the ever-growing applications of Kubernetes. Here `custom resource <https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/>`_ comes into the picture. *A custom resource is an extension of the Kubernetes API that is not necessarily available in a default Kubernetes installation.* To define a custom resource we use something called `Custom Resource Definition <https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/>`_. So MKS Resources are such custom resources that correspond to the TektonCD custom resources.
|
||||
|
||||
|
||||
.. image:: /images/venus-flytrap.gif
|
||||
:class: float-md-right ml-3
|
||||
:width: 250
|
||||
:alt: A venus flytrap engulphing an insect.
|
||||
|
||||
|
||||
Let us now focus on the box containing :code:`Controller` and :code:`API server`. The controller can be said as a stimulus-response mechanism. Take the analogy of a Venus Flytrap plant. The trap is initially open. There are :code:`trigger` hairs on the inside of the trap. Once an insect is detected, there is a change of state and the trap closes in a blick on the eye. The controller works the same way. It listens for the change in the state of the MKS resources and immediately transfers the request to the Tekton API to reflect the change in the corresponding Tekton resources. The changes can be creation, deletion, or updating. The API server ensures that there is a working connection between our controller and the Tekton API.
|
||||
|
||||
|
||||
|
||||
MKS Server also exposes APIs to introduce a change of state in the MKS resources. In technical terms these are called :code:`verbs`. There are five such verbs that we have exposed: :code:`create`, :code:`update`, :code:`get`, :code:`delete`, and :code:`list`. They can be utilized by a REST client, or in our case **MKS CLI** to introduce desired change. The MKS command-line interface provides commands and subcommands to do the desired tasks.
|
||||
|
||||
|
||||
Whenever there is a change in the state, there is a logic running inside the controller to react on that and that also affects our database. We store four datapoints in our database: :code:`created`, :code:`deleted`, :code:`completed`, and :code:`failed`. They tell us about the current statistcs of our MKS resource using a single-page web app called **MKS Dashboard** (or UI).
|
||||
|
||||
This was about the architecture of the Minimal Tekton Server. Let us jump into more technical stuff.
|
||||
|
||||
|
||||
How to implement a CRD controller?
|
||||
----------------------------------
|
||||
|
||||
During this assignment, something that took the most time and effort was the implementation of a controller for our custom resources. This isn't very hard if you go by the rules and do the things according to the well-defined documents and blogs since this is a standard step in the implementation of any custom resource controller. But did we follow the rules? Hell no! But this time, let us go step-by-step.
|
||||
|
||||
1. The first step is to define a :code:`CustomResourceDefinition` for our custom resource. Let us define a CRD called :code:`spacetime`. To do this you can write a YAML file like below.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
# file: spacetime-crd.yaml
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
# name must match the spec fields below, and be in the form: <plural>.<group>
|
||||
name: spacetimes.example.com
|
||||
spec:
|
||||
# group name to use for REST API: /apis/<group>/<version>
|
||||
group: example.com
|
||||
# list of versions supported by this CustomResourceDefinition
|
||||
versions:
|
||||
- name: v1alpha1
|
||||
# Each version can be enabled/disabled by Served flag.
|
||||
served: true
|
||||
# One and only one version must be marked as the storage version.
|
||||
storage: true
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
type: object
|
||||
properties:
|
||||
spec:
|
||||
type: object
|
||||
properties:
|
||||
message:
|
||||
type: string
|
||||
# either Namespaced or Cluster
|
||||
scope: Namespaced
|
||||
names:
|
||||
# plural name to be used in the URL: /apis/<group>/<version>/<plural>
|
||||
plural: spacetimes
|
||||
# singular name to be used as an alias on the CLI and for display
|
||||
singular: spacetime
|
||||
# kind is normally the CamelCased singular type. Your resource manifests use this.
|
||||
kind: SpaceTime
|
||||
# shortNames allow shorter string to match your resource on the CLI
|
||||
shortNames:
|
||||
- st
|
||||
|
||||
You can learn more about the fields and options `here <https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/>`_. The CRD that we defined above corresponds to the :code:`CustomResource` given below. Once you apply the above file you will be able to see the :code:`spacetime` custom resource on your Kubernetes/OpenShift cluster.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
# file: spacetime-cr.yaml
|
||||
apiVersion: spacetimes.example.com/v1alpha1
|
||||
kind: SpaceTime
|
||||
metadata:
|
||||
name: spacetime-cr
|
||||
spec:
|
||||
message: "Hello from space!"
|
||||
|
||||
Apply them using the following commands:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
kubectl apply -f spacetime-crd.yaml
|
||||
kubectl apply -f spacetime-cr.yaml
|
||||
|
||||
2. Once we have defined our custom resources, we need to define the types that will correspond to this custom resource definition. This can be done using :code:`k8s.io/apimachinery/pkg/apis/meta/v1` package written in golang. Did I tell you that this is all in golang? Well, now you know. Create a package structure for a golang project and add the definition of the type as given below.
|
||||
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
mkdir -p pkg/api/spacetime/v1alpha1
|
||||
touch pkg/api/spacetime/v1alpha1/{spacetime_types,register,doc}.go pkg/api/spacetime/register.go
|
||||
|
||||
|
||||
Add the following content to the corresponding files.
|
||||
|
||||
.. code-block:: golang
|
||||
|
||||
// file: /pkg/api/spacetime/v1alpha1/spacetime_types.go
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
type SpaceTime struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||
|
||||
Spec SpaceTimeSpec `json:"spec"`
|
||||
}
|
||||
|
||||
type SpaceTimeSpec struct {
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
type SpaceTimeList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ListMeta `json:"metadata"`
|
||||
|
||||
Items []SpaceTime `json:"items"`
|
||||
}
|
||||
|
||||
|
||||
**To be Continued**
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 163 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 2.4 MiB |
Reference in New Issue
Block a user