Bella Alice

Bella Alice

1602572608

Un móvil con una pantalla correctamente pixelada

¿Buscas tonos de llamada gratis para iPhone? Así que ha comprado un nuevo iPhone ingenioso y no debe esperar para comenzar. Dado el uso del iPhone, el mercado secundario es simplemente enorme. Un simple imperio de miles de millones de dólares solo para atender a las aplicaciones y productos de iPhone. Los tonos de llamada gratuitos para iPhone son simplemente una pequeña parte de la imagen. Existe un gran mercado para aplicaciones, imágenes, fondos de pantalla, animaciones, temas, juegos, widgets y mucho más específicos para iPhone.
Adquieres nuevos tipos. Hay muchos sitios de Internet donde puede comprarlos o puede obtener otros nuevos de su proveedor de tonos de llamada, pero rara vez puede encontrar lo que realmente desea, cuando no son valiosos. Si decide modificar el suyo una y otra vez, le costará una fortuna. Podrías vivir un problema con el mismo tono de llamada aburrido día tras día, pero afortunadamente, hay una opción más para una persona personalmente. Afortunadamente, estas opciones son más fáciles, más baratas, más divertidas, más únicas y una buena opción en el mercado.
Obtenerlos de forma gratuita puede convertirse en un poco difícil, especialmente en sitios web y foros basados en la web. El suministro de descargas gratuitas de tonos de llamada no es solo una broma. Hay muchos sitios que podrían ofrecer para obtener definitivamente los tonos de llamada de las canciones favoritas, pero debería para comprarlo de ambos. Mirar tu biblioteca de música y desear si es posible disfrutarlos se convierten en tus tonos de llamada pero no entenderás cómo. Entonces no busques más porque puedo compartir el secreto de crear tonos de llamada personalizados para iPhone de forma legal y gratuita.

#tonosgratis #tonosdellamada

What is GEEK

Buddha Community

Un móvil con una pantalla correctamente pixelada
 Bella Alice

Bella Alice

1602572608

Un móvil con una pantalla correctamente pixelada

¿Buscas tonos de llamada gratis para iPhone? Así que ha comprado un nuevo iPhone ingenioso y no debe esperar para comenzar. Dado el uso del iPhone, el mercado secundario es simplemente enorme. Un simple imperio de miles de millones de dólares solo para atender a las aplicaciones y productos de iPhone. Los tonos de llamada gratuitos para iPhone son simplemente una pequeña parte de la imagen. Existe un gran mercado para aplicaciones, imágenes, fondos de pantalla, animaciones, temas, juegos, widgets y mucho más específicos para iPhone.
Adquieres nuevos tipos. Hay muchos sitios de Internet donde puede comprarlos o puede obtener otros nuevos de su proveedor de tonos de llamada, pero rara vez puede encontrar lo que realmente desea, cuando no son valiosos. Si decide modificar el suyo una y otra vez, le costará una fortuna. Podrías vivir un problema con el mismo tono de llamada aburrido día tras día, pero afortunadamente, hay una opción más para una persona personalmente. Afortunadamente, estas opciones son más fáciles, más baratas, más divertidas, más únicas y una buena opción en el mercado.
Obtenerlos de forma gratuita puede convertirse en un poco difícil, especialmente en sitios web y foros basados en la web. El suministro de descargas gratuitas de tonos de llamada no es solo una broma. Hay muchos sitios que podrían ofrecer para obtener definitivamente los tonos de llamada de las canciones favoritas, pero debería para comprarlo de ambos. Mirar tu biblioteca de música y desear si es posible disfrutarlos se convierten en tus tonos de llamada pero no entenderás cómo. Entonces no busques más porque puedo compartir el secreto de crear tonos de llamada personalizados para iPhone de forma legal y gratuita.

#tonosgratis #tonosdellamada

Diego  Elizondo

Diego Elizondo

1652926080

Cómo Construir Un Analizador En Rust Por Diversión Y Ganancias

Un viernes por la mañana, holgazaneando, estás pensando en los nuevos programas de Netflix para ver. Su jefe viene y le pide que escriba un analizador para un archivo de unidad de Systemd .

Lo necesita para el lunes.

Cada vez que pensabas que el fin de semana estaba disponible

Estás nervioso.

La última vez que se le pidió que escribiera un analizador, se metió en la madriguera del conejo de la web, copiando y pegando fórmulas Regex hasta que funcionó™.

Básicamente lo que todos los desarrolladores habían hecho (sangre en la mano)

Tomas un sorbo de tu té de boba para calmarte. Buscas Systemd en Google y te gusta... no, no es tan simple como pensabas.

Ese sentimiento cuando estás tan desesperado porque te quitan el fin de semana

Tu buen truco de copiar y pegar expresiones regulares sale volando por la ventana. Las posibilidades de pasar un fin de semana sin interrupciones para atracones de programas se acercan rápidamente null.

#PEG al rescate

No pierdas la esperanza todavía. Permítame presentarle Parse Expression Grammer (PEG) , una manera fácil de familiarizarse con los analizadores y ahorrar su valioso fin de semana.

PEG es una forma legible de escribir reglas de sintaxis y es bastante similar a las expresiones regulares, que es diferente de una contraparte de gramática libre de contexto como Backus-Naur Form (BNF) en la que las expresiones deben reducirse a símbolos más pequeños. Lo siento, Noam Chomsky , quizás otros días de trabajo.

Usaré una biblioteca de análisis de Rust PEG llamada Pest , que es bastante impresionante. Si aún no lo has hecho, esperaré mientras instalas Rust .

En serio, ¿quién no se oxida en estos días?

#Empezando

