21 Laravel Tutorials for Learning Laravel in 2021

21 Laravel Tutorials for Learning Laravel in 2021

https://ift.tt/3rI359X


2021 is a great time to learn Laravel and improve your knowledge if you’ve been using it. To start the year off we’ve made a list of 21 tutorials on everything from getting started to going deeper with the framework.

Getting Started with Laravel Tutorials

In this step by step Laracasts series, you’ll learn how to build web applications with Laravel. You’ll start with the basics and incrementally dig deeper and deeper, as you review real-life examples. Once complete, you should have all the tools you need.

In this tutorial, you’ll go through building a simple link directory app. It covers everything from planning, setting up your database, Blade views, and more. Join our weekly Laravel newsletter and get this as a free PDF.

As you begin to work with Laravel one thing you should note is how the release process works and when new versions are scheduled to come out.

This is a multiple part series taking you through building a Vue SPA with Laravel. part 1, part 2, part 3, part 4, part 5, and part 6.

Laravel Eloquent

Laravel Eloquent is an object-relational mapper (ORM) that makes it easy to interact with your database. When using Eloquent, each database table has a corresponding “Model” that is used to interact with that table. In addition to retrieving records from the database table, Eloquent models allow you to insert, update, and delete records from the table as well.

At its core Eager Loading, is telling Eloquent that you want to grab a model with specific relationships that way the framework produces a more performant query to grab all the data you will need. By eager loading, you can take many queries down to just one or two.

In this tutorial, you’ll set up some example relationships and then walk through how queries change with and without eager loading.

In this tutorial, we’ll show you more or less hidden secrets, methods, and properties you might not know to improve your code.

Eloquent ORM seems like a simple mechanism, but under the hood, there’s a lot of semi-hidden functions and less-known ways to achieve more with it. In this tutorial, you’ll see and discover a few tricks you might not know about.

If you’ve been working with Laravel for any time, you probably know the standard methods for creating Eloquent Models like make(), create(), update, and save(). Laravel includes some other methods are that also really useful for creating and updating Models that I feel don’t get enough attention. In this tutorial, you’ll learn about some of these additional methods and see how they might be useful.

Laravel Validation

A core part of any project is understanding how to validate the incoming request from your users and in this tutorial let’s look at how we can setup validation with our controllers, form requests, and rules.

Learn how to work with and test string length validation.

Have I been pwned? is a service created by Troy Hunt that aims to archive all data breaches and then allow you to check and see if your email or username has been included in any breaches. It’s a super helpful service to see if your email or password has been found in a breach and in this tutorial learn how to utilize this data in your Laravel Validation

Laravel Helpers

Laravel provides many excellent helper functions that are convenient for doing things like working with arrays, file paths, strings, and routes, among other things like the beloved dd() function. You can also define your own set of helper functions for your Laravel applications and PHP packages, by using Composer to import them automatically.

There are a ton of helper methods in Laravel that make development more efficient. If you work with the framework, I encourage you to see what helpers you can introduce in your day-to-day work. In this post, I’d like to point out a few of my favorites.

Going Deeper

In this tutorial, learn all about Laravel Jobs and Queues by building a simple analytics app.

Sanctum is Laravel’s lightweight API authentication package. In this tutorial, we’ll be looking at using Sanctum to authenticate a React-based single-page app (SPA) with a Laravel backend.

Laravel Model events allow you to tap into various points in a model’s lifecycle, and can even prevent a save or delete from happening. The Laravel model events documentation outlines how you can hook into these events with event classes, and this article aims to build upon and fill in a few additional details on setting up events and listeners.

Having a fast test suite can be just as important as having a fast application. As a developer, getting feedback quickly about the state of your code allows for a much quicker development turnaround. Here we are going to run through some tips you can implement today to make your tests run faster.

In this tutorial, you will create a test case to test the user model and a seeder to seed ten users, and each is following one user into the database.

In this tutorial, get a quick jumpstart on learning how to use routing in your Laravel applications.

Laravel comes with a feature called model factories that are designed to allow you to quickly build out “fake” models. These have several use cases with the two biggest being testing and database seeding. Take a deeper look at this feature in this tutorial

Many great developers could improve and gain some productivity and better tooling in their Terminal, so take a look at this tutorial for improving your productivity.

Wrap up

2020 was quite a strange year for everyone but even during the pandemic Laravel continued releasing new versions, making improvements, and getting better. In 2021, look for the release of Laravel 9 and 10, as well as more conferences, and hopefully more in-person meetups as things go back to normal.

