<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Bornfight</title>
    <description>The latest articles on Forem by Bornfight (@bornfightcompany).</description>
    <link>https://forem.com/bornfightcompany</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F1897%2F01c118d8-0fe8-43ae-a918-b0a3c2a75f60.jpg</url>
      <title>Forem: Bornfight</title>
      <link>https://forem.com/bornfightcompany</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/bornfightcompany"/>
    <language>en</language>
    <item>
      <title>Check yo' project structure before you wreck yo' project structure</title>
      <dc:creator>Davor Tvorić</dc:creator>
      <pubDate>Mon, 04 Apr 2022 09:48:50 +0000</pubDate>
      <link>https://forem.com/bornfightcompany/check-yo-project-structure-before-you-wreck-yo-project-structure-3egp</link>
      <guid>https://forem.com/bornfightcompany/check-yo-project-structure-before-you-wreck-yo-project-structure-3egp</guid>
      <description>&lt;p&gt;I gotta admit, when it came to structuring a frontend project, I didn't really know why people considered it that important. I've mostly been working on smaller projects either alone or with 2-3 people. The projects' structure didn't matter all that much because they were abandoned as soon as we were finished with the project. With this kind of experience you might get lulled into the feeling that the default setup is all that you need.&lt;br&gt;
I realized there's a lot more than meets the eye when I started working on an existing project that was a couple of years old. Just imagine being plopped in a foreign structure where you have to think about &lt;strong&gt;every little detail&lt;/strong&gt; and question yourself constantly!&lt;br&gt;
I started thinking a lot more about where I'd place a function, partial or a simple object. By just spending some time thinking about what would be the most logical solution, I've (hopefully) improved mine and everyone else's developer experience.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff1267hagcwy749fo1fj3.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff1267hagcwy749fo1fj3.jpg" alt="Developer experience"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The catch is that I still have a lot to learn. I'm sure there's some things I haven't even considered because they're manageable at the time. But I don't see that as a bad thing, since that's something that could probably be improved. That's why I think it's important that you review how you structure your projects once in a while.&lt;/p&gt;

&lt;p&gt;In this article, I'll explain why we've had the idea for a standard project structure within our team. My experience is related to frontend, but you might find something interesting even if you work in something else! But if you're in need of an actual structure, I'll be showing that in some other post.&lt;/p&gt;

&lt;h2&gt;
  
  
  How can you condense complex project structures into a single template?
&lt;/h2&gt;

&lt;p&gt;Our projects' structure can vary a lot depending on the length of the project, the complexity, the features, and a number of other factors. However, I think we can make a generic structure which would work great in most cases. Now you're probably thinking, what about existing projects? It might be really complex (and inefficient) to change the whole structure in an existing project, but who says that you have to change absolutely everything? If you're going to work on a project for some time, why not make it easier for yourself if it's possible? After all, you've probably gathered a lot of knowledge throughout the years and could surely improve on the parts you designed at the beginning of the project.&lt;/p&gt;

&lt;p&gt;Tackling this problem might not even be as complicated as you might think. Just writing down and explaining each folder/file will give you insight about your current situation.&lt;br&gt;
From there you can easily see whether the decisions you made make sense! When I did this, it really felt like a game of Sudoku. When it seems like there's nothing else that can be done, you stumble upon a couple of smaller things here and there and, suddenly, a huge playing field opens up. That's my method for handling larger and older projects that are in time for a tune up.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fc.tenor.com%2FaEbRRiginLwAAAAC%2Fmechanic-hammer.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fc.tenor.com%2FaEbRRiginLwAAAAC%2Fmechanic-hammer.gif" alt="Clarkson hitting a car with a hammer"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  Many projects, even more factors, but not enough resources
&lt;/h2&gt;

&lt;p&gt;I work in an agency, but we work on projects of varying lengths. Some are done in a month's time and some are worked on for years. We're not limited to one technology, so that's also another factor. That's just a couple of things, but our structures can be wildly different. This means that each time you switch projects you have to get used to a different structure, as well. By not having a defined standard within the team, it meant that new projects would succumb to the same fate. That's more cognitive load that you don't want to have.&lt;br&gt;
To counter that, we've researched which structure would fit us the best. Most of our focus was on scalability, readability, and extendibility. That's a lot of &lt;em&gt;-bilitys&lt;/em&gt;, but in simpler terms we wanted to make sure that the project structure we made is easy to understand, use and improve. Sounds really simple, but to find something concrete on the Internet proved to be somewhat of a tough task. We were defining this structure for our frontend projects where the technologies are relatively young. Therefore, there's a lot of resources that show their ideas on really small examples with little experience in larger projects. It also doesn't help that only some use actual architectural patterns that are commonly used in software development.&lt;br&gt;
We did manage to find some resources that really helped us out:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://blog.webf.zone/contemporary-front-end-architectures-fb5b500b0231" rel="noopener noreferrer"&gt;Contemporary Front-end Architectures&lt;/a&gt; by Harshal Patil&lt;/li&gt;
&lt;li&gt;&lt;a href="https://infinum.com/handbook/frontend/react/project-structure" rel="noopener noreferrer"&gt;Infinum Frontend Handbook&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://michalzalecki.com/elegant-frontend-architecture/" rel="noopener noreferrer"&gt;How to structure frontend application&lt;/a&gt; by Michal Zalecki&lt;/li&gt;
&lt;li&gt;&lt;a href="https://angular.io/guide/styleguide#folders-by-feature-structure" rel="noopener noreferrer"&gt;Folders-by-feature structure&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://reactpatterns.com/#container-component" rel="noopener noreferrer"&gt;Container component&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There's a lot to learn from each resource, but we didn't use every single thing from them. Each part was discussed and made sure that it really worked for us. It helped that we could decide as a team because each of us had some experience in something the others didn't, so it's important not to dismiss anyone's opinion.&lt;br&gt;
After defining a structure, there's two last steps that were incredibly important and made everything click:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Explain each segment so that someone with less experience can understand it with relative ease&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Just by using your explanation from the last step, create a smaller app to test out your structure&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhackernoon.com%2Fimages%2F1%2Avrxt-ULqMURtcTHQ3ayfoA.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhackernoon.com%2Fimages%2F1%2Avrxt-ULqMURtcTHQ3ayfoA.gif" alt="Salt bae"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These steps were vital to adding most of the finishing touches. If we hadn't done them, we would have shot our own leg when we started a new project. It makes sense testing out what you did, but it is tempting to skip this part since you've already done the majority of the work. It will also help you to objectively look at the work you've done. Don't forget that everything can be improved!&lt;/p&gt;

&lt;h2&gt;
  
  
  Final words
&lt;/h2&gt;

&lt;p&gt;Following this plan we came up with a concise &lt;a href="https://create-react-app.dev/" rel="noopener noreferrer"&gt;CRA&lt;/a&gt; template (and Vue template) with a detailed README. Now we're able to preserve the same project structure throughout multiple projects and relieve ourselves of the cognitive load when switching to other projects.&lt;br&gt;
This does not mean that our work is over, but it should be less of a hassle to have a great foundation and improve everything from here.&lt;/p&gt;

&lt;p&gt;And if that doesn't sound great, I don't know what does!&lt;/p&gt;

</description>
      <category>programming</category>
      <category>engineeringmonday</category>
      <category>javascript</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Phone Number Normalisation</title>
      <dc:creator>Ajdin Mustafić</dc:creator>
      <pubDate>Mon, 28 Mar 2022 13:16:42 +0000</pubDate>
      <link>https://forem.com/bornfightcompany/phone-number-normalisation-4gpi</link>
      <guid>https://forem.com/bornfightcompany/phone-number-normalisation-4gpi</guid>
      <description>&lt;p&gt;The phone number normalisation is used to translate a phone number into a standard form.&lt;/p&gt;

&lt;p&gt;For example, there is E.164 international standard which defines format as "[+] [country code] [subscriber number including area code] and can have a maximum of fifteen digits". However, we rarely save numbers, especially domestic ones, in this exact format. &lt;/p&gt;

&lt;p&gt;This can be a huge problem if you wanted to allow your users to import their mobile phone contacts into your application. The users can have the phone number, in their phone contacts, entered with or without country code, or can enter country codes like 00385 or +385, etc. So if you didn't have the phone number normalisation, these two numbers 00385991234567 and +385991234567 would be imported as two different phone numbers for the same contact even though when calling, they are the same, just written in different format standards.&lt;/p&gt;

&lt;p&gt;We have a similar challenge on one of our projects, so our first step was to research, what should be covered and what others cover when they do the phone number normalisation. &lt;/p&gt;