Comencemos con una gramática simple para analizar una declaración de declaración de variable similar a JavaScript. Comenzaremos pensando en un conjunto de reglas para entradas válidas.

#Una declaración de declaración:

  • comienza con una palabra clave var, seguida de uno o más identificadores.
  • es insensible al espacio en blanco
  • termina con un punto y coma ( ;)

#Un grupo de identificadores:

  • está precedido por una varpalabra clave
  • está delimitado por comas
  • es insensible al espacio en blanco

#Un identificador:

  • puede contener cualquier número de dígitos, caracteres y guiones bajos en mayúsculas y minúsculas
  • no puede comenzar con un dígito
  • no puede contener ningún espacio

Un identificador es un término , lo que significa que es una pieza irrompible del token. También lo son las varpalabras clave y los puntos y comas.

Regresa un poco al lado BNF, usando Extended Backus-Naur Grammar (EBNF) , podrías definir formalmente la gramática anterior de esta manera:

<alpha>  := 'a' | 'b' | 'c' | 'd' | 'e' | /* ... */ 'z'
         |  'A' | 'B' | 'C' | 'D' | 'E' | /* ... */ 'Z'

<digit>  := 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9

<Decl>   := 'var' <Idents> '\n'? ';'
<Idents> := <Ident> ('\n'? ',' <Ident>)*
<Ident>  := <alpha>+ (<alpha> | <digit> | '_')*

El nombre de la regla en mayúsculas representa un símbolo que no termina (es decir, se puede dividir en términos más pequeños). El nombre en minúscula representa un término.

En aras de la brevedad, omitimos los espacios en blanco implícitos de las reglas. Básicamente, pueden existir uno o más espacios en blanco entre cada símbolo que ve.

¡Vamos a profundizar en ello! Las reglas <alpha>y <digit>se explican por sí mismas, por lo que dejaremos que lo adivines.

<Decl>es la regla más compleja para una instrucción de declaración, que presenta una varpalabra clave, un <Idents>símbolo, una nueva línea opcional y termina con un punto y coma. Básicamente, esta regla dice: "Cualquier entrada de cadena que comience con var, seguida de uno o más espacios, luego una subregla <Idents>, seguida de uno o más espacios y finalmente termine con un solo punto y coma es válida y felizmente la masticaré. "

<Idents>puede ser un solo <Ident>símbolo, seguido de cero o más pares de comas y <Ident>.

Finalmente, un <Ident>debe comenzar con uno o más caracteres, seguido de cero o más caracteres, dígitos o guiones bajos.

#Ok, código por favor

¡Espera, joven Anakin! Cabeza caliente, eres. He aquí que, con la gramática definida, podremos analizar estas declaraciones:

var foo, bar, baz;

var   foo_1, baRamYu,baz99;

var foo_x
  , baroo
  , bazoo
  ;

No, no me olvidé de formatear mi código. ¡Es JS válido, y también es para nuestro analizador! Aquí hay algo que nuestras reglas no soportarán:

var 99Problems

¿Alguien quiere adivinar qué está mal aquí? ✋ Deja tu respuesta en el comentario. (psss, si tu respuesta es correcta, te sigo + 3 me gusta en tu publicación 👍)

#Entra el óxido y las plagas

Ok, espero que ya tengas Rust instalado (En tu terminal, intenta escribir which cargoy ver si aparece). Comience creando un nuevo proyecto binario de Rust con

$ cargo new --bin maybe-js; cd maybe-js

Dentro de la carpeta del proyecto, abra el Cargo.tomlarchivo y agregue lo siguiente en dependencies, y ejecútelo cargo updatepara instalarlo.

[dependencies]
pest = "2.0"
pest_derive = "2.0"

Una vez hecho esto, cdingrese srcy cree un archivo llamado grammar.pesty pegue lo siguiente en él:

alpha = { 'a'..'z' | 'A'..'Z' }
digit = { '0'..'9' }
underscore = { "_" }
newline = _{ "\n" | "\r" }
WHITESPACE = _{ " " }

declaration = { "var" ~ !newline ~ idents ~ newline? ~ ";" }
idents = { ident ~ (newline? ~ "," ~ ident)* }
ident = @{ !digit ~ (alpha | digit | underscore)+ }

Ahora bien, si he tenido su atención durante los últimos minutos, no debería ser difícil adivinar lo que está sucediendo aquí. (Oh, ¿no lo he hecho? De todos modos... aquí vamos)

Los cinco primeros son todos términos. Son conjuntos de valores válidos. el | se llama Choice Operator , que es como "o-si no".

first | or_else

Al hacer coincidir una expresión de elección, firstse intenta. Si first coincide con éxito, la expresión completa se realiza correctamente de inmediato. Sin embargo, si firstfalla, or_elsese intenta a continuación.

La newlineregla tiene un peculiar _antes del corchete, que en Pest habla significa "silencioso": simplemente no lo queremos como parte de nuestros tokens analizados, pero de todos modos es parte de una sintaxis válida.

La WHITESPACEregla tiene un lugar especial en Pest. Si lo definió, Pest insertará automáticamente espacios en blanco opcionales implícitos (de acuerdo con la WHITESPACEregla que defina) entre cada símbolo. Nuevamente, _dice que queremos silenciarlo, ya que no queremos toneladas de espacios en blanco como parte de nuestro árbol de sintaxis.

La declarationregla es muy similar a la contraparte de EBNF que aprendimos antes. Las tildes ("~") simplemente significan "y luego". La regla comienza con una palabra clave "var", seguida de cualquier cosa que no sea un salto de línea (el "!" hace lo que hubiera adivinado intuitivamente: negar una regla), seguida de una subregla idents, un salto de línea opcional y finaliza con un punto y coma.