Filed in:
News

programming

via Laravel News https://ift.tt/14pzU0d

January 1, 2021 at 12:09PM

How Zippo Lighters Are Made

How Zippo Lighters Are Made

https://ift.tt/2JxWWMk

How Zippo Lighters Are Made

Link

BRANDMADE.TV takes us inside the Zippo lighter factory for a look at how they create their iconic windproof lighters. The process starts out with rolls of brass which are shaped to form each lighter’s case before it’s chromed. The interior is formed from steel, then brass, flint, a wick, and cotton are added to complete the assembly.

fun

via The Awesomer https://theawesomer.com

December 31, 2020 at 02:00PM

SQL Clause is coming to town

SQL Clause is coming to town

https://ift.tt/2WSmK90

Olya Kudriavtseva has an ugly christmas sweater:

“He’s making a table. He’s sorting it twice. SELECT * FROM contacts WHERE behavior = “nice”; SQL Clause is coming town! (buy here)

Katie Bauer observes:

I mean, except for the fact that sorting something twice is TERRIBLY optimized

So how bad is this? Let’s find out.

Some test data

We are defining a table santa, where we store peoples names (GDPR, EU Regulation 2016/679 applies!), their behavior (naughty or nice), their age, their location, and their wishlist items.

create table santa (
	id integer not null primary key auto_increment,
	name varchar(64) not null,
	loc point srid 0 not null,
	age integer not null,
	behavior enum('naughty', 'nice') not null,
	wish varchar(64) not null
)

We are also writing some code to generate data (to evade GDPR, we are using randomly generated test data):

for i in range(1, size):
	data = {
	    "id": i,
	    "name": "".join([chr(randint(97, 97 + 26)) for x in range(64)]),
	    "xloc": random()*360-180,
	    "yloc": random()*180-90,
	    "age": randint(1, 100),
	    "behavior": "naughty" if random() > nicelevel else "nice",
	    "wish": "".join([chr(randint(97, 97 + 26)) for x in range(64)]),
	}

	c.execute(sql, data)
	if i%1000 == 0:
	    print(f"{i=}")
	    db.commit()

db.commit()

The full data generator is available as santa.py. Note that the data generator there defines more indexes – see below.

In our example we generate one million rows, and assume a general niceness of 0.9 (90% of the children are nice). Also, all of our children have 64 characters long names, a single 64 characters long wish, a random age, and are equidistributed on a perfect sphere.

Our real planet is not a perfect sphere, and also not many people live in the Pacific Ocean. Also, not many children have 64 character names.

Sorting it twice

How do you even sort the data twice? Now, assuming we sort by name, we can run an increasingly deeply nested subquery:

kris@localhost [kris]> select count(*) from santa where behavior = 'nice';
+----------+
| count(*) |
+----------+
|   900216 |
+----------+
1 row in set (0.25 sec)

kris@localhost [kris]> explain select count(*) from santa where behavior = 'nice'\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: santa
   partitions: NULL
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 987876
     filtered: 50.00
        Extra: Using where
1 row in set, 1 warning (0.00 sec)

Note (Code 1003): /* select#1 */ select count(0) AS `count(*)` from `kris`.`santa` where (`kris`.`santa`.`behavior` = 'nice')

Out of 1 million children, we have around 900k nice children. No indexes can be used to resolve the query.

Let’s order by name, using a subquery:

kris@localhost [kris]> explain 
  -> select t.name from (
  ->   select * from santa where behavior = 'nice'
  -> ) as t order by name;
+----+-------------+-------+------------+------+---------------+------+---------+------+--------+----------+-----------------------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows   | filtered | Extra                       |
+----+-------------+-------+------------+------+---------------+------+---------+------+--------+----------+-----------------------------+
|  1 | SIMPLE      | santa | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 987876 |    50.00 | Using where; Using filesort |
+----+-------------+-------+------------+------+---------------+------+---------+------+--------+----------+-----------------------------+
1 row in set, 1 warning (0.00 sec)

Note (Code 1003): /* select#1 */ select `kris`.`santa`.`name` AS `name` from `kris`.`santa` where (`kris`.`santa`.`behavior` = 'nice') order by `kris`.`santa`.`name`

We can already see that the MySQL 8 optimizer recognizes that this subquery can be merged with the inner query, and does this.

This can be done multiple times, but the optimizer handles this just fine:

kris@localhost [kris]> explain 
  -> select s.name from (
  ->   select t.name from (
  ->     select * from santa where behavior = 'nice'
  ->   ) as t order by name
  -> ) as s order by name;