&lt;p&gt;One of my outputs were the test cases that are covered by Whatsapp:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;I can't contact a foreign mobile number without a country code&lt;/strong&gt; - &lt;em&gt;For example, if your phone number is from Croatia and you saved a contact with a mobile phone number from Austria, without the country code, Whatsapp will not recognize it as existing.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;I can contact domestic mobile number without country code&lt;/strong&gt; - &lt;em&gt;For example, if your phone number is from Croatia and you saved a contact with a mobile phone number from Croatia, without the country code, Whatsapp will recognize it as it is (existing).&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;I can contact a foreign mobile number with "00" country code&lt;/strong&gt; - &lt;em&gt;For example, if your phone number is from Croatia and you saved a contact with a mobile phone number from Austria, with the 0043 country code standard, Whatsapp will recognize it as existing.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;I can contact a foreign mobile number with a "+" country code&lt;/strong&gt; - &lt;em&gt;For example, if your phone number is from Croatia and you saved a contact with a mobile phone number from Austria, with the +43 country code standard, Whatsapp will recognize it.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;I can contact a foreign mobile number with "+" country code and 0 before the mobile prefix&lt;/strong&gt; - &lt;em&gt;For example, save the foreign phone number in your contacts with "+" country code and zero before the mobile operator prefix (+385 &lt;strong&gt;0&lt;/strong&gt; 99 1234567). Whatsapp will recognize and normalise the number to +385 99 1234567.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;I can't contact a foreign mobile number with "00" country code and 0 before mobile prefix&lt;/strong&gt; - &lt;em&gt;For example, save the foreign phone number in your contacts with "00385" country code and zero before mobile prefix (+385 &lt;strong&gt;0&lt;/strong&gt; 99 1234567). Whatsapp will not recognize the number as the same as +385991234567.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;I can't contact domestic mobile number with "00" country code and 0 before mobile prefix&lt;/strong&gt; - &lt;em&gt;For example, save the domestic phone number in your contacts with "00385" country code and zero before mobile prefix (+385 &lt;strong&gt;0&lt;/strong&gt; 99 1234567). Whatsapp will not recognize the number as the same as +385991234567.&lt;/em&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Handling phone numbers, especially without normalisation can create a real mess in your application because many users in different countries use different phone number standards to create their contacts.&lt;/p&gt;