La identsregla es nuevamente similar al ejemplo EBNF. Es un solo ident, seguido de cero o más idents separados por comas.

La identregla es un poco especial. La "@", conocida como Atomic , delante del corchete está ahí para decir: "No quiero que se apliquen espacios en blanco implícitos a esta regla". Seguro que no queremos incluir ningún espacio en nuestro nombre de variable. Además, marcar una regla como atómica de esta manera trata la regla como un término, silenciando las reglas internas de coincidencia. Cualquier regla interna se descarta.

string_lit = { "\"" ~ inner ~ "\"" }
inner = { ASCII_ALPHANUMERIC* }

Tenga en cuenta que ASCII_ALPHANUMERICes una regla incorporada conveniente en Pest para cualquier carácter y dígito ASCII.

Si analizamos una cadena "hola" con esta regla, esto generará primero un string_litnodo, que a su vez tiene un innernodo que contiene la cadena "hola", sin comillas.

Árbol de regla no atómica

Agregar un sigilo "@" delante del string_litcorchete:

string_lit = @{ "\"" ~ inner ~ "\"" }
inner = { ASCII_ALPHANUMERIC* }

string_litTerminaremos con un nodo plano que contiene ""hola"".

Árbol de la regla atómica

Un sigilo similar "$" conocido como Compound Atomic , protege los espacios en blanco implícitos dentro de la regla. La diferencia es que permite que las reglas de coincidencia internas se analicen normalmente.

La !digitparte evita que la regla avance si comienza con un número. Si no es así, una o más combinaciones de caracteres, números y guiones bajos están bien.

#Pero espera, ¿dónde está el código?

¡Dang, mi inteligente explorador! Pareces arrinconarme en cada movimiento. Sí, eso no era código en absoluto, sino una definición de gramática de Pest. Ahora tenemos que escribir un código de Rust para analizar un texto. Inicie src/main.rsy agregue lo siguiente:

/// You need to do this to use macro
extern crate pest;                                                                                                                                                                                   
#[macro_use]                                                                                                                                                                                         
extern crate pest_derive;                                                                                                                                                                            

/// 1. Import modules                                                                                                                                                                                            
use std::fs;                                                                                                                                                                                         
use pest::Parser;                                                                                                                                                                                    
use pest::iterators::Pair;                                                                                                                                                                           

/// 2. Define a "marker" struct and add a path to our grammar file.                                                                                                                                                                                                 
#[derive(Parser)]                                                                                                                                                                                    
#[grammar = "grammar.pest"]                                                                                                                                                                            
struct IdentParser; 

/// 3. Print the detail of a current Pair and optional divider
fn print_pair(pair: &Pair<Rule>, hard_divider: bool) {
    println!("Rule: {:?}", pair.as_rule());
    println!("Span: {:?}", pair.as_span());
    println!("Text: {:?}", pair.as_str());
    if hard_divider {
        println!("{:=>60}", "");
    } else {
        println!("{:->60}", "");
    }
}

fn main() {
    /// 4. Parse a sample string input
    let pair = IdentParser::parse(Rule::declaration, "var foo1, bar_99, fooBar;")
        .expect("unsuccessful parse")
        .next().unwrap();

    print_pair(&pair, true);
    
    /// 5. Iterate over the "inner" Pairs
    for inner_pair in pair.into_inner() {
 
        print_pair(&inner_pair, true);

        match inner_pair.as_rule() {
            /// 6. If we match an idents rule...
            Rule::idents =>  {
                /// 7. Iterate over another inner Pairs
                for inner_inner_pair in inner_pair.into_inner() {
                    match inner_inner_pair.as_rule() {
                        /// 8. The term ident is the last level
                        Rule::ident => {
                            print_pair(&inner_inner_pair, false);
                        }
                        _ => unreachable!(),
                    }
                }
            }
            _ => unreachable!(),
        }
    }
}

Está bien si no entiendes la mayoría de las cosas aquí. Ejecutémoslo cargo runen el directorio de su proyecto y miremos la salida impresa.

Rule: declaration
Span: Span { str: "var foo1, bar_99, fooBar;", start: 0, end: 28 }
Text: "var foo1, bar_99, fooBarBaz;"
============================================================
Rule: idents
Span: Span { str: "foo1, bar_99, fooBar", start: 4, end: 27 }
Text: "foo1, bar_99, fooBarBaz"
============================================================
Rule: ident
Span: Span { str: "foo1", start: 4, end: 8 }
Text: "foo1"
------------------------------------------------------------
Rule: ident
Span: Span { str: "bar_99", start: 10, end: 16 }
Text: "bar_99"
------------------------------------------------------------
Rule: ident
Span: Span { str: "fooBar", start: 18, end: 27 }
Text: "fooBarBaz"
------------------------------------------------------------

El concepto más importante aquí es un Pair. Representa un par de tokens coincidentes o, de manera equivalente, el texto distribuido que una regla con nombre coincidió correctamente.

A menudo usamos Pairs para:

Determinar qué regla produjo elPair

Usar el Paircomo materia prima&str

Inspeccionar las sub-reglas internas nombradas que produjeron elPair

let pair = Parser::parse(Rule::enclosed, "(..6472..) and more text")
    .unwrap().next().unwrap();

assert_eq!(pair.as_rule(), Rule::enclosed);
assert_eq!(pair.as_str(), "(..6472..)");

let inner_rules = pair.into_inner();
println!("{}", inner_rules); // --> [number(3, 7)]

A Pairpuede tener cero, una o más reglas internas. Para máxima flexibilidad, Pair::into_inner()devuelve Pairs, que es un tipo de iterador sobre cada par.

💡 Pair::into_inner()es un idioma muy común cuando se trabaja con Pest. Asegúrate de entender qué Paires a.