+----+-------------+-------+------------+------+---------------+------+---------+------+--------+----------+-----------------------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows   | filtered | Extra                       |
+----+-------------+-------+------------+------+---------------+------+---------+------+--------+----------+-----------------------------+
|  1 | SIMPLE      | santa | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 987876 |    50.00 | Using where; Using filesort |
+----+-------------+-------+------------+------+---------------+------+---------+------+--------+----------+-----------------------------+
1 row in set, 1 warning (0.00 sec)

Note (Code 1003): /* select#1 */ select `kris`.`santa`.`name` AS `name` from `kris`.`santa` where (`kris`.`santa`.`behavior` = 'nice') order by `kris`.`santa`.`name`

We can see using filesort, so while we ask for the query result to be sorted by name twice, it is actually only sorted once.

No sorting at all

We can improve on this, using a covering index in appropriate order:

kris@localhost [kris]> alter table santa add index behavior_name (behavior, name);
Query OK, 0 rows affected (21.82 sec)
Records: 0  Duplicates: 0  Warnings: 0

Having done this, we now see that we lost the using filesort altogether:

kris@localhost [kris]> explain select s.name from ( select t.name from (select * from santa where behavior = 'nice') as t order by name ) as s order by name;
+----+-------------+-------+------------+------+---------------+---------------+---------+-------+--------+----------+--------------------------+
| id | select_type | table | partitions | type | possible_keys | key           | key_len | ref   | rows   | filtered | Extra                    |
+----+-------------+-------+------------+------+---------------+---------------+---------+-------+--------+----------+--------------------------+
|  1 | SIMPLE      | santa | NULL       | ref  | behavior_name | behavior_name | 1       | const | 493938 |   100.00 | Using where; Using index |
+----+-------------+-------+------------+------+---------------+---------------+---------+-------+--------+----------+--------------------------+
1 row in set, 1 warning (0.00 sec)

Note (Code 1003): /* select#1 */ select `kris`.`santa`.`name` AS `name` from `kris`.`santa` where (`kris`.`santa`.`behavior` = 'nice') order by `kris`.`santa`.`name`

The query is now annotated using index, which means that all data we ask for is present in the (covering) index behavior_name, and is stored in sort order. That means the data is physically stored and read in sort order and no actual sorting has to be done on read – despite us asking for sorting, twice.

Hidden ‘SELECT *’ and Index Condition Pushdown

In the example above, we have been asking for s.name and t.name only, and because the name is part of the index, using index is shown to indicate use of a covering index. We do not actually go to the table to generate the result set, we are using the index only.

Now, if we were to ask for t.* in the middle subquery, what will happen?

kris@localhost [kris]> explain
  -> select s.name from (
  ->   select * from (
  ->     select * from santa where behavior = 'nice'
  ->   ) as t order by name
  -> ) as s order by name;
+----+-------------+-------+------------+------+---------------+---------------+---------+-------+--------+----------+-----------------------+
| id | select_type | table | partitions | type | possible_keys | key           | key_len | ref   | rows   | filtered | Extra                 |
+----+-------------+-------+------------+------+---------------+---------------+---------+-------+--------+----------+-----------------------+
|  1 | SIMPLE      | santa | NULL       | ref  | behavior_name | behavior_name | 1       | const | 493938 |   100.00 | Using index condition |
+----+-------------+-------+------------+------+---------------+---------------+---------+-------+--------+----------+-----------------------+
1 row in set, 1 warning (0.00 sec)

Note (Code 1003): /* select#1 */ select `kris`.`santa`.`name` AS `name` from `kris`.`santa` where (`kris`.`santa`.`behavior` = 'nice') order by `kris`.`santa`.`name`

In the Code 1003 Note we still see the exact same reconstituted query, but as can be seen in the plan annotastions, the internal handling changes – so the optimizer has not been working on this query at all times, but on some intermediary representation.

The ‘using index condition’ annotation points to Index Condition Pushdown Optimization being used. In our example, this is not good.

Worse than sorting: Selectivity

The column we select on is a column with a cardinality of 2: behavior can be either naughty or nice. That means, in an equidistribution, around half of the values are naughty, the other half is nice.

Data from disk is read in pages of 16 KB. If one row in a page matches, the entire page has to be read from disk. In our example, we have a row length of around 200 Byte, so we end up with 75-80 records per page. Half of them will be nice, so with an average of around 40 nice records per page, we will very likely have to read all pages from disk anyway.