&lt;p&gt;Feel free to share your experience and your test case examples in the comments section.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>testing</category>
      <category>qualityassurance</category>
      <category>engineeringmonday</category>
    </item>
    <item>
      <title>Starting as a Junior QA? Don't worry, I got you</title>
      <dc:creator>Mario Tupek</dc:creator>
      <pubDate>Tue, 22 Mar 2022 10:13:37 +0000</pubDate>
      <link>https://forem.com/bornfightcompany/starting-as-a-junior-qa-dont-worry-i-got-you-49o0</link>
      <guid>https://forem.com/bornfightcompany/starting-as-a-junior-qa-dont-worry-i-got-you-49o0</guid>
      <description>&lt;p&gt;Almost 5 years ago, I've started my QA journey as a student (AKA Junior) and didn't even know what QA was! Little by little, I started picking up pieces of what QA might actually be and how to do it properly. A lot of mistakes were done in the first year (tbh, it was the hardest one for me personally), but as the years went by, it gradually became easier because of all the knowledge I've managed to gather. This post will have a few tips for all my fellow Junior QAs' that are just starting out and hopefully, you can learn from my mistakes.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;1. Write down everything&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;This is the most crucial part that will make your life much easier. When you are testing web app, mobile app, TV app, etc., you &lt;strong&gt;HAVE&lt;/strong&gt; to write down every single thing you notice while testing. Reason for that is very simple: You'll forget to report it later. That's it. It happened to me and it happens to everyone. We're not robots that can remember every scenario that we've tested, step by step. We're only humans that have errors. Those things that you'll write down (whether it's on plain paper, notepad, code comments, etc.), they will become useful when an unexpected issue appears and someone asks you if it happened before. And guess what, you'll have a log of it written somewhere and explain that it was tested and eventually reported issue.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;2. Devs are your best friends&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;You might think this is not possible, but when it happens, it's the best relationship within a project (or a whole company) you can have. At the beginning, devs will hate you, prepare for that mentally, because it can be exhausting to hear "It's a feature, not a bug" a million times. In those moments, if you are really certain that it's actually a bug, you can ask another dev for a second opinion. In some cases, it really can happen that it's a feature, no matter how hard you really see it as a bug, and that is perfectly fine. You've done your part and move on for more testing. Just remember that, in this relationship, you have your best intentions to break their code for better product at the end. :)&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;3. Don't forget your main goal&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Usually as a junior, forgetting what's on your plate for testing is really easy. You want to prove yourself to the others by reporting as many bugs as possible, and it's completely natural to do that, but one thing to understand: You've been given a goal to accomplish under defined deadline and with certain requirements. Follow those requirements and you'll be golden. By reporting visual issues (icons and pixels misaligned, missing exclamation mark, colour is 5% brighter than in design, etc.) before incoming release, you'll create a mess inside your team and nobody needs to think that product is not working properly. Your time for reporting those issues will come. Sticking to your main goal is something you should have on your mind, day by day, as you're testing a product.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;4. Testing only acceptance criteria is not enough&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Everyone can test it, and you're not everyone. You are QA, and your job is to think outside of acceptance criteria (AC). Every issue that you'll discover will mainly be &lt;em&gt;between&lt;/em&gt; the lines of written AC and it's your job to turn on your special QA skillset that you possess and break the AC, little by little. It's your time to get into the shoes of all those end users that will be using your tested product. Think of every possible way they can use it, convert it into cases and test it. &lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Summary&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Hopefully these tips might come in handy to some of you, as they would certainly have helped me when I started as a junior. What do you think about them?&lt;br&gt;
Let me know in the comments if you have any other tips or disagreements you'd like to share.&lt;/p&gt;

</description>
      <category>engineeringmonday</category>
      <category>career</category>
      <category>beginners</category>
      <category>motivation</category>
    </item>
    <item>
      <title>Traditional Education vs Self Taught Route in Programming (2022 edition)</title>
      <dc:creator>Luka Kukina</dc:creator>
      <pubDate>Mon, 14 Mar 2022 14:23:30 +0000</pubDate>
      <link>https://forem.com/bornfightcompany/traditional-education-vs-self-taught-route-in-programming-2022-edition-355n</link>
      <guid>https://forem.com/bornfightcompany/traditional-education-vs-self-taught-route-in-programming-2022-edition-355n</guid>
      <description>&lt;p&gt;This blog post will be written from the self taught programmer's perspective.&lt;br&gt;
Backstory: after I graduated from college (Nutrition), I started learning programming in my free time: HTML, CSS, JavaScript and React. I was able to land my first job after just 3 months of studying, but ever since then, I was wondering if I should have went to a Computer Sciences university of some kind...&lt;/p&gt;

&lt;h2&gt;
  
  
  5 Years of College vs 3 Months of Self Taught
&lt;/h2&gt;

&lt;p&gt;College gives you a plan, it gives you a structured path of learning, it gives you dedicated teachers who are teaching you stuff in a particular order, but...&lt;br&gt;
College also gives you an extensive overview of everything that programming has to offer. I would probably have to learn plenty of technologies that I would not be interested in, many of the subjects that are not directly connected to programming would be hard to pass and if I went to college for 5 years, I would "lose" 20x more time to get a first "real" job...&lt;/p&gt;

&lt;p&gt;The good thing about the self taught route is that you can turn your focus completely and solely on technologies that interest you and that you want to master.&lt;br&gt;
On the other hand, there are a lot of questions that are hard to answer if you are on your own:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;where to start from?&lt;/li&gt;
&lt;li&gt;how to distinguish what is crucial to understand if you want to move forward?&lt;/li&gt;
&lt;li&gt;what is not so important?&lt;/li&gt;
&lt;li&gt;why are there so many ways to write things and who should I listen to?&lt;/li&gt;
&lt;li&gt;is this still being used??&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;(so many questions 🤯).&lt;/p&gt;

&lt;p&gt;And that brings us to...&lt;/p&gt;

&lt;h2&gt;
  
  
  Imposter Syndrome
&lt;/h2&gt;

&lt;p&gt;I am not sure how it goes with the imposter syndrome when you have a computer science degree, but when you're a self taught programmer - it is very real. You will often think that things you don't know are actually some basics that you should have known. Also, you won't have the strongest programming foundations, and because of that you will think there must have been a better way to solve a problem. You won't feel as good reviewing a PR or giving advice, and you won't feel as competent as people with a computer science degree.&lt;br&gt;
But, it's not always that bad, especially because the IT industry is full of very friendly people that are understanding and always willing to help you out.&lt;/p&gt;

&lt;h2&gt;
  
  
  Information Availability
&lt;/h2&gt;

&lt;p&gt;It has never been easier or faster to get information you need. Because of that, more and more people are successful in becoming self taught programmers. But, that is not necessarily making it easier. With so much (different) information, paths and advices, it might be overwhelming for people and make them feel uncertain if they are moving in the right direction - it may even make them quit. &lt;/p&gt;

&lt;h2&gt;
  
  
  Job Opportunities
&lt;/h2&gt;

&lt;p&gt;There are so many IT companies in the world and there are more of them each day. The amount of code that needs to be taken care of is huge and the amount of code that still needs to be written is even bigger. The point is: &lt;strong&gt;There are not enough developers&lt;/strong&gt; in this world! This fact makes a computer science diploma less important when it comes to landing a job. Almost everybody should be able to land a job as a junior developer because there is such a large need for developers right now. You need to be a good fit for a company (sometimes more important than the actual knowledge), and you'll become a master of your craft as you work on a real world problems.&lt;/p&gt;

&lt;h2&gt;
  
  
  If I had to do it all over again
&lt;/h2&gt;

&lt;p&gt;Many people might say that self taught programmers got it easy by bypassing college, but I actually think that it is the harder path. If I had to start all over again from high school, I would definitely go to a computer science college and earn myself a degree. But if I had to do it all over again from the point where I already graduated from Nutrition, I think I would choose a self taught route again, but this time I would also try to become a part-time computer science student to have a structured curriculum and a certainty that I have the necessary foundation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Like with everything else, there are good and bad aspects on both paths. Many programmers that I've met said that everybody is a self taught to a certain extent. I agree with that, college would give me a wide spectrum of knowledge, but when it comes to mastering a craft, you have to dig deep on your own. By now, I was able to progress to a mid level JavaScript developer and at this point I think I have more benefits by working on real world projects, so I don't see myself going to college again. But, if you are in the similar position, I hope this post helped you in making your decision.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>career</category>
      <category>beginners</category>
      <category>engineeringmonday</category>
    </item>
    <item>
      <title>First 6 months: Dreams vs Reality</title>
      <dc:creator>Valentin Vuk</dc:creator>
      <pubDate>Mon, 07 Mar 2022 09:17:44 +0000</pubDate>
      <link>https://forem.com/bornfightcompany/first-6-months-dreams-vs-reality-1l2p</link>
      <guid>https://forem.com/bornfightcompany/first-6-months-dreams-vs-reality-1l2p</guid>
      <description>&lt;p&gt;So six months have passed, 350 commits have been made and 147 daily meetings attended...here is a short recap of what I have expected versus what that looked like in reality.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Well, dreams, they feel real while we're in them right? Its only when we wake up that we realize that something was actually strange."&lt;/em&gt; - Cobb&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The Code
&lt;/h2&gt;

&lt;p&gt;Like every one of us, I have learned my craft mostly on online tutorials. And there you touch on really wide subjects. In my case, as a react developer, that would be react router, storybook, animation libraries, testing, internalization and concepts like spa, ssg and ssr to name a few. And here is me walking into my first job thinking I will use all those tools daily.&lt;/p&gt;

&lt;p&gt;Well, that didn’t work as planned. In reality, the best way to describe how it actually is: you dive in and work much deeper, but with much less tools. And these tools depend on the project that you get assigned. Sometimes it sucks not working with the stuff that you find interesting and engaging, but that is the reality of having a job. On the bright side, there’s plenty of interesting things to learn in the depth of every tool.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Musn't be afraid to dream a little bigger, darling."&lt;/em&gt; - Eames&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Scrum is like your mother-in-law, it points out ALL your faults
&lt;/h2&gt;

&lt;p&gt;I imagined my everyday working flow to look something like this: senior developer on the project gives me one detailed task for a week or two, and my communication is solely with him or in rare cases with the backend team - and that’s it.&lt;/p&gt;

&lt;p&gt;Ken Schwaber had other ideas. Because of this guy, things called organization, communication, time and task management, planning etc. came into my life. Daily meetings, story points, estimations...whole new world. To this day it is a work in progress, and also - scrum development isn’t particularly student friendly. But as I wrote in the title of this section, it points out all your flaws and gives you something to work on - really important characteristics for your future successful career.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Look if you want my help, you're gonna have to be completely open with me. I need to know my way around your thoughts better than your wife, better than your therapist, better than anyone."&lt;/em&gt; - Cobb&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The Squad
&lt;/h2&gt;

&lt;p&gt;Totally expected to work with Richards, Gilfoyles, Jian Yangs characters of the world, sometimes with a bit of Mark Zuckerberg ego on the side. Very hard to engage with, even harder to learn something from them.&lt;/p&gt;

&lt;p&gt;I still remember my first few days where I was actually shocked how incredibly brilliant, but also so down to earth and approachable everyone were. From giving me advice, to playing Fifa on lunch breaks and having great time on our "spontaneous" parties. Impressed.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"I got someone better!"&lt;/em&gt; - Miles&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The Conclusion
&lt;/h2&gt;

&lt;p&gt;In retrospect, it's incredible how much you can be in the wrong with expectations (👋 estimations). Also, our developer community is incredible in real life too, even better, because you have that human touch too. And for my fellow students, I recommend you start exploring jobs, because you learn so so much - not only about the technical stuff, but more importantly, the processes of developing a product, organizational skills and the mindset behind successful programmers and companies.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flrqlygfc2pev3awt75zf.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flrqlygfc2pev3awt75zf.gif" alt="Totem spinning"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>engineeringmonday</category>
      <category>beginners</category>
      <category>career</category>
      <category>motivation</category>
    </item>
    <item>
      <title>5 Mistakes I’ve Made as a Junior Flutter Developer</title>
      <dc:creator>Zvonimir Vujnović</dc:creator>
      <pubDate>Mon, 28 Feb 2022 20:03:12 +0000</pubDate>
      <link>https://forem.com/bornfightcompany/5-mistakes-ive-made-as-a-junior-flutter-developer-55id</link>
      <guid>https://forem.com/bornfightcompany/5-mistakes-ive-made-as-a-junior-flutter-developer-55id</guid>
      <description>&lt;p&gt;So you want to learn Flutter. Maybe you’ve seen a cool job opening for Flutter developers or wanted to try how it compares to native development of Android or iOS apps. You’ve started learning Flutter and it seemed pretty cool, right? You wanted to learn more and more and the hunger for Flutter knowledge doesn’t stop? Well it might be a time to slow down and reflect on what you’ve learned. Maybe try to be a bit self critical. See what could’ve been done better. After all, Flutter is a new technology and many times there isn't a right or wrong answer. Here are some mistakes I made as a Junior Flutter Developer:&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Ignoring native development
&lt;/h2&gt;

&lt;p&gt;A few years before I started learning Flutter, I started developing Android apps using Kotlin. Unfortunately it didn't last long because I was a student and didn’t have enough free time to further increase my Android skills. &lt;br&gt;
Today, I can see clearly that the basics of both Android and iOS would be a useful background. Maybe it isn’t the worst mistake not to learn native development but it sure does help. As you develop more and more Flutter projects, you’ll find yourself opening android and ios folders more often. Sometimes you may have to tweak native code to get desired behavior. (A good example would be implementing native splash screens - although nowadays, there is a package for everything.) &lt;br&gt;
Overall, it is generally considered a good practice to have experience with native development before starting Flutter. Surely, it isn’t a must to get you going with Flutter but at some point you’ll need to understand the concepts of native development. &lt;/p&gt;
&lt;h2&gt;
  
  
  2. Not making everything a widget
&lt;/h2&gt;

&lt;p&gt;One way of implementing a DRY principle in programming is always extracting a repeating logic into a function. This led me to extracting repeating UI components into functions but I’ve realized soon that this kind of approach is no good.&lt;/p&gt;

&lt;p&gt;Flutter is a bit different in that way. Since we want our app to be as performant as it can be, we need to minimize the amount of rebuilds it’s making. For example, imagine having a screen with a button that is changing color on click. Performance wise, you’d only want to rebuild that button when the color has changed. If you use something like the code below, the whole screen will rebuild every time!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Scaffold(
  body: Column(
    children: [
      ...,
      ...,
      ...,
      ElevatedButton(
    style: ElevatedButton.styleFrom(primary: color),
        onPressed: () {
          setState(() {
            changeColor(),
          });
        },
        child: const Text(‘Button’),
      ),
    ],
  ),
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The key is to extract that button in a separate widget and move the color changing logic into that new widget. As you call setState(), only that widget will be rebuilt and the rest won’t. Now, it probably doesn’t sound that important, but when you have some heavy-computing happening and/or the screen itself is rebuilding frequently (animations can be performance heavy), there is a possibility that the app will lag. To further understand this topic, I would recommend this video: &lt;a href="https://www.youtube.com/watch?v=IOyq-eTRhvo"&gt;https://www.youtube.com/watch?v=IOyq-eTRhvo&lt;/a&gt;. I myself started to use this approach only after seeing this video (yes I’m ashamed) because I never, to that day, had a reason to optimize my app. &lt;/p&gt;

&lt;h2&gt;
  
  
  3. Lack of state management
&lt;/h2&gt;

&lt;p&gt;If you’ve read my previous mistake, you may wonder how you can change the color of our button widget from another widget that is higher in widget tree. What happens if some other component needs to change the color of the button? Well, the solution to that problem isn’t trivial. &lt;br&gt;
That’s why we use state management solutions. Some of the most popular state management solutions are Provider, Riverpod, BLoC and GetX. &lt;br&gt;
When I first started my Flutter journey, I only used setState() as my state management approach. As far as I think, it isn’t bad to start that way because then you know exactly what happens with your widgets and how Flutter is rebuilding and drawing your screens. &lt;br&gt;
As soon as you start making more complex apps, everything will become a mess. You’ll have trouble finding anything in your code since it will probably be spaghetti code. The best way to clean that mess is to implement a state management solution. That way you’ll decouple UI components from the business logic and everything will have its place in your project. &lt;br&gt;
I personally started with BLoC but didn’t find it that helpful nor simple. A few months ago I was introduced to Riverpod and never looked back. Anyway, it’s a matter of personal preference and you should find what works for you and stick with it. &lt;/p&gt;

&lt;h2&gt;
  
  
  4. Using too many packages
&lt;/h2&gt;

&lt;p&gt;Flutter is a framework developed with simplicity in mind. If you aren’t new to Flutter, you’ve probably heard: There is a package for everything - and yes, there almost literally is. When developing a new feature chances that someone already implemented it and made a package for others to reuse it are pretty high. It's as simple as plug'n'play.&lt;br&gt;
Of course, if you want to become a good Flutter developer and know what’s happening under the hood of those packages, you’ll probably want to implement it yourself. It might be time consuming but it is the best way to actually learn fundamentals. &lt;br&gt;
When I first started learning Flutter, I was a victim of this mistake myself. I would start working on a new feature and the first thought that would cross my mind was: Let’s check if there is a package for that! Unfortunately, the package was there in 90% of situations. Just later, I realized that no package is without its flaws. &lt;br&gt;
Imagine the situations where you need to develop a feature which already has a package dedicated for it but it just lacks that little thing that you need. You have no choice but to write it on your own. Having experience doing things yourself will definitely come in handy. &lt;/p&gt;

&lt;h2&gt;
  
  
  5. Not being consistent
&lt;/h2&gt;

&lt;p&gt;Flutter provides you with package flutter_lints in every new project by default if you are using Flutter 2.3.0-12.0.pre or newer. It provides the latest set of recommended lints that encourage good coding practices. &lt;br&gt;
When I first started, I wanted to learn as much as possible and go through the Flutter framework as quickly as I could. The result of that was inconsistent code with a lot of bad practices which were error prone. My life changed when I started using the lint package.&lt;br&gt;&lt;br&gt;
No more single quotes double quotes dilemma. Choose one and stick with it. (Personally I use single quotes in Flutter projects because imports are automatically added with single quotes.) Functions without return types don’t exist anymore. I started avoiding using var. And so on and so forth.&lt;br&gt;
Personal favorite lints of mine are &lt;code&gt;always_declare_return_types&lt;/code&gt; and &lt;code&gt;always_specify_types&lt;/code&gt;.&lt;br&gt;
Introduction of lints in my projects made my code cleaner, better and most important more consistent. &lt;br&gt;
Like in every other project (or anything you do in life) consistency is key. &lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;To conclude, don’t be discouraged if you are making some of these mistakes as well but always strive to learn more and do more. These were my top 5 mistakes and I hope you can learn from them, because I most certainly did. Feel free to share some of the mistakes you’ve made when starting with Flutter!&lt;/p&gt;

</description>
      <category>engineeringmonday</category>
      <category>flutter</category>
      <category>dart</category>
      <category>mobile</category>
    </item>
    <item>
      <title>Animate a frame by using  a transition between main image colors</title>
      <dc:creator>Goran Hrženjak</dc:creator>
      <pubDate>Mon, 21 Feb 2022 11:34:49 +0000</pubDate>
      <link>https://forem.com/bornfightcompany/animate-a-frame-by-using-a-transition-between-main-image-colors-1p2j</link>
      <guid>https://forem.com/bornfightcompany/animate-a-frame-by-using-a-transition-between-main-image-colors-1p2j</guid>
      <description>&lt;p&gt;A disclaimer right away - this is not really about animating image frames; it's just animating the background behind the image and adding some padding.&lt;/p&gt;

&lt;p&gt;I wanted to draw more attention to some images in a grid of uploaded images in one of my projects. Instead of having a plain &lt;em&gt;card&lt;/em&gt; design or having to tweak borders and shadows around those images, I came up with this technique. &lt;/p&gt;

&lt;p&gt;The idea is to extract the main image colors and compose a gradient with transitions between them. This gradient will "circle around" the image making it look more lively and vibrant. &lt;br&gt;
At the same time, each image will have its own unique animated gradient which, in my opinion, will make the transition between the image, image frame and container background color more seamless. &lt;/p&gt;

&lt;p&gt;To achieve that, main image colors are extracted for each image. This "palette" of colors is used in composing the aforementioned gradient.&lt;/p&gt;

&lt;p&gt;A couple of examples:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftcm00ybc0tiee9dkefbi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftcm00ybc0tiee9dkefbi.png" alt="Palette 1"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxajusrbhpzojzjv634b6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxajusrbhpzojzjv634b6.png" alt="Palette 2"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwjuj8oft3ir8ufz3fv8t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwjuj8oft3ir8ufz3fv8t.png" alt="Palette 3"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frwsutix5e45t71z8q5o5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frwsutix5e45t71z8q5o5.png" alt="Palette 4"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The code was mainly influenced by this script by Kepler Gelotte:&lt;br&gt;
&lt;a href="http://www.coolphptools.com/color_extract" rel="noopener noreferrer"&gt;Image Color Extract&lt;br&gt;
&lt;/a&gt;&lt;br&gt;
Input parameters are path to the &lt;strong&gt;image&lt;/strong&gt;, number of &lt;strong&gt;colors&lt;/strong&gt; to extract and &lt;strong&gt;delta&lt;/strong&gt; - the amount of gap when quantizing color values (1-255). The smaller the delta, the more accurate the color, but also - number of similar colors increases.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="k"&gt;declare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strict_types&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App\Service&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ColorPaletteExtractor&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="no"&gt;PREVIEW_WIDTH&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;250&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="no"&gt;PREVIEW_HEIGHT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;250&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;extractMainImgColors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$imagePath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$colorsCount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$delta&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$halfDelta&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$delta&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nv"&gt;$halfDelta&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$delta&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="nv"&gt;$size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;getimagesize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$imagePath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nv"&gt;$scale&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$size&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nv"&gt;$scale&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;PREVIEW_WIDTH&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nv"&gt;$size&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;PREVIEW_HEIGHT&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nv"&gt;$size&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="nv"&gt;$width&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;$size&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="nv"&gt;$height&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;$size&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$scale&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nv"&gt;$width&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nb"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$scale&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nv"&gt;$size&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
            &lt;span class="nv"&gt;$height&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nb"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$scale&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nv"&gt;$size&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="nv"&gt;$imageResized&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;imagecreatetruecolor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$height&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="nv"&gt;$imageType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$size&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

        &lt;span class="nv"&gt;$imageOriginal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;IMG_JPEG&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nv"&gt;$imageType&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nv"&gt;$imageOriginal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;imagecreatefromjpeg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$imagePath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;IMG_GIF&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nv"&gt;$imageType&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nv"&gt;$imageOriginal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;imagecreatefromgif&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$imagePath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;IMG_PNG&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nv"&gt;$imageType&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nv"&gt;$imageOriginal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;imagecreatefrompng&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$imagePath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="nb"&gt;imagecopyresampled&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$imageResized&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$imageOriginal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$height&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$size&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nv"&gt;$size&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

        &lt;span class="nv"&gt;$img&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$imageResized&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="nv"&gt;$imgWidth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;imagesx&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$img&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nv"&gt;$imgHeight&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;imagesy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$img&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="nv"&gt;$totalPixelCount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nv"&gt;$hexArray&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nv"&gt;$y&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nv"&gt;$imgHeight&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nv"&gt;$y&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nv"&gt;$x&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nv"&gt;$imgWidth&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nv"&gt;$x&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nv"&gt;$totalPixelCount&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

                &lt;span class="nv"&gt;$index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;imagecolorat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$img&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$y&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="nv"&gt;$colors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;imagecolorsforindex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$img&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$index&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$delta&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="nv"&gt;$colors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'red'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;intval&lt;/span&gt;&lt;span class="p"&gt;(((&lt;/span&gt;&lt;span class="nv"&gt;$colors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'red'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nv"&gt;$halfDelta&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nv"&gt;$delta&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nv"&gt;$delta&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                    &lt;span class="nv"&gt;$colors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'green'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;intval&lt;/span&gt;&lt;span class="p"&gt;(((&lt;/span&gt;&lt;span class="nv"&gt;$colors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'green'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nv"&gt;$halfDelta&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nv"&gt;$delta&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nv"&gt;$delta&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                    &lt;span class="nv"&gt;$colors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'blue'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;intval&lt;/span&gt;&lt;span class="p"&gt;(((&lt;/span&gt;&lt;span class="nv"&gt;$colors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'blue'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nv"&gt;$halfDelta&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nv"&gt;$delta&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nv"&gt;$delta&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

                    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$colors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'red'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;256&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="nv"&gt;$colors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'red'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt;
                    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$colors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'green'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;256&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="nv"&gt;$colors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'green'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt;
                    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$colors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'blue'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;256&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="nv"&gt;$colors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'blue'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;

                &lt;span class="nv"&gt;$hex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'0'&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;dechex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$colors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'red'&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'0'&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;dechex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$colors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'green'&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'0'&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;dechex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$colors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'blue'&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;isset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$hexArray&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$hex&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="nv"&gt;$hexArray&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$hex&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="nv"&gt;$hexArray&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$hex&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// Reduce gradient colors&lt;/span&gt;
        &lt;span class="nb"&gt;arsort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$hexArray&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;SORT_NUMERIC&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="nv"&gt;$gradients&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
        &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$hexArray&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nv"&gt;$hex&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$num&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;isset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$gradients&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$hex&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nv"&gt;$newHexValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;findAdjacent&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;$hex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$gradients&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$delta&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="nv"&gt;$gradients&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$hex&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$newHexValue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nv"&gt;$newHexValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$gradients&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$hex&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$hex&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="nv"&gt;$newHexValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nv"&gt;$hexArray&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$hex&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="nv"&gt;$hexArray&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$newHexValue&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nv"&gt;$num&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// Reduce brightness variations&lt;/span&gt;
        &lt;span class="nb"&gt;arsort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$hexArray&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;SORT_NUMERIC&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="nv"&gt;$brightness&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
        &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$hexArray&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nv"&gt;$hex&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$num&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;isset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$brightness&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$hex&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nv"&gt;$newHexValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;normalize&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;$hex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$brightness&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$delta&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="nv"&gt;$brightness&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$hex&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$newHexValue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nv"&gt;$newHexValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$brightness&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$hex&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$hex&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="nv"&gt;$newHexValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nv"&gt;$hexArray&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$hex&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="nv"&gt;$hexArray&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$newHexValue&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nv"&gt;$num&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="nb"&gt;arsort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$hexArray&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;SORT_NUMERIC&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// convert counts to percentages&lt;/span&gt;
        &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$hexArray&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nv"&gt;$key&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nv"&gt;$hexArray&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;float&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;$value&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nv"&gt;$totalPixelCount&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$colorsCount&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;array_slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$hexArray&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$colorsCount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$hexArray&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;normalize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$hex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt; &lt;span class="nv"&gt;$hexArray&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$delta&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$lowest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nv"&gt;$highest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nv"&gt;$colors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'red'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;hexdec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$hex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="nv"&gt;$colors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'green'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;hexdec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$hex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="nv"&gt;$colors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'blue'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;hexdec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$hex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$colors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'red'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nv"&gt;$lowest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nv"&gt;$lowest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$colors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'red'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$colors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'green'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nv"&gt;$lowest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nv"&gt;$lowest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$colors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'green'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$colors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'blue'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nv"&gt;$lowest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nv"&gt;$lowest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$colors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'blue'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$colors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'red'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$highest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nv"&gt;$highest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$colors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'red'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$colors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'green'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$highest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nv"&gt;$highest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$colors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'green'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$colors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'blue'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$highest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nv"&gt;$highest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$colors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'blue'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// Do not normalize white, black, or shades of grey unless low delta&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$lowest&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nv"&gt;$highest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$delta&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$hex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$lowest&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nv"&gt;$highest&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nv"&gt;$delta&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$hex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(;&lt;/span&gt; &lt;span class="nv"&gt;$highest&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;256&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nv"&gt;$lowest&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nv"&gt;$delta&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$highest&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nv"&gt;$delta&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nv"&gt;$newHexValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'0'&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;dechex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$colors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'red'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nv"&gt;$lowest&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'0'&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;dechex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$colors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'green'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nv"&gt;$lowest&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'0'&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;dechex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$colors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'blue'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nv"&gt;$lowest&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;isset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$hexArray&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$newHexValue&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;// same color, different brightness - use it instead&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$newHexValue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$hex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;findAdjacent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$hex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt; &lt;span class="nv"&gt;$gradients&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$delta&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$red&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;hexdec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$hex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="nv"&gt;$green&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;hexdec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$hex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="nv"&gt;$blue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;hexdec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$hex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$red&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$delta&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nv"&gt;$newHexValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'0'&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;dechex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$red&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nv"&gt;$delta&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'0'&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;dechex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$green&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'0'&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;dechex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$blue&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;isset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$gradients&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$newHexValue&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$gradients&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$newHexValue&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$green&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$delta&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nv"&gt;$newHexValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'0'&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;dechex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$red&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'0'&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;dechex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$green&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nv"&gt;$delta&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'0'&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;dechex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$blue&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;isset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$gradients&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$newHexValue&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$gradients&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$newHexValue&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$blue&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$delta&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nv"&gt;$newHexValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'0'&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;dechex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$red&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'0'&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;dechex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$green&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'0'&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;dechex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$blue&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nv"&gt;$delta&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;isset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$gradients&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$newHexValue&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$gradients&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$newHexValue&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$red&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nv"&gt;$delta&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nv"&gt;$newHexValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'0'&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;dechex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$red&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nv"&gt;$delta&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'0'&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;dechex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$green&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'0'&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;dechex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$blue&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;isset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$gradients&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$newHexValue&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$gradients&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$newHexValue&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$green&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nv"&gt;$delta&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nv"&gt;$newHexValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'0'&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;dechex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$red&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'0'&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;dechex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$green&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nv"&gt;$delta&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'0'&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;dechex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$blue&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;isset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$gradients&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$newHexValue&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$gradients&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$newHexValue&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$blue&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nv"&gt;$delta&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nv"&gt;$newHexValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'0'&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;dechex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$red&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'0'&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;dechex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$green&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'0'&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;dechex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$blue&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nv"&gt;$delta&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;isset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$gradients&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$newHexValue&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$gradients&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$newHexValue&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$hex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I was getting the best results when working with 6-10 colors and delta between 20 and 35.&lt;/p&gt;

&lt;p&gt;CSS is pretty simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.gradient-background-animation&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;400%&lt;/span&gt; &lt;span class="m"&gt;400%&lt;/span&gt; &lt;span class="cp"&gt;!important&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;animation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;BackgroundGradient&lt;/span&gt; &lt;span class="m"&gt;10s&lt;/span&gt; &lt;span class="n"&gt;ease&lt;/span&gt; &lt;span class="n"&gt;infinite&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.card-picture-container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.875rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="err"&gt;//&lt;/span&gt; &lt;span class="err"&gt;This&lt;/span&gt; &lt;span class="err"&gt;value&lt;/span&gt; &lt;span class="err"&gt;determines&lt;/span&gt; &lt;span class="err"&gt;how&lt;/span&gt; &lt;span class="err"&gt;big&lt;/span&gt; &lt;span class="err"&gt;the&lt;/span&gt; &lt;span class="err"&gt;"frame"&lt;/span&gt; &lt;span class="err"&gt;will&lt;/span&gt; &lt;span class="err"&gt;be&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.card-picture-container&lt;/span&gt; &lt;span class="nt"&gt;img&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;object-fit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;contain&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;max-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;@keyframes&lt;/span&gt; &lt;span class="n"&gt;BackgroundGradient&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;background-position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;50%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="err"&gt;50&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;background-position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt; &lt;span class="m"&gt;50%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="err"&gt;100&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;background-position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;50%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can adjust the layout and the rest of the styling per your liking.&lt;/p&gt;

&lt;p&gt;HTML:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"container"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"card-picture-container gradient-background-animation"&lt;/span&gt; 
       &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"background-image: linear-gradient(-45deg, #78785a,#5a783c,#3c5a1e,#969678,#b4b4b4,#1e1e1e,#d2d2f0)"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;picture&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/images/source/image.jpeg"&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/picture&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can notice, background is added as inline CSS.&lt;/p&gt;

&lt;p&gt;Final result (size decreased for preview purposes):&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7l6on5o7vetj48tkaj72.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7l6on5o7vetj48tkaj72.png" alt="Grid layout"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I've created a Twig extension (filter) and included it in my Symfony project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="k"&gt;declare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strict_types&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App\Twig&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;App\Service\ColorPaletteExtractor&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Twig\Extension\AbstractExtension&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Twig\TwigFilter&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;GradientExtractorExtension&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;AbstractExtension&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;ColorPaletteExtractor&lt;/span&gt; &lt;span class="nv"&gt;$gradientExtractor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;getFilters&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TwigFilter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'get_gradient'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'getGradient'&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
        &lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;getGradient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$imagePath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$colorsCount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$delta&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$colors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;gradientExtractor&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;extractMainImgColors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$imagePath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$colorsCount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$delta&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="nv"&gt;$filteredColors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;array_filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$colors&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="nv"&gt;$percentage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$percentage&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;','&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;array_map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$color&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'#'&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$color&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;array_keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$filteredColors&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;image-grid.html.twig&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"container"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    {% for image in images %}
        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"card-picture-container gradient-background-animation"&lt;/span&gt;
             &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"background-image: linear-gradient(-45deg, {{ asset(image)|get_gradient(7,30) }}); animation-duration: 8s;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;picture&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"{{ asset(image) }}"&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/picture&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    {% endfor %}
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/gh0c/embed/mdqPMoY?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Photos for testing purposes downloaded from &lt;a href="https://www.parkovihrvatske.hr/parkovi" rel="noopener noreferrer"&gt;https://www.parkovihrvatske.hr/parkovi&lt;/a&gt;&lt;/p&gt;

</description>
      <category>engineeringmonday</category>
      <category>css</category>
      <category>php</category>
      <category>design</category>
    </item>
    <item>
      <title>Awesome Shopify Resources for 2022</title>
      <dc:creator>Mario Loncarek</dc:creator>
      <pubDate>Mon, 14 Feb 2022 09:04:18 +0000</pubDate>
      <link>https://forem.com/bornfightcompany/awesome-shopify-resources-for-2022-3hjh</link>
      <guid>https://forem.com/bornfightcompany/awesome-shopify-resources-for-2022-3hjh</guid>
      <description>&lt;p&gt;Shopify released a lot of new features in 2021, and naturally new tools and resources needed to be developed to cover new features. Next is a list of awesome Shopify Resources for 2022 which will help you to create modern Shopify storefronts.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. &lt;a href="https://github.com/Shopify/dawn"&gt;Dawn&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Dawn is Shopify's own open source theme with performance, flexibility, and Online Store 2.0 features built-in and acts as a reference for building Shopify themes. Its great for using it as a starter theme for your new Shopify project.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. &lt;a href="https://www.figma.com/community/file/1017615468313501249"&gt;Dawn Figma files&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;If you will use Dawn as a starter theme for a Shopify project, Shopify give us this great Figma file with all Dawn's components/sections/templates that you can send to designer to speed up the design process.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. &lt;a href="https://www.shopify.com/markets"&gt;Shopify Markets&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;In my opinion Shopify Markets will be the biggest update to Shopify since releasing Online Store 2.0 but will be even bigger than that. Markets will finally allow us to create Market-specific buying experiences. That means native multiple currencies, languages, language specific domains, duties collection for each market etc. It's currently available as a preview feature so I suggest that you don't sleep on this one!&lt;/p&gt;

&lt;h3&gt;
  
  
  4. &lt;a href="https://hydrogen.shopify.dev"&gt;Hydrogen&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Another great open source Shopify resource, but this time for creating headless experience. Hydrogen is React-based framework for building custom storefronts on Shopify which gives you everything you need to start fast, build fast, and deliver the best personalised shopping experiences.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. &lt;a href="https://github.com/idbakkasse/helium"&gt;Helium&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Helium is a great resource for using newest Online Store 2.0 features with modern build tools. Helium will allow you to use ES6, SCSS and hot module reloading for both. Great to use in combination with Shopify's Dawn.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. &lt;a href="https://github.com/ndimatteo/HULL"&gt;HULL&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Hull is another resource for creating headless experiences, but Hull is a complete starter powered by Next.js + Sanity.io. It has a lot of features so you can use it as a complete solution for your headless project.&lt;/p&gt;

&lt;h3&gt;
  
  
  7. &lt;a href="https://github.com/uicrooks/shopify-theme-lab"&gt;Shopify Theme Lab&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Another complete headless solution, but this time for the Vue.js fans, and also you can swap Vue.js for pretty much anything if that stack is not suitable for project.&lt;/p&gt;

&lt;h3&gt;
  
  
  8. &lt;a href="https://github.com/bornfight/goCart.js"&gt;goCart.js&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;A complete open source Shopify Ajax cart solution written in vanilla JS. This plugin includes Ajax cart drawer, Ajax mini cart, add to cart modal, and error modal. Developed by Bornfight's frontend team and new, re-written version will be released this year. &lt;/p&gt;

</description>
      <category>engineeringmonday</category>
      <category>shopify</category>
      <category>resource</category>
      <category>ecommerce</category>
    </item>
    <item>
      <title>Fastest Symfony authentication - AWS Cognito integration</title>
      <dc:creator>Alen Pokos</dc:creator>
      <pubDate>Mon, 07 Feb 2022 09:35:26 +0000</pubDate>
      <link>https://forem.com/bornfightcompany/fastest-symfony-authentication-aws-cognito-integration-583i</link>
      <guid>https://forem.com/bornfightcompany/fastest-symfony-authentication-aws-cognito-integration-583i</guid>
      <description>&lt;p&gt;If you either love AWS services already, or are looking for a good option to use with your multiplatform products, AWS Cognito seems to be a good candidate to adopt into your technical stack.&lt;/p&gt;

&lt;p&gt;For me it was unknown, but once I started digging into it, I find it to solve some problems I was bored with solving.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup Cognito on AWS
&lt;/h2&gt;

&lt;p&gt;For starters, we should prepare our Cognito user pool.&lt;br&gt;
We can do this via AWS UI. On the Cognito page we select "Create new user pool".&lt;br&gt;
There are no really special settings you need to configure upon creation,&lt;br&gt;
so choose either default settings or settings that fit your needs.&lt;/p&gt;

&lt;p&gt;Only thing we need from user pool is to setup APP client.&lt;br&gt;
Configure the APP client as you need.&lt;br&gt;
For the callback URL we will target symfony route &lt;code&gt;/security/cognito/check&lt;/code&gt; ie: &lt;code&gt;http://localhost:8000/security/cognito/check&lt;/code&gt;.&lt;br&gt;
If using local Symfony, be careful about using http or https domains. Spent some time to figure that one out because I was reckless :D.&lt;/p&gt;
&lt;h2&gt;
  
  
  Symfony
&lt;/h2&gt;

&lt;p&gt;At the time of writing this article, Symfony 6 was the newest version and used to test this code.&lt;/p&gt;
&lt;h2&gt;
  
  
  Symfony installation
&lt;/h2&gt;

&lt;p&gt;To be able to follow this post, you should either have an existing Symfony project or create a new one.&lt;br&gt;
For ease of example, I will provide quick intro how to set up a new clean Symfony project.&lt;/p&gt;

&lt;p&gt;We start with the new symfony project &lt;code&gt;symfony new --webapp .&lt;/code&gt;&lt;br&gt;
Please, see &lt;a href="https://symfony.com/doc/current/setup.html"&gt;Documentation&lt;/a&gt; on installation and setup of Symfony project.&lt;/p&gt;

&lt;p&gt;To verify we installed successfully, we can run server using &lt;code&gt;symfony server:start&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Install and configure packages for Cognito integration
&lt;/h2&gt;

&lt;p&gt;Now that we have Symfony and Cognito ready, we can begin integration into our Symfony application.&lt;br&gt;
We will use &lt;code&gt;knpuniversity&lt;/code&gt; bundle that provides variety of built-in connectors, but it is missing Cognito one.&lt;br&gt;
For that, we will install Cognito agent provided by another package.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;composer require knpuniversity/oauth2-client-bundle cakedc/oauth2-cognito&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Once installation is complete we begin to configure the bundle.&lt;br&gt;
Update &lt;code&gt;config/packages/knpu_oauth2_client.yaml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;knpu_oauth2_client:
    clients:
        # configure your clients as described here: https://github.com/knpuniversity/oauth2-client-bundle#configuration
        cognito: # name of our client
            type: 'generic' # type 
            provider_class: '\CakeDC\OAuth2\Client\Provider\Cognito' # class provided by agent package
            client_id: '&amp;lt;AWS_CLIENT_ID&amp;gt;' # Cognito app id
            client_secret: '&amp;lt;AWS_CLIENT_SECRET&amp;gt;' # Cognito app secret
            redirect_route: connect_cognito_check # name of the route where we wanna redirect callback, it mush be same as configued in the Cognito app
            provider_options:
                region: &amp;lt;AWS_REGION&amp;gt;
                cognitoDomain: &amp;lt;AWS_COGNITO_DOMAIN&amp;gt; # Cognito domain, just the domain, without region and aws suffix
                scope: 'email' #scopes configured in cognito
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We also need some Symfony User. If you do not already have this, we can create it now.&lt;br&gt;
If you already have user and user providers, you can skip this part and go to creation of connection controller.&lt;br&gt;
Create user using maker bundle, &lt;code&gt;bin/console make:user&lt;/code&gt; with settings:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;store user in the database: NO # this is for demo purpose. In the real world you would probably wanna store it into a database&lt;/li&gt;
&lt;li&gt;unique property: Email # this can be whatever you need&lt;/li&gt;
&lt;li&gt;Hash/check password: NO # again, if you need it otherwise you can use it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This will generate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;src/Security/User.php&lt;/code&gt; Our User class&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;src/Security/UserProvider.php&lt;/code&gt; User provider class used by Symfony security.
It will also update the security configuration &lt;code&gt;config/packages/security.yaml&lt;/code&gt; with information about our new user provider.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you are not familiar with these terms, I would urge you to read basics of Symfony security in &lt;a href="https://symfony.com/doc/current/security.html"&gt;Symfony Security documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Next we need to create connection controller, that will provide routes and calls to oauth client bundle, ie:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php

namespace App\Controller;

use KnpU\OAuth2ClientBundle\Client\ClientRegistry;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;

class SecurityCognitoController extends AbstractController
{
    /**
     * Link to this controller to start the "connect" process
     */
    #[Route("/login", name:"connect_cognito_start")]
    public function connectAction(ClientRegistry $clientRegistry)
    {
        // will redirect to AWS Cognito!
        return $clientRegistry
            -&amp;gt;getClient('cognito') // key used in config/packages/knpu_oauth2_client.yaml
            -&amp;gt;redirect();
    }

    /**
     * After going to Cognito, you're redirected back here
     * because this is the "callback URL" you configured
     * in AWS Cognito APP settings
     */
    #[Route("/security/cognito/check", name:"connect_cognito_check")]
    public function connectCheckAction(Request $request, ClientRegistry $clientRegistry)
    {
        // ** if you want to *authenticate* the user, then
        // leave this method blank and create a Guard authenticator
    }

    #[Route("/logout", name:"security_logout")]
    public function logout(){}
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Logout is currently not configured, and you can customize this to your needs later.&lt;/p&gt;

&lt;p&gt;Last code class we need to create is custom Authenticator, by following KNP docs and guidelines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php

namespace App\Security;

use CakeDC\OAuth2\Client\Provider\CognitoUser;
use KnpU\OAuth2ClientBundle\Client\ClientRegistry;
use KnpU\OAuth2ClientBundle\Security\Authenticator\OAuth2Authenticator;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport;

class CognitoAuthenticator extends OAuth2Authenticator
{
    private $clientRegistry;
    private $router;

    public function __construct(ClientRegistry $clientRegistry, RouterInterface $router)
    {
        $this-&amp;gt;clientRegistry = $clientRegistry;
        $this-&amp;gt;router = $router;
    }

    public function supports(Request $request): ?bool
    {
        // continue ONLY if the current ROUTE matches the check ROUTE
        return $request-&amp;gt;attributes-&amp;gt;get('_route') === 'connect_cognito_check';
    }

    public function authenticate(Request $request): Passport
    {
        $client = $this-&amp;gt;clientRegistry-&amp;gt;getClient('cognito');
        $accessToken = $this-&amp;gt;fetchAccessToken($client);

        // NOTE: Here you can store token into session if you are using stateful authentication.

        return new SelfValidatingPassport(
            new UserBadge($accessToken-&amp;gt;getToken(), function() use ($accessToken, $client) {
                /** @var CognitoUser $user */
                $cognitoUser = $client-&amp;gt;fetchUserFromToken($accessToken);

                // NOTE: here you can load/save user from storage such as database

                $user = new User();
                $user-&amp;gt;setEmail($cognitoUser-&amp;gt;getEmail());
                return $user;
            })
        );
    }

    public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
    {
        // change "app_homepage" to some route in your app
        $targetUrl = $this-&amp;gt;router-&amp;gt;generate('app_homepage');

        return new RedirectResponse($targetUrl);

        // or, on success, let the request continue to be handled by the controller
        //return null;
    }

    public function onAuthenticationFailure(Request $request, AuthenticationException $exception): ?Response
    {
        $message = strtr($exception-&amp;gt;getMessageKey(), $exception-&amp;gt;getMessageData());

        return new Response($message, Response::HTTP_FORBIDDEN);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Please note the &lt;code&gt;targetUrl&lt;/code&gt; in the &lt;code&gt;onAuthenticationSuccess&lt;/code&gt; method. Customize this to your needs.&lt;br&gt;
I will also provide simple controller at the end of the article for convenience of testing.&lt;/p&gt;

&lt;p&gt;Last thing is to update our &lt;code&gt;security.yaml&lt;/code&gt; configuration to use our custom provider:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
firewalls:
    ...
    main:
        ...
        custom_authenticator: App\Security\CognitoAuthenticator
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the main subsection, not the entire contents of the file. For our configuration, we only needed to add &lt;code&gt;custom_authenticator&lt;/code&gt; setting that is our authenticator class.&lt;/p&gt;

&lt;p&gt;Once done and you try it, by opening &lt;code&gt;http://localhost:8000/login&lt;/code&gt; you should be redirected to AWS hosted login page.&lt;br&gt;
After you login you will be redirected back to your symfony site with error exception from &lt;code&gt;UserProvider::refreshUser&lt;/code&gt;.&lt;br&gt;
If you just wish to try it out, you can &lt;code&gt;return $user&lt;/code&gt; in this method.&lt;br&gt;
Important!! This is for testing only, and it is not good practice. You should fit this to your implementation.&lt;/p&gt;

&lt;p&gt;If you wish to see try it out, here is a simple test controller:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php

namespace App\Controller;

use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Security;

final class DefaultController
{
    #[Route("/", name:"app_homepage")]
    #[IsGranted("ROLE_USER")]
    public function __invoke(Security $security): Response
    {
        // we return with html head and body tags as this is needed by Symfony profiler to attach to the page 
        return new Response(sprintf("&amp;lt;html&amp;gt;&amp;lt;head&amp;gt;&amp;lt;/head&amp;gt;&amp;lt;body&amp;gt;Welcome %s&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;", $security-&amp;gt;getUser()-&amp;gt;getUserIdentifier()));
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and you also need to update &lt;code&gt;services.yml&lt;/code&gt; and add section load new controller:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    ...

    # controllers are imported separately to make sure services can be injected
    # as action arguments even if you don't extend any base controller class
    App\Controller\:
        resource: '../src/Controller/'
        tags: [ 'controller.service_arguments' ]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And there you have it. You can login into your Symfony application using AWS Cognito.&lt;/p&gt;

&lt;p&gt;Feel free to clean up the code, improve the security of it and make it ready for the real world.&lt;/p&gt;

&lt;p&gt;Security is important and sometimes hard topic. I would urge you to read &lt;a href="https://symfony.com/doc/current/security.html"&gt;Symfony Security documentation&lt;/a&gt; to better understand how it works, what are good practices and how to avoid pitfalls.&lt;/p&gt;

&lt;p&gt;Have fun coding, creating and learning.&lt;/p&gt;

</description>
      <category>engineeringmonday</category>
      <category>aws</category>
      <category>authentication</category>
      <category>php</category>
    </item>
    <item>
      <title>5 tips I wish I knew as a junior developer</title>
      <dc:creator>Mario Loncarek</dc:creator>
      <pubDate>Mon, 31 Jan 2022 11:34:08 +0000</pubDate>
      <link>https://forem.com/bornfightcompany/5-tips-i-wish-i-knew-as-a-junior-developer-38a1</link>
      <guid>https://forem.com/bornfightcompany/5-tips-i-wish-i-knew-as-a-junior-developer-38a1</guid>
      <description>&lt;p&gt;Here are some tips for junior developers or everyone who just started taking interest in becoming professional in the area, but especially for those who want to progress as quickly as possible. These tips come from my own personal experience and from mistakes I made which resulted in stagnation of my progress.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Kill the ego
&lt;/h2&gt;

&lt;p&gt;This is the most important one. Stop thinking that you already know everything. Stop trying to get attention to show how much you know. Stop saying “I know that”. Relax - everybody knows that you are a junior, they know how much you know and they shape your tasks to fit that fact. &lt;/p&gt;

&lt;p&gt;Coming into an agency environment for the first time in your life and thinking that you know something is a good sign of the level you are on. Know that every junior is a company’s investment for the future. It’s not expected that you make money for the company right away because you could not be independent in your work - when you’re a junior, there will always be someone checking after you, mentoring you and helping you when you get stuck. It's OK not to know everything and accept that, you are here to learn and that is what being a junior is. &lt;/p&gt;

&lt;p&gt;Killing your ego is the first step in making progress. Thinking that you know everything is the biggest blocker you can do for yourself, and you will not progress or grow until you completely eliminate your ego. Stay humble, hustle hard.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Request a good mentorship
&lt;/h2&gt;

&lt;p&gt;Now that you are ready to really learn and understand where you are, and on your path to becoming a better developer and worker, it’s time to understand how important it is to have a good mentor. I was very lucky to have the best possible person to mentor me, which made my skills skyrocket in a year or two. If you don't have one, request this from your company first thing in the morning. If a company would not provide you with a mentor, leave the company, that's not a good place for a junior developer, and it also shows red flags about how other aspects of the company are handled.&lt;/p&gt;

&lt;p&gt;Good mentor is a life hack in becoming a really good developer and useful for your company in much less time than it would take you alone (we are talking years here). A mentor will give you all of the answers you need many times faster than Google or Stack Overflow will. Take every advice you can from a mentor, squeeze as much information as you can and absorb like a sponge. Realize what mindset you need in order to be on your mentor’s level. It’s really important to learn how to listen - you are here to ask questions and not to be smart. Insist on constant code reviews, and insist on them to be very critical, and understand that critical code reviews are for your own good. Never take them personally. &lt;/p&gt;

&lt;p&gt;Never forget to respect your mentor because he is putting a lot of time and effort into making you a good developer and that is a very hard job to do, because knowing how to be a good mentor is a science on its own.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Show initiative
&lt;/h2&gt;

&lt;p&gt;If you want to stand out as a motivated worker, show initiative. That’s what separates people who are only doing their jobs from someone who wants to grow constantly. And that’s what being a good worker really is - a person who is highly motivated and shows initiative. That kind of person adds value to the company and pushes things to be done. &lt;/p&gt;

&lt;p&gt;Give constructive suggestions. Take the hardest task that no one else wants. Take ownership of the things you are doing and take responsibility for how they are done. But try to be useful while doing it, don’t just do things for the sake of doing them to show off - meaning don’t be fake!&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Be the hardest working individual
&lt;/h2&gt;

&lt;p&gt;Work hard and stay hungry. Seek to be the best developer in your company, but compete only with yourself. Not everyone has the same timeline, so never compare yourself to others. You are on your own path and things will come - and that will only depend on you. &lt;/p&gt;

&lt;p&gt;Difference between being good and being great is proportional with the hard work you are willing to invest in your skill. Most of the time this will mean going an extra mile in your free time. Having a good life/work balance is important, but I do not regret working hard after my 9-5 job when I needed to understand things deeper because it helped me to get where I wanted to be and to learn much faster.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Understand how business really works
&lt;/h2&gt;

&lt;p&gt;Don't think about the money at all as a junior developer. Only focus on learning, progressing and gathering real experience. You want to be on a level on which you are useful for the company and you can create real revenue with the work you do. Until that point you really don't have many arguments for some crazy salary. Money will come naturally, and a good company will never exploit your level, so don’t worry about being hungry, or recognize another red flag of a bad company. &lt;/p&gt;

&lt;p&gt;But don’t fool yourself - realize early that when talking about the business side of everything, in the end it’s all about the money. Your salary depends on how much money you can earn for the company through your work. Companies can not do business if they are losing money. That's why employing a junior is an investment for the future of the company because companies lose money until you can be independent in your work and become useful. That also means that your salary will be bigger with more useful work you can do if you're into the money thing. &lt;/p&gt;

&lt;p&gt;Of course, you can make more money on your own, but you will never become a great specialist if you don’t start working in the company first - that is where you will be given real experience, big projects and the best possible education. That’s all the things you will not get as a junior developer going on your own. And in my opinion, that will slow your progress - and we’re talking about years here.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;These are the tips that would have helped me a lot throughout my junior years. What do you think about them?&lt;br&gt;
Do you have any other tips or disagreements with any of them? Let me know in the comments.&lt;/p&gt;

</description>
      <category>engineeringmonday</category>
      <category>career</category>
      <category>beginners</category>
      <category>motivation</category>
    </item>
    <item>
      <title>Top 5 essential skills for fresh parents</title>
      <dc:creator>TomislavNovacicBF</dc:creator>
      <pubDate>Mon, 24 Jan 2022 14:06:58 +0000</pubDate>
      <link>https://forem.com/bornfightcompany/top-5-essential-skills-for-fresh-parents-2jne</link>
      <guid>https://forem.com/bornfightcompany/top-5-essential-skills-for-fresh-parents-2jne</guid>
      <description>&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;This article is all about work-life "balance" and how to continue progressing in your career after the baby comes. I will write about my conclusions and organisation in this new environment. We will wrap things up with 5 essential skills you can work on to prepare yourself for the arrival of the newcomer.&lt;/p&gt;

&lt;h2&gt;
  
  
  The comfort zone
&lt;/h2&gt;

&lt;p&gt;Things are going great, you are learning new stuff and reading work-related articles on a daily basis. You are as motivated as ever, advancing really quickly and on your way to become a ninja developer (or other equivalent role). Your diet is on check and you are getting your workouts in. Nothing can stop you! And then one day you become a parent...&lt;/p&gt;

&lt;h2&gt;
  
  
  The chaos
&lt;/h2&gt;

&lt;p&gt;At the beginning things are going good, but as the baby grows you start to realise that your free time becomes shorter and shorter, and soon enough you will have practically no free time. You now don’t have time for your partner or working out, let alone for personal development.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What to do now? How to continue working on your goals and be there for your child at the same time?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;People always talk about work-life balance and you always thought it was some nonsense that lazy people say? Yeah, me too. Well there is some truth in that approach, because now you just have to make things work somehow. Save yourself a few months (or a year) of getting the hang on things and start working on this skills immediately if you are expecting kids any time soon.&lt;/p&gt;

&lt;h2&gt;
  
  
  Top 5 skills ambitious parent needs
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Time management&lt;/strong&gt;&lt;br&gt;
Day only has 24 hours so try to get the best out of every minute. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Read whenever you have a few minutes to spare.&lt;/strong&gt; Read while your partner is playing with the baby, when you're in the rest room, in the bed after everyone is asleep and you have few atoms of energy left.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Get up early&lt;/strong&gt;. Wake up first and start your day in a complete peace (and use that time wisely).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Work from home&lt;/strong&gt;. If you have the option to work from home, just take it - you’ll save a bunch of commute and getting-ready hours, and you can use that in a better way. If that is not a possibility for you, then travel to work with public transportation so you can do some work while you are on your way to the office. If you, for some reason, prefer the car over public transportation then you can listen to audio books or podcasts while driving.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Don't sacrifice sleep&lt;/strong&gt;, it's counter productive after some time and it's not worth it in the end. Fresh mind = more focus = better productivity and more growth.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;2. Organization&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Try to plan every minute of your day up front&lt;/strong&gt;. This enables you to see how much literature you can consume in a day. According to that you can set realistic goals and don't get frustrated thinking you've done too little that day. When you precisely estimate every action in your day, you unknowingly start to do repetitive tasks even more quickly (eating for example).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;3. Multitasking&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Incorporate learning in any activity that does not require your complete focus&lt;/strong&gt;. Listen to audio books while you are grocery shopping, cleaning, cooking, in the gym or walking a dog. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;4. Focus&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Focus 110% while working&lt;/strong&gt;. That is the only time of the day that is strictly dedicated for your work and personal growth. It’s also the only time when you’ll have complete peace and no distractions. You’ll start to appreciate those hours more.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Start adjusting to working in non-ideal environments&lt;/strong&gt;. There will be times when you have to work or read and kids are screaming and running around, and you have to get used to it (it gets better over time I promise).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;5. Dedication&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Prioritise&lt;/strong&gt;. Not all things you stumble upon on your go-to reading materials are important for your line of work. Read only about stuff that is applicable to your work and future aspirations, skip the rest. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Delete your social media accounts&lt;/strong&gt; (or leave them but use them responsibly). The same goes for TV and gaming consoles. Time spent on these platforms is valuable and cannot be returned.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;P.S. Don't forget to spend quality time with your family, don't be a stranger. This article focuses on the parts of the day you are "free".&lt;/p&gt;

&lt;p&gt;Did I forget anything? Does any of this sound familiar to you? Feel free to react and comment down below.&lt;/p&gt;

</description>
      <category>engineeringmonday</category>
      <category>productivity</category>
      <category>learning</category>
      <category>motivation</category>
    </item>
    <item>
      <title>iOS Code Review Checklist</title>
      <dc:creator>ivcelic</dc:creator>
      <pubDate>Mon, 17 Jan 2022 16:11:36 +0000</pubDate>
      <link>https://forem.com/bornfightcompany/ios-code-review-checklist-53ia</link>
      <guid>https://forem.com/bornfightcompany/ios-code-review-checklist-53ia</guid>
      <description>&lt;p&gt;To encourage iOS developers to approach code review more throughly we've built a simple check list that should be followed when going through an iOS pull request. &lt;/p&gt;

&lt;p&gt;Of course we do not go through it and add checkmarks on every PR but we use it to remind us from time to time what should we look for when code reviewing. This is also a good start for someone who is new in iOS development or code reviewing in general.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwawzhxix6mpkdti6hg2d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwawzhxix6mpkdti6hg2d.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Are there any merge conflicts in the PR?&lt;/strong&gt; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If yes - return to assignee before looking further into code.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;2. Did the static analysis check run?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;eg. for checking the Swift code style we use Swift Lint&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;3. Check the architecture&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;eg. data should not be fetched or processed in presenters or in views&lt;/li&gt;
&lt;li&gt;eg. views should not be modified in view models&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;4. Is the code consistent with the agreed coding guidelines?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Are there any new Xcode warnings introduced?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjxzq48w4w2qgfnz8asl2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjxzq48w4w2qgfnz8asl2.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. Prefer static constants over computed properties&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Prefer&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;static let c: Int = 1234
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Over&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;static var d: Int { return 1234 }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;7. Check single source of truth principle&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;eg. don’t preserve the same information in multiple places in the code&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;8. Avoid singletons&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;use dependency injection instead&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;9.Look for force unwrapping&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;force unwrap should be avoided (use in &amp;lt; 1% of the cases)&lt;/li&gt;
&lt;li&gt;Using ! should always be a red flag!&lt;/li&gt;
&lt;li&gt;Check if early return from functions (eg. guard) is used&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;10.Constants&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Extract constant to a struct&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;11.Check for magic numbers&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Avoid harcoding, avoid magic numbers, if needed extract into a constant&lt;/li&gt;
&lt;li&gt;If added, magic numbers should be commented&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe3jyv7h8w0webggpx6hg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe3jyv7h8w0webggpx6hg.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;12.Check encapsulation&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Check if public variable or function can be private or private(set)?&lt;/li&gt;
&lt;li&gt;If a class won’t be ever instantiated - use enum instead.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;13.Check polymorphism&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Should we mark the class final?&lt;/li&gt;
&lt;li&gt;Should we use class or static keyword for a function/variable.&lt;/li&gt;
&lt;li&gt;Prefer composition with protocols over inheritance.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;14.Check for single responsability&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The function should have one purpose! Split it in two if makes sense.&lt;/li&gt;
&lt;li&gt;The class should not have too many responsabilities - split if needed.&lt;/li&gt;
&lt;li&gt;Avoid massive view controller, add managers, helpers, utils instead.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fydli4fgvwxzdf2pih7b7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fydli4fgvwxzdf2pih7b7.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;15.Check for explicit use of self keyword&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Explicit (unneeded) use of self should be avoided
because it makes the capturing semantics of self stand out more in closures, and prevents verbosity elsewhere&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;16.Performance check&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;use strings concatenation with /() instead of +&lt;/li&gt;
&lt;li&gt;use isEmpty instead of == nil&lt;/li&gt;
&lt;li&gt;use ! instead of == false&lt;/li&gt;
&lt;li&gt;instantiate DateFormatter only once&lt;/li&gt;
&lt;li&gt;reuse cells&lt;/li&gt;
&lt;li&gt;use image caching &lt;/li&gt;
&lt;li&gt;use background threads where needed&lt;/li&gt;
&lt;li&gt;etc…&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;17.Error handling&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Are all the errors cases handled in code? Log the error, notify the user, retry, fail safely…&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;18.Check security vulnerabilities&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Are there any user passwords or other secrets stored as plain text?&lt;/li&gt;
&lt;li&gt;Is there any sensitive data being logged?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;19.Check naming&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is naming clear and consistent. The naming is important for writing self-documenting code!&lt;/li&gt;
&lt;li&gt;Boolean values should start with is, can, should, will…&lt;/li&gt;
&lt;li&gt;When in doubt - use longer names (adds more information) over shorter names (can bring confusion).&lt;/li&gt;
&lt;li&gt;Use UpperCamelCase for types and protocols, lowerCamelCase for everything else.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd1dzcry28pfy1tocflb8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd1dzcry28pfy1tocflb8.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;20.Check duplicate code&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Duplicate code is a big no no and should be extracted and reused!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;21.Remove unnecessary code&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Remove commented code. You can always get it back with git.&lt;/li&gt;
&lt;li&gt;Remove empty and/or unused variables, functions, imports…&lt;/li&gt;
&lt;li&gt;No need to add explicit init for structs if using only the default initialiser.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;22.Memory leaks&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Closures should use weak self&lt;/li&gt;
&lt;li&gt;Delegates should be weak&lt;/li&gt;
&lt;li&gt;Check if unowned is misused&lt;/li&gt;
&lt;li&gt;Check for any retain cycles&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;23.Check if all strings are localised&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;24.Is the code covered with logs?&lt;/strong&gt; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Every important event in the app should be logged.&lt;/li&gt;
&lt;li&gt;The logs should contain enough information (class, function, parameters, severity).&lt;/li&gt;
&lt;li&gt;Repeating information can pollute the log.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;25.Is the code well documented?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Does every public function contain a comment?&lt;/li&gt;
&lt;li&gt;Does the code contain a comment for every specific part of the code?&lt;/li&gt;
&lt;li&gt;Does every specific class (manager, service, script…) contain a comment about their purpose?&lt;/li&gt;
&lt;li&gt;Does every file contain a copyright?&lt;/li&gt;
&lt;li&gt;Should the README be updated?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhzmqqyyif76p1kmspny8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhzmqqyyif76p1kmspny8.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As mention before, we use this checklist as a reminder and a motivation for doing better code reviews. Thus, we are adding bullets to our checklist and improving it over time. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What would you add to the list?&lt;/strong&gt; 🙂&lt;/p&gt;

</description>
      <category>engineeringmonday</category>
      <category>ios</category>
      <category>codereview</category>
      <category>swift</category>
    </item>
  </channel>
</rss>