#Vamos a analizar Systemd

Si has llegado hasta aquí, te mereces este gatito.

Ahora es el momento de poner el trabajo. Aquí hay un ejemplo de un archivo de unidad Systemd:

[Unit]
Description=Nginx
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
Environment=PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/home/ec2-user/.local/bin
Environment=LD_LIBRARY_PATH=/usr/local/lib
Environment=PKG_CONFIG_PATH=/usr/local/lib/pkgconfig
ExecStart=/usr/local/sbin/nginx-runner.sh
Restart=on-failure
RestartSec=0
KillMode=process

[Install]
WantedBy=multi-user.target

El archivo está agrupado en secciones, cada una con un nombre entre corchetes. Cada sección contiene cero o más pares de nombre y valor de propiedad, separados por un signo igual "=".

Tratemos de desarrollar un conjunto de reglas. Cree un nuevo proyecto de óxido con cargo new --bin systemd-parser, luego cree un archivo con el nombre src/grammar.pestcon las siguientes reglas:


/// Implicit white spaces are ok.
WHITESPACE = _{ " " }

/// Set of characters permited 
char = { ASCII_ALPHANUMERIC | "." | "_" | "/" | "-"  }

/// name is one or more chars. Note that white spaces are allowed.
name = { char+ }

// value can be zero or more char, plus = and : for path variables.
value = { (char | "=" | ":" )* }

/// section is a name, enclosed by square brackets.
section = { "[" ~ name ~ "]" }

/// property pair is a name and value, separated by an equal sign.
property = { name ~ "=" ~ value }

/// A Systemd unit file structure
file = {
    SOI ~
    ((section | property)? ~ NEWLINE)* ~
    EOI
}

En el main.rsarchivo, comience con lo siguiente

extern crate pest;
#[macro_use]
extern crate pest_derive;

use std::fs;
use std::env::current_dir;
use std::collections::HashMap;
use pest::Parser;

#[derive(Parser)]
#[grammar = "grammar.pest"]
struct SystemdParser;

/// Implement a simple AST representation
#[derive(Debug, Clone)]
pub enum SystemdValue {
    List(Vec<String>),
    Str(String),
}

// ...

Como primer paso, después de las importaciones y la configuración iniciales, definimos una SystemdValueenumeración como una representación simple del tipo de datos en un archivo Systemd. SystemdValue::Str(String)capturará un solo valor de propiedad y SystemdValue::List(Vec<String>)capturará varios valores de propiedad con un nombre de clave de propiedad duplicado. Por ejemplo, en el nginx.servicearchivo anterior hay varias Environmentpropiedades.

Aquí está la mainfunción:


fn main() {
    // Read and parse the unit file.
    let unparsed_file = fs::read_to_string("nginx.service")
        .expect("cannot read file");
    let file = SystemdParser::parse(Rule::file, &unparsed_file).expect("fail to parse")
        .next()
        .unwrap();

    // Create a fresh HashMap to store the data.
    let mut properties: HashMap<String, HashMap<String, SystemdValue>> = HashMap::new();

    // These two mutable variables will be used to store
    // section name and property key name.
    let mut current_section_name = String::new();
    let mut current_key_name = String::new();

    // Iterate over the file line-by-line.
    for line in file.into_inner() {
		match line.as_rule() {
			Rule::section => {
                // Update the current_section_name
                let mut inner_rules = line.into_inner();
                current_section_name = inner_rules.next().unwrap().as_str().to_string();
			}
			Rule::property => {
                let mut inner_rules = line.into_inner();
                // Get a sub map of properties with the current_section_name key, or create new.
                let section = properties.entry(current_section_name.clone()).or_default();

                // Get the current property name and value.
                let name = inner_rules.next().unwrap().as_str().to_string();
                let value = inner_rules.next().unwrap().as_str().to_string();

                // If the property name already exists...
                if name == current_key_name {
                    // Get the section of the map with the key name, or insert a new SytemdValue::List.
                    let entry = section.entry(current_key_name.clone()).or_insert(SystemdValue::List(vec![]));
                    // Push the value onto the inner vector of SystemdValue::List.
                    if let SystemdValue::List(ent) = entry {
                        ent.push(value);
                    }
                } else {
                    // Create a new SystemdValue::List and save it under name key.
                    let entry = section.entry(name.clone()).or_insert(SystemdValue::List(vec![]));
                    // Push the current value onto the vector, then set the
                    // current_key_name to the current name.
                    if let SystemdValue::List(ent) = entry {
                        ent.push(value);
                    }
                    current_key_name = name;
                }
			}
			Rule::EOI => (),
			_ => unreachable!(),
		}
    }
}

Todo esto está bien, pero no usamos SystemdValue::Strninguna parte del código. Para mantener limpio el código, decidimos tratar cada propiedad como HashMap<String, SystemdValue::List(Vec<String>), donde la clave del mapa es la clave de propiedad y el vector String almacena la lista de valores de propiedad. Si no hay valor, el vector está vacío. Si hay un valor, este vector contiene ese único valor, y así sucesivamente.

Para que la API sea un poco más fácil de usar, escribiremos una pequeña función auxiliar para procesar todos los correos electrónicos de un solo valor Systemd::List(Vec<String>)y convertirlos en archivos Systemd::Str(String).

// Iterate over the nested maps, and convert empty and 
// single-element `SystemdValue::List<Vec<String>>` to 
// `SystemdValue::Str(String)`.
fn pre_process_map(map: &mut HashMap<String, HashMap<String, SystemdValue>>) {
    for (_, value) in map.into_iter() {
		for (_, v) in value.into_iter() {
			if let SystemdValue::List(vs) = v {
				if vs.len() == 0 {
					let v_ = SystemdValue::Str(String::new());
					*v = v_.clone();
				} else if vs.len() == 1 {
					let v_ = SystemdValue::Str((vs[0]).clone());
					*v = v_.clone();
				}
			}
		}
    }
}