Using the index will not decrease the amount of data read from disk at all. In fact we will have to read the index pages on top of the data pages, so using an index on a low cardinality column has the potential of making the situation slightly worse than even a full table scan.

Generally speaking, defining an index on a low cardinality column is usually not helpful – if there are 10 or fewer values, benchmark carefully and decide, or just don’t define an index.

In our case, the index is not even equidistributed, but biased to 90% nice. We end up with mostly nice records, so we can guarantee that all data pages will be read for the SQL SELECT * FROM santa WHERE behavior = "nice", and the index usage will not be contributing in any positive way.

We could try to improve the query by adding conditions to make it more selective. For example, we could ask for people close to our current position, using an RTREE index such as this:

kris@localhost [kris]> ALTER TABLE santa ADD SPATIAL INDEX (loc);
...
kris@localhost [kris]> set @rect = 'polygon((10 10, 10 20, 20 20, 20 10, 10 10 ))';
kris@localhost [kris]> select * from santa where mbrcovers(st_geomfromtext(@rect), loc);
...
1535 rows in set (3.53 sec)

The ALTER defines a spatial index (an RTREE), which can help to speed up coordinate queries.

The SET defines a coordinate rectangle around our current position (supposedly 15/15).

We then use the mbrcovers() function to find all points loc that are covered by the @rect. It seems to be somewhat complicated to get MySQL to actually use the index, but I have not been investigating deeply.

If we added an ORDER BY name here, we would see using filesort again, because data is retrieved in RTREE order, if the index loc is used, but we want output in name order.

Conclusion

  • The Santa query is inefficient, but likely sorting twice is not the root cause for that.
    • The optimizer will be able to merge the multiple sorts and be able to deliver the result with one or no sorting, depending on our index construction.
    • The optimizer is not using the reconstituted query shown in the warning to plan the execution, and that is weird.
  • Selectivity matters, especially for indices on low cardinality columns.
    • Asking for all nice behaviors on a naughty/nice column is usually not benefitting from index usage.
    • Additional indexable conditions that improve selectivity can help, a lot.

technology

via Planet MySQL https://ift.tt/2iO8Ob8

December 30, 2020 at 06:56AM

How Golf Balls Are Made

How Golf Balls Are Made

https://ift.tt/2L2Pfya

How Golf Balls Are Made

Link

Tens of millions of golf balls are made every year. In this clip from Golf Town, they take us inside one of Titleist’s factories to see how they make their Pro V1 and Pro V1x golf balls. The process starts with a rubber sheet, which is formed and smoothed, then encased in a dimpled urethane covering before painting and packaging.

fun

via The Awesomer https://theawesomer.com

December 30, 2020 at 08:00AM

OK, gun nuts, this one’s for you!

OK, gun nuts, this one’s for you!

https://ift.tt/38L7Yq5

 

Ian McCollum of Forgotten Weapons has just released his latest video, in which he examines the firearms used in the original Star Wars movie, released in 1977.  They were based on real firearms, but embellished with add-on components and props to look more like science fiction weapons.

I found the presence of an OEG (occluded eye gunsight) particularly interesting, because this was originally developed in South Africa (a few years after Star Wars came out).  I used one of the first models to be produced there, and found it intriguing.  Basically, one doesn’t look through the sight at all:  it’s a solid object that can’t be seen through.  One keeps both eyes open, so that with one eye one sees the target, and with the other the red dot image in the otherwise blank sight.  One’s brain superimposes the dot on the target, making it relatively easy to hit what one’s aiming at.

I must admit, though, I prefer today’s red dot sights, where I can see the target through the sight.

Peter

non critical

via Bayou Renaissance Man https://ift.tt/1ctARFa

December 30, 2020 at 01:05PM

Add All the Ports to Your Laptop with $34 off Vava’s 12-in-1 Docking Station

Add All the Ports to Your Laptop with $34 off Vava’s 12-in-1 Docking Station

https://ift.tt/2EONRMO


Best Tech DealsBest Tech DealsThe best tech deals from around the web, updated daily.

Vava 12-in-1 USB-C Docking Station | $66 | Amazon | Clip coupon + code: KINJA1228

Many laptops these days sacrifice extensive ports in the favor of being as thin and light as possible, which has its obvious benefits and drawbacks. That’s great for easy portability, but can sometimes be a drag when you need to plug in a device or if you want to make your laptop the center of a more robust home office setup.