¡Ahora estamos listos para imprimirlo para que el mundo lo vea!

fn main() {

    // Our main code 

    pre_process_map(properties);

    println!("{:#?}", properties);
}

¡Auge! ¡Felicidades! Acaba de escribir un analizador de archivos Systemd, además de uno mini JS. 🤯 Ahora tendrás algo de tiempo libre para divertirte el viernes por la noche. Con otra tarde, es posible que incluso descubras cómo serializar el archivo de tu unidad Systemd en JSON para impresionar a tu jefe el lunes.

Puede consultar el código del analizador implementado como biblioteca en [este repositorio] (https://github.com/jochasinga/systemd-parser)

Fuente: https://hackernoon.com/how-to-build-a-parser-in-rust-for-fun-and-profit

#rust 

Ajay Kapoor

1619510116

What are Pros and Cons of Internet of Things? - Xebi

IoT or the Internet of Things is a trending topic today and can be heard on the lips of every techie. It is a common thing that many individuals are using it and their entire day-to-day life is dependent on it. Pros and Cons of the Internet of Things

Zillions of devices are interconnected in the IoT ecosystem, and surprisingly we as human beings never realized that these devices virtually surround us in inter-human or machine-to-machine interaction.

But, yes they never realize that this is what we call an IoT.

The ubiquity of wireless networks has possibly turned on everything. Be it a child’s toy or a driverless truck; all this is an example of IoT that has merged the digital and physical universe.

Statista reports that the installed base of active IoT connected devices is forecast to reach 21.5 billion units by the year 2025. Apart from all the path-breaking discoveries, IoT with its own set of pros and cons.

Here, we will see how IoT is luring the end-users with its captivating benefits and features, and at the same time, it is emerging as a dark side too.

Read the full blog here: Pros and cons of IoT

IoT app development company in India

#iot #internet-of-things #iot-benefits #iot-pros #iot-cons #iot-pros-and-cons

Mike doctor

Mike doctor

1624347900

The Pros and Cons of Entrepreneurship in 2021. DO NOT MISS!!!

In this video, I’m going over why you SHOULD and why you SHOULD NOT become an entrepreneur.
I know a lot of you guys are aspiring entrepreneurs who want to create your own business and work for yourself. And I’m sure a lot of you watching are also seasoned entrepreneurs who can relate to this video :)

I’ll be going over 6 pros and cons that entrepreneurs face, as well as my tips on how to navigate entrepreneurship the best way possible. If you’ve wanted to know how to become an entrepreneur, this video will also be extremely valuable.

After graduating college, I started doing a lot of side hustles. From there, I gradually began starting businesses, failing at most of them, and then finding my passions. Entrepreneurship is a long journey, and it’s a lifestyle. And my goal in this video is to convince you how awesome it is to be your own boss and set your own schedule!
📺 The video in this post was made by Charlie Chang
The origin of the article: https://www.youtube.com/watch?v=Iqpd7z-CwAw
🔺 DISCLAIMER: The article is for information sharing. The content of this video is solely the opinions of the speaker who is not a licensed financial advisor or registered investment advisor. Not investment advice or legal advice.
Cryptocurrency trading is VERY risky. Make sure you understand these risks and that you are responsible for what you do with your money
🔥 If you’re a beginner. I believe the article below will be useful to you ☞ What You Should Know Before Investing in Cryptocurrency - For Beginner
⭐ ⭐ ⭐The project is of interest to the community. Join to Get free ‘GEEK coin’ (GEEKCASH coin)!
☞ **-----CLICK HERE-----**⭐ ⭐ ⭐
Thanks for visiting and watching! Please don’t forget to leave a like, comment and share!

#bitcoin #blockchain #the pros and cons of entrepreneurship in 2021 #the pros and cons #entrepreneurship

Cómo Construir Una Pantalla De Esqueleto Con CSS Para Una Mejor UX

Cargadores de contenido, pantallas esqueléticas, elementos fantasma y marcadores de posición de contenido. Estos son los nombres dados al efecto que exploraremos hoy.

Muchas empresas, como Linkedin, Facebook, Youtube y Slack, utilizan este efecto en sus aplicaciones y sitios web, como habrás notado.

Por mucho que los desarrolladores queramos que nuestros sitios web se carguen lo más rápido posible, hay momentos en los que es necesario representar una gran cantidad de datos en la página, por lo que las pantallas Skeleton son una excelente opción.

requisitos previos

Este artículo asume que usted tiene:

  • Conocimientos de HTML y CSS (SASS)
  • Conocimiento de JavaScript (ES6)

Usaremos HTML y SASS para este proyecto. Si desea comenzar con SASS, consulte esta Guía para principiantes.

¿Qué es una pantalla de esqueleto?

Una pantalla esqueleto es un marcador de posición animado que simula el diseño de un sitio web mientras se cargan los datos.

Le informan al usuario que se está cargando algún contenido y, lo que es más importante, brindan una indicación de lo que se está cargando, ya sea una imagen, texto, tarjeta, etc.

Esto le da al usuario la impresión de que el sitio web es más rápido porque ya sabe qué tipo de contenido se está cargando antes de que aparezca. Esto se conoce como rendimiento percibido .

Estos son algunos ejemplos de pantallas esqueléticas de Facebook y LinkedIn:

1-2

Estado de carga del feed de inicio de LinkedIn

2-2

Estado de carga del feed de inicio de Facebook

Diferentes tipos de pantallas de esqueleto

Hay 2 tipos principales de pantallas de esqueleto:

  • Marcadores de posición de contenido
  • Marcadores de posición de color

Los marcadores de posición de contenido suelen ser cuadros y círculos de color gris claro que simulan la apariencia de la página, como se muestra en las imágenes de arriba para Facebook y LinkedIn.

Los marcadores de posición de color son más difíciles de crear porque simulan no solo el diseño de la interfaz de usuario, sino también el color dominante. Se encuentra más comúnmente en sitios web enfocados en imágenes como Pinterest y Unsplash.

9

Ejemplo de marcador de posición de color de Pinterest

¿Por qué usar pantallas de esqueleto?

  • Parecen ser más rápidos y más fáciles de usar. El rendimiento percibido mejorado proporciona una buena experiencia de usuario y ayuda a aumentar la tasa de conversión.
  • El problema con los giradores/cargadores es que no tenemos idea de qué se está cargando o cuánto tiempo llevará.
  • El uso de spinners/cargadores crea un período de incertidumbre para el usuario ya que se desconoce el tiempo de carga.
  • Las pantallas esqueléticas llaman la atención del usuario sobre el progreso en lugar del tiempo de espera.
  • Crea una ilusión de velocidad y tiempo de carga corto.

Cuándo usarlos

  • Úselo para notificar al usuario que algo se está cargando cuando más de un elemento se está cargando al mismo tiempo.
  • Utilícelo cuando la carga de datos tarde más de 3 segundos.
  • Uso en sitios web con mucho tráfico.
  • Úselo para un proceso en segundo plano o de larga ejecución.

Cosas a tener en cuenta

Al implementar pantallas de esqueleto, debemos tener en cuenta el objetivo que intentamos lograr con el sitio web o la aplicación, y priorizar la carga del contenido.

El uso de pantallas de carga esqueléticas no es excusa para omitir la optimización del rendimiento real, y si puede almacenar en caché contenido significativo y mostrarlo, será bueno.

Creación de una interfaz de usuario de carga de esqueleto de desarrollo diario

En esta sección, profundizaremos en la implementación de la pantalla de carga básica siguiendo un proceso paso a paso para que sea más fácil de entender.

Construiremos uno como la sección de noticias de daily.dev.

Paso 1: configurar el proyecto

Primero, para codificar conmigo, clone o descargue el código de inicio para el diseño aquí . Puede descargar los archivos utilizando DownGit .

El código contiene el diseño de la tarjeta, por lo que continuaremos desde aquí en los próximos pasos.

Para comenzar, inicie el servidor de desarrollo en el IDE y abra su navegador.

captura de pantalla-codepen-io-israelmitolu-full-wvpOaQd-2022-04-21-17_16_47

Diseño de la tarjeta de inicio

Paso 2: Diseña los elementos del Esqueleto

Hay 5 elementos que queremos construir para la carga del esqueleto: la imagen del logotipo, el título, los detalles, la imagen de portada y la sección de pie de página.

4-3

Elementos esqueléticos de Daily Dev

Ahora, agregaremos skeletonclases a las ubicaciones de los elementos anteriores.

Para el logotipo,

<img class="card__header header__img skeleton" />

Para el título, habrá 2 divs para representar las dos líneas que tenemos en la imagen de arriba.

<div class="skeleton skeleton-text"></div>
<div class="skeleton skeleton-text"></div>

Para obtener más información, agregue el siguiente código dentro del div de la clase body__text:

<div class="skeleton skeleton-text skeleton-text__body"></div>

Dentro del body__imgdiv, agregue el siguiente código:

<img class="skeleton" alt="" id="cover-img" />

Para el pie de página, agregue este código:

<div class="skeleton skeleton-text skeleton-footer"></div>

Ahora, el código HTML completo de la tarjeta:

<a class="card" id="card-link" target="_blank">
  <div class="card__header">
    <div>
      <img class="card__header header__img skeleton" id="logo-img" alt="" />
    </div>
    <h3 class="card__header header__title" id="card-title">
      <div class="skeleton skeleton-text"></div>
      <div class="skeleton skeleton-text"></div>
    </h3>
  </div>

  <div class="card__body">
    <div class="card__body body__text" id="card-details">
      <div class="skeleton skeleton-text skeleton-text__body"></div>
    </div>

    <div class="card__body body__img">
      <img class="skeleton" alt="" id="cover-img" />
    </div>
  </div>

  <div class="card__footer" id="card-footer">
    <div class="skeleton skeleton-text skeleton-footer"></div>
  </div>
</a>

Ahora, agreguemos algo de estilo para hacer los componentes del esqueleto:

.skeleton {
  animation: skeleton-loading 1s linear infinite alternate;
}

@keyframes skeleton-loading {
  0% {
    background-color: hsl(200, 20%, 80%);
  }
  100% {
    background-color: hsl(200, 20%, 95%);
  }
}

.skeleton-text {
  width: 100%;
  height: 0.7rem;
  margin-bottom: 0.5rem;
  border-radius: 0.25rem;
}

.skeleton-text__body {
  width: 75%;
}

.skeleton-footer {
  width: 30%;
}

Este es el diseño resultante:

5

Carga de componentes de la tarjeta

Paso 3: Clona la plantilla de la tarjeta

Inserte una templateetiqueta entre containery el cardelemento en el index.htmlarchivo.

En la imagen de arriba hay una templateetiqueta que comenté, y sí, es un elemento HTML válido ;). Se utiliza para declarar fragmentos de HTML que se pueden clonar e insertar en el documento mediante script.

<template id="card-template">

Como resultado, asegúrese de agregar la etiqueta de cierre </template>después de la etiqueta de cierre del carddiv.