There are all sorts of USB-C hubs available, but Vava’s 12-in-1 Docking Station is one of the most port-packed options we’ve seen at an affordable price. Simply plug it into a USB-C port and you’ll add two USB 3.0 ports, two USB 2.0 ports, a USB-C PD port, SD and microSD card readers, an Ethernet port, a 3.5mm headphone jack, DC in port, and two HDMI ports. Those HDMI ports enable dual-monitor 4K/60fps action with compatible laptops, letting you turn your slim notebook into a beast of a home PC.

The Vava 12-in-1 Docking Station usually runs $100, but right now when you clip the Amazon coupon and input the exclusive promo code KINJA1228, you’ll drop it down to just $66. If you need a more robust hub like this, it’s a bargain.

G/O Media may get a commission

This deal was originally published in October 2020 by Andrew Hayward and was updated with new information on 12/28/2020.


Tech

via Lifehacker https://lifehacker.com

December 28, 2020 at 01:48PM

Python Dash: How to Build a Beautiful Dashboard in 3 Steps

Python Dash: How to Build a Beautiful Dashboard in 3 Steps

https://ift.tt/2Kx8Arx

Data visualization is an important toolkit for a data scientist. Building beautiful dashboards is an important skill to acquire if you plan to show your insights to a C-Level executive. In this blog post you will get an introduction to a visualization framework in Python. You will learn how to build a dashboard from fetching the data to creating interactive widgets using Dash – a visualization framework in Python.

Introduction to Dash

The dash framework can be divided into two components

  1. Layouts: Layout is the UI element of your dashboard. You can use components like Button, Table, Radio buttons and define them in your layout.
  2. Callbacks: Callbacks provide the functionality to add reactivity to your dashboard. It works by using a decorator function to define the input and output entities. 

In the next section you will learn how to build a simple dashboard to visualize the marathon performance from 1991 to 2018. 

Importing the libraries

Let us first import all the import libraries

import dash
import dash_core_components as dcc
import dash_html_components as html
import dash_split_pane
import plotly.express as px
import pandas as pd
from datetime import datetime

We are importing the pandas library to load the data and the dash library to build the dashboard. 

The plotly express library is built on top of ploty to provide some easy-to-use functionalities for data visualization.

First we will begin by downloading the data. The data can be accessed on Kaggle using the following link   

Step 1: Initializing a Dash App

We start by initializing a dash app and using the command run_server to start the server.

external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
 
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
 
 
if __name__ == '__main__':
   app.run_server(debug=True)

Step 2: Building the Layout

We will start by dividing our UI layer into two parts  – the left pane will show the settings window which will include an option to select the year. The right pane will include a graphical window displaying a bar plot.

app.layout = html.Div(children=[
   html.H1(children='World Marathon Analysis',
    style={'textAlign': 'center'}),
  
   dash_split_pane.DashSplitPane(
   children=[
  
   html.Div(children=[
        html.H1(children='Settings', style={'textAlign': 'center'}),
           ], style={'margin-left': '50%', 'verticalAlign': 'middle'}),
   html.Div(children=[
        html.H1(children='Graph View', style={'textAlign': 'center'}),
            ])
   ],
   id="splitter",
   split="vertical",
   size=1000,
)
  
])

We construct two div elements- one for the left pane and the other for the right pane. To align the header elements to the center we use the style tag and using standard CSS syntax to position the HTML elements.

If you now start the server and go to your browser on localhost:8050, you will see the following window.

Step 3: Creating the Dropdown Widget and the Graphical Window

Once we have the basic layout setup we can continue with the remaining parts.

Loading the Data  

We begin by loading the data using the pandas library

def convert_to_time(time_in_some_format):
   time_obj =  datetime.strptime(time_in_some_format, '%H:%M:%S').time()
   return time_obj
 
def get_data():
  df = pd.read_csv('world_marathon_majors.csv', engine="python")
  df['time'] = df['time'].apply(convert_to_time)
  return df

We create two functions to load the data and convert the time value to datetime object values.

The table below shows the first five rows of the dataset.

Every row consists of

  1. The Year the marathon took place
  2. The winner of the marathon in that year
  3. The gender of the winner
  4. The country the winner represents
  5. The time to finish the race
  6. The country in which the marathon took place.

Extending the Layout

The next step is to extend our layout layer by adding the dropdown widget and the graphical window.