Ahora veamos el código JavasScript que usaremos para clonar la plantilla de la tarjeta.

Cree una scriptetiqueta justo antes del final de la bodyetiqueta y agregue el siguiente código:

const container = document.querySelector(".container");
const cardTemplate = document.getElementById("card-template");
for (let i = 0; i < 10; i++) {
  container.append(cardTemplate.content.cloneNode(true));
}

El código anterior toma el contenedor de la página y la plantilla de la tarjeta, y luego crea 9 clones/copias de la tarjeta (haciendo 10 en total). Luego agrega/inserta las tarjetas en el contenedor.

6

Interfaz de usuario de esqueleto de tarjeta clonada

Paso 4: Crea un archivo JSON

Necesitamos algunos datos antes de que podamos agregar contenido a la página. Normalmente, necesitaría obtener datos con un sitio web externo, pero usaremos uno que configuré específicamente para este proyecto.

Para comenzar, cree un archivo llamado data.jsonen la carpeta del proyecto.

Agregue el siguiente código al archivo JSON.

[
  {
    "id": 1,
    "logoImage": "https://res.cloudinary.com/daily-now/image/upload/t_logo,f_auto/v1/logos/4a287b2e7cb5499bae863f8e7137cdb4",
    "title": "Writing Cleaner CSS Using BEM ",
    "details": "Mar 12, 2022 · 4m read time",
    "coverImage": "https://res.cloudinary.com/daily-now/image/upload/f_auto,q_auto/v1/posts/dd19e7a56475f39ab1c38167c02c7b58",
    "link": "https://israelmitolu.hashnode.dev/writing-cleaner-css-using-bem-methodology"
  },
  {
    "id": 2,
    "logoImage": "https://daily-now-res.cloudinary.com/image/upload/t_logo,f_auto/v1628412854/logos/freecodecamp",
    "title": "The Beginner's Guide to Sass",
    "details": "Apr 05, 2022 · 8m read time",
    "coverImage": "https://res.cloudinary.com/daily-now/image/upload/f_auto,q_auto/v1/posts/bec6719be210973098293a32dc732d1e",
    "link": "https://www.freecodecamp.org/news/the-beginners-guide-to-sass/"
  },
  {
    "id": 3,
    "logoImage": "https://res.cloudinary.com/daily-now/image/upload/t_logo,f_auto/v1/logos/devto",
    "title": "I made Squid Game with Javascript",
    "details": "Oct 25, 2021 · 3m read time",
    "coverImage": "https://res.cloudinary.com/daily-now/image/upload/f_auto,q_auto/v1/posts/1f947033365381cbe322ddf294ad7169",
    "link": "https://dev.to/0shuvo0/i-made-squid-game-with-javascript-10j9"
  },
  {
    "id": 4,
    "logoImage": "https://res.cloudinary.com/daily-now/image/upload/t_logo,f_auto/v1/logos/4a287b2e7cb5499bae863f8e7137cdb4",
    "title": "Using Custom Cursors with Javascript for a Better User Experience",
    "details": "Feb 12, 2022 · 9m read time",
    "coverImage": "https://res.cloudinary.com/daily-now/image/upload/f_auto,q_auto/v1/posts/3d056b99c95b37cd35ae5cfc6a8b38be",
    "link": "https://israelmitolu.hashnode.dev/using-custom-cursors-with-javascript-for-a-better-user-experience"
  },
  {
    "id": 5,
    "logoImage": "https://daily-now-res.cloudinary.com/image/upload/t_logo,f_auto/v1628412854/logos/freecodecamp",
    "title": "React Best Practices - Tips for Writing Better React Code in 2022",
    "details": "Feb 03, 2022 · 31m read time",
    "coverImage": "https://res.cloudinary.com/daily-now/image/upload/f_auto,q_auto/v1/posts/5a629fff5583f9ab5f0931d14736b299",
    "link": "https://www.freecodecamp.org/news/best-practices-for-react/"
  },
  {
    "id": 6,
    "logoImage": "https://res.cloudinary.com/daily-now/image/upload/t_logo,f_auto/v1/logos/tnw",
    "title": "You suck at Googling: 5 tips to improve your search skills",
    "details": "Mar 31, 2022 · 4m read time",
    "coverImage": "https://res.cloudinary.com/daily-now/image/upload/f_auto,q_auto/v1/posts/e318150ae67c2083ff3585a96f366f7b",
    "link": "https://thenextweb.com/news/5-tips-to-improve-your-google-search-skills"
  },
  {
    "id": 7,
    "logoImage": "https://res.cloudinary.com/daily-now/image/upload/t_logo,f_auto/v1/logos/logrocket",
    "title": "A better way of solving prop drilling in React apps",
    "details": "Jan 14, 2022 · 13m read time",
    "coverImage": "https://res.cloudinary.com/daily-now/image/upload/f_auto,q_auto/v1/posts/6fe4c4060bca638b419d8b2c63d8eaf7",
    "link": "https://blog.logrocket.com/solving-prop-drilling-react-apps/"
  },
  {
    "id": 8,
    "logoImage": "https://res.cloudinary.com/daily-now/image/upload/t_logo,f_auto/v1/logos/dz",
    "title": "Golang and Event-Driven Architecture",
    "details": "Apr 18, 2022 · 6m read time",
    "coverImage": "https://res.cloudinary.com/daily-now/image/upload/f_auto,q_auto/v1/posts/d06eddd82c62288df6e2600bcda61579",
    "link": "https://dzone.com/articles/golang-and-event-driven-architecture"
  },
  {
    "id": 9,
    "logoImage": "https://res.cloudinary.com/daily-now/image/upload/t_logo,f_auto/v1/logos/4a287b2e7cb5499bae863f8e7137cdb4",
    "title": "Introduction to Git In 16 Minutes",
    "details": "Mar 18, 2021 · 8m read time",
    "coverImage": "https://res.cloudinary.com/daily-now/image/upload/f_auto,q_auto/v1/posts/3c02111a8f242f607551500432e17a78",
    "link": "https://vickyikechukwu.hashnode.dev/introduction-to-git-in-16-minutes"
  },
  {
    "id": 10,
    "logoImage": "https://res.cloudinary.com/daily-now/image/upload/t_logo,f_auto/v1/logos/4a287b2e7cb5499bae863f8e7137cdb4",
    "title": "How to Create a Sleek Preloader Animation Using GSAP Timeline",
    "details": "Jan 25, 2022 · 7m read time",
    "coverImage": "https://res.cloudinary.com/daily-now/image/upload/f_auto,q_auto/v1/posts/e238c35cb9d41dd9a5475602aef00119",
    "link": "https://israelmitolu.hashnode.dev/how-to-create-a-sleek-preloader-animation-using-gsap-timeline"
  }
]