app.layout = html.Div(children=[
   html.H1(children='World Marathon Analysis',
    style={'textAlign': 'center'}),
  
   dash_split_pane.DashSplitPane(
   children=[
  
   html.Div(children=[
        html.H1(children='Settings', style={'textAlign': 'center'}),
        dcc.Dropdown(id='dropdown-menu', options=[{'label':x, 'value': x} for x in range(df['year'].min(), df['year'].max()+1)],
         value=df['year'].max(),
         style={'width': '220px','font-size': '90%','height': '40px',}
        )
    ], style={'margin-left': '50%', 'verticalAlign': 'middle'}),
   html.Div(children=[
        html.H1(children='Graph View', style={'textAlign': 'center'}),
        dcc.Graph( id='input-graph',figure=get_default_data())
    ]) 
   ],
   id="splitter",
   split="vertical",
   size=1000,
)
])

We give the dropdown widget a unique id called dropdown-menu and the graphical window is given an id input-graph. 

Callbacks

Callbacks are used to enable communication between two widgets. 

We define a function called update_output_div which takes the year value whenever the dropdown menu is changed. On every change in the dropdown value the function update_output_div is executed and a bar plot is drawn to indicate the top countries which won the race.

@app.callback(
   dash.dependencies.Output('input-graph', 'figure'),
   [dash.dependencies.Input('dropdown-menu', 'value')]
)
def update_output_div(value):
   test_sample = df[df['year'] == value]
   test_sample = test_sample.groupby('country')['time'].min().reset_index()
   tt = test_sample.sort_values(by=['time'])
   fig = px.bar(tt, y='country', x='time', orientation='h', hover_data=["time"], )
   return fig

Live Demo

Let us now see the dashboard in action.

In this blog post you learned how to build a simple dashboard in Python. You can extend the above dashboard to include more widgets and displaying more graphs for further analysis.

The post Python Dash: How to Build a Beautiful Dashboard in 3 Steps first appeared on Finxter.

Python

via Finxter https://ift.tt/2HRc2LV

December 28, 2020 at 10:59AM

2-Acre Vertical Farm Run By AI and Robots Out-Produces 720-Acre Flat Farm

2-Acre Vertical Farm Run By AI and Robots Out-Produces 720-Acre Flat Farm

https://ift.tt/3rxeZDx

schwit1 quotes Intelligent Living: Plenty is an ag-tech startup in San Francisco, co-founded by Nate Storey, that is reinventing farms and farming. Storey, who is also the company’s chief science officer, says the future of farms is vertical and indoors because that way, the food can grow anywhere in the world, year-round; and the future of farms employ robots and AI to continually improve the quality of growth for fruits, vegetables, and herbs. Plenty does all these things and uses 95% less water and 99% less land because of it. Plenty’s climate-controlled indoor farm has rows of plants growing vertically, hung from the ceiling. There are sun-mimicking LED lights shining on them, robots that move them around, and artificial intelligence (AI) managing all the variables of water, temperature, and light, and continually learning and optimizing how to grow bigger, faster, better crops. These futuristic features ensure every plant grows perfectly year-round. The conditions are so good that the farm produces 400 times more food per acre than an outdoor flat farm. Another perk of vertical farming is locally produced food. The fruits and vegetables aren’t grown 1,000 miles away or more from a city; instead, at a warehouse nearby. Meaning, many transportation miles are eliminated, which is useful for reducing millions of tons of yearly CO2 emissions and prices for consumers. Imported fruits and vegetables are more expensive, so society’s most impoverished are at an extreme nutritional disadvantage. Vertical farms could solve this problem.


Read more of this story at Slashdot.

geeky

via Slashdot https://slashdot.org/

December 27, 2020 at 07:28PM

A question from my childhood answered

A question from my childhood answered

https://ift.tt/3nPQIGt

I saw this posted at Wirecutter’s.

I grew up with the audiobooks of James Herriot’s All Creatures Great and Small series, narrated by Christopher Timothy, who played James Herriot MRCVS in the BBC series (which I also love).

A few times n the book series, James mentions having to put down an animal with a humane killer.  I never knew that was a specific device until I saw this video.

I found this extremely interesting because it answered a question from my childhood that I never knew I had.

guns

via https://gunfreezone.net

December 26, 2020 at 06:25AM

How Gift Wrapping Paper is Made: Rotary Screen Printing

How Gift Wrapping Paper is Made: Rotary Screen Printing

https://ift.tt/2KvoT85

If you thought gift wrapping paper was wasteful as an end product, wait ’til you see the production method. In rotary screen printing, each color requires its own copper cylinder:

Source

Here’s a more in-depth look at how the process works:

I’ll stick with newspaper.

fun

via Core77 https://ift.tt/1KCdCI5

December 23, 2020 at 12:49PM