Para replicar la sección de noticias de Daily Dev, hemos creado algunos datos que tienen una matriz de objetos con propiedades como identificación, imagen de logotipo, título, detalles e imagen de portada.

Paso 5: rellene los elementos HTML con el contenido adecuado

Agrega el siguiente código a la etiqueta del script que aloja tu JavaScript:

fetch("data.json")
  .then((response) => response.json())
  .then((posts) => {
    container.innerHTML = "";
    posts.forEach((post) => {
      const div = cardTemplate.content.cloneNode(true);
      div.getElementById("card-link").href = post.link;
      div.getElementById("logo-img").src = post.logoImage;
      div.getElementById("card-title").textContent = post.title;
      div.getElementById("card-details").textContent = post.details;
      div.getElementById("cover-img").src = post.coverImage;
      div.getElementById(
        "card-footer"
      ).innerHTML = ` <ion-icon name="arrow-up"></ion-icon>
          <ion-icon name="chatbox-ellipses"></ion-icon>
          <ion-icon name="bookmark"></ion-icon>`;
      container.append(div);
    });
  });

El código anterior es lo que usaremos para agregar contenido a las tarjetas una vez que terminen de cargarse.

Ahora, déjame explicarte el código poco a poco:

fetch("data.json")
  .then((response) => response.json())

Aquí, tenemos una solicitud de recuperación básica, donde establecemos la ruta al recurso. En este caso, el data.jsonarchivo. Si fuera una API externa, usaría la URL del punto final como argumento:

El fetch()método no devuelve directamente el cuerpo de la respuesta JSON, sino una promesa que se resuelve con un objeto de respuesta.

Para obtener más información, consulta los documentos de MDN .

.then((posts) => {
    container.innerHTML = "";
    posts.forEach((post) => {
      const div = cardTemplate.content.cloneNode(true);
      div.getElementById("logo-img").src = post.logoImage;
      div.getElementById("card-title").textContent = post.title;
      div.getElementById("card-details").textContent = post.details;
      div.getElementById("cover-img").src = post.coverImage;
      div.getElementById(
        "card-footer"
      ).innerHTML = `<ion-icon name="arrow-up"></ion-icon>
          <ion-icon name="chatbox-ellipses"></ion-icon>
          <ion-icon name="bookmark"></ion-icon>`;
      container.append(div);
    });
  });

Aquí, definimos lo que debería suceder después de obtener los datos.

El código primero borra la página y luego ejecuta un forEach()método que extrae las propiedades del archivo JSON y luego lo ingresa en los elementos de la tarjeta (imagen del logotipo, título de la tarjeta,...) usando .textContentla propiedad.

Finalmente, para el pie de página, solíamos .innerHTMLinsertar los íconos como contenido HTML.

Si agregó todo correctamente, no debería haber ningún error, y esta es nuestra interfaz de usuario de carga de esqueleto completamente funcional.

7-1

Nuestra interfaz de usuario de esqueleto de Daily Dev terminada

Consulte la demostración en vivo y el repositorio de código fuente en Github.

Limitación de red en Chrome DevTools

Es importante tener en cuenta que no establecimos un tiempo de espera porque esta pantalla básica depende de la velocidad de la red del usuario.

Si desea simularlo a diferentes velocidades de red, vaya a la pestaña de red en Devtools de su navegador.

He aquí cómo hacerlo en Chrome v100:

8

Acelerador de red en Chrome DevTools

  1. Abra DevTools (Ctrl+Mayús+i).
  2. Vaya a la pestaña "Red".
  3. Seleccione el tipo de conexión que desea
  4. Vuelva a cargar la página para ver los activos que se descargan a la velocidad de conexión especificada.

Si las opciones predeterminadas no le convienen, puede crear un perfil de limitación de red personalizado seleccionando la opción en la parte superior del menú desplegable.

Conclusión

¡Llegaste hasta el final! Aprendió sobre la carga de esqueleto y cómo contribuye a la experiencia del usuario al crear la ilusión de velocidad al cargar datos, y ha implementado la suya propia.

Espero que hayas encontrado útil este tutorial y que sirva como un buen punto de partida para crear varias pantallas de carga de esqueleto.

Si encontró este artículo revelador, compártalo con sus amigos y su red. Además, no dude en conectarse conmigo en Twitter y mi blog donde comparto recursos y artículos para que sea un mejor desarrollador.

¡Gracias por leer y feliz codificación!

Antes de ir, aquí hay algunos paquetes de carga de esqueleto para React , Angular y Vue .

Fuente: https://www.freecodecamp.org/news/how-to-build-skeleton-screens-using-css-for-better-user-experience/ 

#css #react #angular #vue #skeleton