How to Upload Multiple Files React Native

Khi lập trình ứng dụng mobile, có khá nhiều thứ liên quan đến hình ảnh. Hướng dẫn sau đây sẽ giúp bạn có thể upload nhiều hình ảnh trong app React Native, tương tự Facebook hay instagram…

Chuẩn bị

Trong hướng dẫn này sử dụng api code dot.net core. Bạn có thể sử dụng ngôn ngữ khác như nodejs, php, java… Bạn có thể tham khảo thêm tại đây.

Trong React Native sử dụng 3 thư viện

npm install react-native-image-crop-picker'
npm install react-native-actionsheet
npm install axios

Các bạn tham khảo thêm ở github của thư viện để biết cách cấu hình chi tiết.

Code backend API

[HttpPost]
[Route("")]
public async Task<IActionResult> Post([FromForm]List<IFormFile> files)
{
    try
    {
        var today = DateTime.Today;
        var uploadPath = @"C:\web\files\files"; // Path.Combine(_hostingEnvironment.WebRootPath, "Content", "Files");
        uploadPath += $"\\{today.Year}\\{today.Month}".PadLeft(2, '0');
        if (!Directory.Exists(uploadPath))
        {
            Directory.CreateDirectory(uploadPath);
        }
        
        var fileUrls = new List<string>();
        foreach (var file in files)
        {
            if (file.Length > 0)
            {
                var fileExtension = Path.GetExtension(file.FileName);
                string fileName = $"{FileHelper.GenerateUniqueFileName}{fileExtension}";
                await file.CopyToAsync(stream);
                var fileUrl = $"files/{today.Year}/{today.Month}".PadLeft(2, '0') + "/" + fileName;
                fileUrls.Add(fileUrl);
            }
        }

        var fileItemResponse = new ResultDataObject
        {
            Data = fileUrls,
            Code = (int)ErrorCodeResultEnum.Ok,
            Message = "Ok"
        };
        return Ok(fileItemResponse);
    }
    catch (Exception ex)
    {
        var fileItemResponse = new ResultDataObject
        {
            Message = ex.Message,
            Code = (int)ErrorCodeResultEnum.Failure
        };
        return Ok(fileItemResponse);
    }
}

Code React Native

Chọn ảnh từ thư viện sử dụng ImagePicker, sử dụng state để lưu lại ảnh đã chọn

onActionSelectPhotoDone = index => {
    switch (index) {
      case 0:
        ImagePicker.openCamera({}).then(image => {
          this.setState({
            localPhotos: [...this.state.localPhotos, image]
          });
        });
        break;
      case 1:
        ImagePicker.openPicker({
          multiple: true,
          maxFiles: 10,
          mediaType: 'photo'
        }).then(images => {
          images.forEach((image) => {
           this.setState({
            localPhotos: [...this.state.localPhotos, image]
          });
          });
        }).catch(error => {
          alert(JSON.stringify(error));
        });
        break;
      default:
        break;
    }
  };

Code hiển thị hình ảnh sau khi chọn

renderListPhotos = localPhotos => {
    const photos = localPhotos.map((photo, index) => (
      <TouchableOpacity key={index}
        onPress={() => {
           this.showActionSheet(index);
        }}
      >
        <Image style={styles.photo} source={{ uri: photo.path }} />
      </TouchableOpacity>
    ));

    return photos;
  };

  renderSelectPhotoControl = localPhotos => {
    return (
      <View style={styles.sectionContainer}>
        <Text style={styles.sectionTitle}>Select photos</Text>
        <ScrollView style={styles.photoList} horizontal={true}>
          {this.renderListPhotos(localPhotos)}
          <TouchableOpacity onPress={this.onPressAddPhotoBtn.bind(this)}>
            <View style={[styles.addButton, styles.photo]}>
              <Text style={styles.addButtonText}>+</Text>
            </View>
          </TouchableOpacity>
        </ScrollView>
      </View>
    );
  };

Sử dụng axios & FormData để Upload

  onDoUploadPress() {
    const { localPhotos } = this.state;
    if (localPhotos && localPhotos.length > 0) {
      let formData = new FormData();
      localPhotos.forEach((image) => {
        const file = {
          uri: image.path,
          name: image.filename || Math.floor(Math.random() * Math.floor(999999999)) + '.jpg',
          type: image.mime || 'image/jpeg'
        };
        formData.append('files', file);
      });

      axios
        .post('https://api.tradingproedu.com/api/v1/fileupload', formData)
        .then(response => {
          this.setState({ logs: JSON.stringify(response.data) });
        })
        .catch(error => {
          alert(JSON.stringify(error));
        });
    } else {
      alert('No photo selected');
    }
  }

Chúc các bạn thành công.

Full source code https://github.com/tuanitpro/react-native-upload-files

SonarQube: Code Quality and Security

Trong quá trình lập trình & phát triển phần mềm chúng ta thường hay gặp vấn đề về quản lý chất lượng code, code smell, dirty code hay technical debt, thậm chí tồn tại lỗ hổng bảo mật. Nhất là khi dự án có sự tham gia của nhiều member, với trình độ kinh nghiệm khác nhau. Hoặc khi dự án chưa có rules, coding conventions, coding styles rõ ràng. Đến một ngày nào đó cần maintainance dự án hay develop thêm feature mới, chúng ta mới giật mình nhìn lại đống code cũ, tại sao nó lại tệ hại như vậy.

SonarQube là một open source platform, được phát triển bởi SonarSource dành cho việc kiểm tra liên tục chất lượng code (code quality), review code một cách tự động để phát hiện ra các bugs, code smell, lỗ hổng bảo mật cho 25+ ngôn ngữ lập trình khác nhau. SonarQube hỗ trợ báo cáo duplicated code, coding standards, unit tests, code coverage, code complexity, comments, bugs, and security vulnerabilities.

Cài đặt SonarQube trên Windows

Hướng dẫn cài đặt và bắt đầu với SonarQube. Bạn có thể sử dụng Docker hoặc download file về chạy bình thường. Yêu cầu máy có Java JDK 11 trở lên. Cấu hình máy tối thiểu 2GB RAM. https://docs.sonarqube.org/latest/requirements/requirements/

Đầu tiên vào https://www.sonarqube.org/downloads/ chọn bản Community (miễn phí). Giải nén và tìm thư mục bin để chạy. Đối với Windows có thể cài thành service để tiện sử dụng.

Nếu gặp lỗi liên quan JAVA, các bạn chú ý cài lại Java JDK. Sau đó tìm conf/wrapper.conf sửa lại dòng sau:

wrapper.java.command=C:\Program Files\Java\jdk-12.0.2\bin\java

Truy cập: http://localhost:9000 username/password: admin/admin để kiểm tra. Nếu thành công thì chúng ta xong bước cài đặt. Tiếp theo tích hợp dự án vào SonarQube để phân tích.

Tích hợp dự án của bạn vào SonarQube

Sau khi đăng nhập thành công, click vào http://localhost:9000/projects/create để tạo dự án mới. Nhập key & tên dự án, sau đó chuyển sang màn hình nhập key, chọn loại dự án của bạn, và download file scanner của nó về, giải nén và thêm vào biến môi trường %PATH%. Ví dụ mình làm về Windows, dot net core và reactjs thì cần

sonar-scanner-4.0.0.1744-windows
sonar-scanner-msbuild-4.6.2.2108-net46
sonar-scanner-msbuild-4.6.2.2108-netcoreapp2.0

Sau đó mở project của bạn và chạy câu lệnh theo hướng dẫn để sonarqube phân tích.

SonarScanner.MSBuild.exe begin /k:"KEY_CUA_BAN" /d:sonar.host.url="http://localhost:9000" /d:sonar.login="API_KEY_CUA_BAN"

MsBuild.exe /t:Rebuild

SonarScanner.MSBuild.exe end /d:sonar.login="API_KEY_CUA_BAN"

Kết quả sau khi áp dụng

Chúc các bạn thành công.

Dãy số Fibonacci trong C#

Quy luật của dãy số Fibonacci: số tiếp theo bằng tổng của 2 số trước, 2 số đầu tiên của dãy số là 0, 1. Ví dụ: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, …

Sử dụng yield trong C# để trả về dãy số Fibonacci

static void Main()
{
 foreach(var value in Fibonacci())
 {
 Console.Write(value + " ");
 if(value > 1000) 
 {
 break;
 }
 }
}

static IEnumerable<int>  Fibonacci()
{
 int current = 0;
 int next = 1;
 while(true)
 {
 yield return current;
 int oldCurrent = current;
 current = next;
 next = next + oldCurrent;
 } 
}

Kết quả:

0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597

Add thêm website trên VPS nginx CentOS

Thông thường mỗi VPS mình chỉ chạy cho một website mà thôi, tuy nhiên trong trường hợp bạn có nhiều website và muốn add thêm chạy trên VPS thì sao, hãy tham khảo bài hướng dẫn này để thực hiện.

Giới thiệu Virtual Hosts

Virtual Hosts được sử dụng để giúp cho một VPS có thể chạy được nhiều website khác nhau.

Theo như nginx website, Virtual Hosts được gọi là Server Blocks trên nginx, tuy nhiên cho dễ dàng giống như Apache nên mình sẽ gọi là Virtual Hosts trong bài này. Các bước add thêm website trên VPS nginx chạy CentOS bằng Virtual Hosts như sau:

Chuẩn bị server

Đã cài đặt sẵn webserver Nginx trên CentOS

Tạo thư mục chứa website

Ví dụ mình sẽ tạo thư mục ở folder /home/ nhé. Thay tuanitpro.com bằng domain của bạn.

mkdir -p /home/www/tuanitpro.com/public_html

Gán quyền

Đảm bảo cho website hoạt động bình thường

chown -R nginx:nginx /home/www/tuanitpro.com/public_html

Cài đặt Virtual Hosts

Thêm file cấu hình .conf cho domain mới

nano /etc/nginx/conf.d/tuanitpro.com.conf

Sử dụng đoạn code sau:

#
# tunanitpro.com configuration
#
server {
    listen       80;
    server_name tuanitpro.com;
    root /home/www/tuanitpro.com/public_html;
    location / {
        
        index index.php  index.html index.htm;
        try_files $uri $uri/ /index.php?q=$uri&$args;
    }

    error_page  404              /404.html;
    location = /404.html {
        root   /home/www/tuanitpro.com/public_html;
    }

    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /home/www/tuanitpro.com/public_html;
    }

    # pass the PHP scripts to FastCGI server
    #
    location ~ \.php$ {
        root           /home/www/tuanitpro.com/public_html;
        fastcgi_pass   127.0.0.1:9000;
        fastcgi_index  index.php;
        fastcgi_param  SCRIPT_FILENAME   $document_root$fastcgi_script_name;
        include        fastcgi_params;
    }
}

Lưu lại và thoát.

Reload Nginx

service nginx reload

Entity framework update modified fields only

Coding

 public virtual int Update(T entity, params Expression>[] properties)
        {
            if (entity.Id < 1)
            {
                return Insert(entity).Id;
            }
            if (properties?.Any() == true)
            {
                _dbContext.Attach(entity);
                foreach (var prop in properties)
                {
                    _dbContext.Entry(entity).Property(prop).IsModified = true;
                }
            }
            else
            {
                _dbContext.Entry(entity).State = EntityState.Modified;
            }

            return _dbContext.SaveChanges();
        }

        public virtual int Update(T entity, object replaceBy)
        {
            if (entity.Id < 1)
            {
                return Insert(entity).Id;
            }
            if (replaceBy == null)
            {
                return _dbContext.SaveChanges();
            }

            var properties = replaceBy.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);            
            if (properties?.Any() == true)
            {
                foreach (var prop in properties)
                {
                    var valueOfProp = prop.GetValue(replaceBy, null);
                    var propOfEntity = entity.GetType().GetProperty(prop.Name);
                    propOfEntity.SetValue(entity, Convert.ChangeType(valueOfProp, propOfEntity.PropertyType), null);

                    _dbContext.Entry(entity).Property(propOfEntity.Name).IsModified = true;
                }
            }
            else
            {
                _dbContext.Entry(entity).State = EntityState.Modified;
            }

            return _dbContext.SaveChanges();
        }

Using

var contact = new Contact { Id = 1, FullName = "Le Thanh Tuan" };

var rs1 = contactService.Update(contact, x => x.FullName);

var rs2 = contactService.Update(contact, new
{
	Id = 1,
	Phone = "0976060432",
	UserName = "tuanitpro",                
	FullName = "Le Thanh Tuan"                             
});

Handle errors in ASP.NET Core

if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
if (env.IsProduction() || env.IsStaging())
{
app.UseExceptionHandler(options =>
{
options.Run(async context =>
{
context.Response.StatusCode = 500;
context.Response.ContentType = “text/plain”;
await context.Response.WriteAsync(“CONTACT: 097 6060 432”);

var exceptionHandlerPathFeature =
context.Features.Get();
var now = System.DateTime.Now;
var eventLog = new EventLog
{
DateCreated = now,
RequestPath = exceptionHandlerPathFeature?.Path,
IPAddress = context.Request.HttpContext.Connection.RemoteIpAddress.ToString(),
Message = exceptionHandlerPathFeature?.Error.Source
};
string eventLogString = JsonConvert.SerializeObject(eventLog);

eventLogString += exceptionHandlerPathFeature?.Error.StackTrace + “\n\r”;

File.AppendAllText(“log.txt”, eventLogString);

ColorLife.Core.Helpers.IEmailProvider emailProvider = new ColorLife.Core.Helpers.EmailProvider(“[Urgent] Bug “, “[email protected]”);
emailProvider.Send(eventLogString, null);
});
});
app.UseHsts();
}

Phần mềm check shot (Shutter shots) Canon EOS 40D 50D 60D 70D 6D 7D 5D Mark II 5D Mark III 1D Mark IV

Phần mềm check shot (Shutter shots) Canon EOS 40D 50D 60D 70D 6D 7D 5D Mark II 5D Mark III 1D Mark IV giúp mọi người tự check nhanh chóng số ảnh đã chụp của máy ảnh Canon. Nhất là những bạn mua lại máy cũ đã qua sử dụng.

Tải về phần mềm EOSinfo theo link

 https://drive.google.com/file/d/1sk2FvHc05xz8nOgdC03CDIRrSvkGgnZK/view?usp=sharing

Các Camera được hỗ trợ:
Rebel XS 1000D Kiss F
Rebel XSi 450D Kiss X2
Rebel T1i 500D Kiss X3
Rebel T2i 550D Kiss X4
Rebel T3 1100D Kiss X50
Rebel T3i 600D Kiss X5
Rebel T4i 650D Kiss X6i
Rebel T5i 700D Kiss X7i
Rebel SL1 100D Kiss X7
40D 50D 60D 70D
6D 7D

5D Mark II
5D Mark III
1D Mark IV
1D X
ID C


Cách sử dụng: Giải nén và chạy file EOSInfo.exe bằng quyền Administrator

1.Tắt Camera
2.Kết nối Camera qua cổng USB
3.Mở Camera
4.Đóng chương trình EOS Utility nếu đang mở
5.Chờ kết quả
6.Tắt máy ảnh & đọc kết quả

Chúc các bạn thành công

Canon EOS 6D, Lens 40f2.8

Pagination trong ReactJs

Khi làm các ứng dụng web, chúng ta luôn có nhu cầu lấy dữ liệu từ các remote server, API… các dữ liệu mạng xã hội, tin tức, shopping, thanh toán thì rất nhiều records, do đó chúng ta cần giải pháp phân trang để giảm tải sự hiển thị quá nhiều data gây khó chịu cho người dùng.

Hướng dẫn đơn giản sau đây giúp bạn dễ dàng phân trang trong app ReactJs

Ví dụ ở đây sử dụng API dữ liệu các quốc gia, 248 quốc gia tất cả. Chúng ta sẽ bắt đầu với ứng dụng react đơn giản.

Tạo một app react js

[code lang="js"]
npx create-react-js pagination
[/code]

Cài đặt các thư viện cần thiết

[code lang="js"]
npm i bootstrap countries-api prop-types react-flags
[/code]

Sau khi cài đặt thành công chúng ta copy folder flags ở địa chỉ node_modules\react-flags\vendor đưa vào folder public\img

Open file index.js, thêm code bootstrap

[code lang=”js”] import “bootstrap/dist/css/bootstrap.min.css”; [/code]

Components

Trong folder src, tạo folder components

Tạo 2 component

  • CountryCard.jsx Component
  • Pagination.jsx Component

CountryCard Component

[code lang=”js”] import React, { Component, Fragment } from ‘react’; import PropTypes from ‘prop-types’; import Flag from ‘react-flags’; class CountryCard extends Component { render() { const { cca2: code2 = “”, region = null, name = {} } = this.props.country || {}; return (
{name.common} {region}
) } } CountryCard.propTypes = { country: PropTypes.shape({ cca2: PropTypes.string.string, region: PropTypes.string.isRequired, name: PropTypes.shape({ common: PropTypes.string.isRequired }).isRequired }).isRequired } export default CountryCard [/code]

Pagination Component

[code lang=”js”] import React, { Component, Fragment } from “react”; import PropTypes from “prop-types”; const LEFT_PAGE = “LEFT”; const RIGHT_PAGE = “RIGHT”; const range = (from, to, step = 1) => { let i = from; const range = []; while (i <= to) { range.push(i); i += step; } return range; }; class Pagination extends Component { constructor(props) { super(props); const { totalRecords = null, pageLimit = 30, pageNeighbours = 0 } = props; this.pageLimit = typeof pageLimit === "number" ? pageLimit : 30; this.totalRecords = typeof totalRecords === "number" ? totalRecords : 0; this.pageNeighbours = typeof pageNeighbours === "number" ? Math.max(0, Math.min(pageNeighbours, 2)) : 0; this.totalPages = Math.ceil(this.totalRecords / this.pageLimit); this.state = { currentPage: 1 }; } componentDidMount() { this.gotoPage(1); } gotoPage = page => { const { onPageChanged = f => f } = this.props; const currentPage = Math.max(0, Math.min(page, this.totalPages)); const paginationData = { currentPage, totalPages: this.totalPages, pageLimit: this.pageLimit, totalRecords: this.totalRecords }; this.setState({ currentPage }, () => onPageChanged(paginationData)); }; handleClick = (page, evt) => { evt.preventDefault(); this.gotoPage(page); }; handleMoveLeft = evt => { evt.preventDefault(); this.gotoPage(this.state.currentPage – this.pageNeighbours * 2 – 1); }; handleMoveRight = evt => { evt.preventDefault(); this.gotoPage(this.state.currentPage + this.pageNeighbours * 2 + 1); }; fetchPageNumbers = () => { const totalPages = this.totalPages; const currentPage = this.state.currentPage; const pageNeighbours = this.pageNeighbours; const totalNumbers = this.pageNeighbours * 2 + 3; const totalBlocks = totalNumbers + 2; if (totalPages > totalBlocks) { let pages = []; const leftBound = currentPage – pageNeighbours; const rightBound = currentPage + pageNeighbours; const beforeLastPage = totalPages – 1; const startPage = leftBound > 2 ? leftBound : 2; const endPage = rightBound < beforeLastPage ? rightBound : beforeLastPage; pages = range(startPage, endPage); const pagesCount = pages.length; const singleSpillOffset = totalNumbers - pagesCount - 1; const leftSpill = startPage > 2; const rightSpill = endPage < beforeLastPage; const leftSpillPage = LEFT_PAGE; const rightSpillPage = RIGHT_PAGE; if (leftSpill && !rightSpill) { const extraPages = range(startPage - singleSpillOffset, startPage - 1); pages = [leftSpillPage, ...extraPages, ...pages]; } else if (!leftSpill && rightSpill) { const extraPages = range(endPage + 1, endPage + singleSpillOffset); pages = [...pages, ...extraPages, rightSpillPage]; } else if (leftSpill && rightSpill) { pages = [leftSpillPage, ...pages, rightSpillPage]; } return [1, ...pages, totalPages]; } return range(1, totalPages); }; render() { if (!this.totalRecords) return null; if (this.totalPages === 1) return null; const { currentPage } = this.state; const pages = this.fetchPageNumbers(); return ( ); } } Pagination.propTypes = { totalRecords: PropTypes.number.isRequired, pageLimit: PropTypes.number, pageNeighbours: PropTypes.number, onPageChanged: PropTypes.func }; export default Pagination; [/code]

App.js

[code lang=”js”] import React, { Component } from ‘react’; import Countries from ‘countries-api/lib/data/Countries.json’; import ‘./App.css’; import Pagination from “./components/Pagination”; import CountryCard from ‘./components/CountryCard’; class App extends Component { state = { allCountries: [], currentCountries: [], currentPage: null, totalPages: null }; componentDidMount() { const allCountries = Countries; this.setState({ allCountries }); } onPageChanged = data => { const { allCountries } = this.state; const { currentPage, totalPages, pageLimit } = data; const offset = (currentPage – 1) * pageLimit; const currentCountries = allCountries.slice(offset, offset + pageLimit); this.setState({ currentPage, currentCountries, totalPages }); }; mapCountry(country, index) { return } render() { const { allCountries, currentCountries, currentPage, totalPages } = this.state; const totalCountries = allCountries.length; if (totalCountries === 0) return null; const headerClass = [ “text-dark py-2 pr-4 m-0”, currentPage ? “border-gray border-right” : “” ] .join(” “) .trim(); const displayCountries = currentCountries.map(this.mapCountry); return (

{totalCountries}{” “} Countries

{currentPage && ( Page {currentPage} /{” “} {totalPages} )}
{displayCountries}
); } } export default App; [/code]

Download mã nguồn ở đây

GitHub

LÀM ĐÀN ÔNG ĐỪNG CÁI GÌ CŨNG CỐ GIỎI, CHỈ CẦN XUẤT CHÚNG MỘT KỸ NĂNG, CẢ ĐỜI BẠN SẼ NỞ HOA

Người xưa đã có câu “nhất nghệ tinh, nhất thân vinh, hay một nghề cho chín, còn hơn chín nghề.”  Nhưng đọc thêm bài viết dài một chút cũng không hẳn là một ý tồi.

Đứa bạn 1: Tôi có thể thiết kế rất giỏi

Đứa bạn 2: Tôi là một huấn luyện viên gym rất xuất sắc

Đồng nghiệp 1: Tôi cực kỳ giỏi việc nịnh sếp

Đồng nghiệp 2: Tôi thực sự rất giỏi việc đóng clip hài

Tôi: Tôi có thể làm mọi thứ mà các ông làm

1. Có một sự thật là khi bạn giỏi mọi thứ, thực ra bạn lại chẳng thực sự giỏi một thứ gì. Ngoại trừ những “siêu nhân” biết tuốt, mỗi người trên cuộc đời này chỉ thực sự vĩ đại trong một lĩnh vực hay kỹ năng gì đó, và đó là thứ sẽ nuôi sống người đàn ông cả cuộc đời.

2. Trường học dạy chúng ta phải có điểm cao ở mọi môn, nhưng trường đời chỉ thực sự cần bạn là chuyên gia trong một lĩnh vực mà thôi. Như các cụ đã nói, một nghề cho chín còn hơn chín nghề.

3. Trong cuốn sách Average is Over (Tạm dịch: Sự chấm hết của trung bình), kinh tế gia Tyler Cowen cho rằng kỷ nguyên của sự “bình thường” sắp chấm dứt.

Chỉ vào chục năm nữa, khi robot bắt đầu thay thế các công việc đòi hỏi kỹ năng tầm thấp hoặc trung bình, chiến lược sống sót duy nhất của bạn là phải giỏi ở một thứ, chỉ cần một mà thôi.

5. Giỏi nhiều thứ mới dễ, xuất chúng ở một ngành nghề mới thực sự khó. Khi bạn nghe thấy một đứa bạn, vừa đánh đàn giỏi, vừa học giỏi, vừa kinh doanh giỏi, vừa làm chồng giỏi, vừa làm bố giỏi… nói chung cái gì cũng giỏi, thì tốt nhất hãy xem gia thế của bạn ấy là ai trước.

Vì sự thực là, sẽ luôn có chi phí cơ hội, cực kỳ hiếm người có thể xuất sắc ở mọi lĩnh vực. Ngoài ra, thì để cái gì cũng biết thì vô cùng dễ, để thực sự là chuyên gia đầu ngành của một lĩnh vực thì đòi hỏi sức kiên trì lớn hơn rất nhiều.

6. Quy luật 10,000 giờ. Để thực sự xuất chúng ở một chuyên ngành nào đó, bạn cần bỏ ra ít nhất 10,000 giờ cho chúng. Nghe thì không to lắm, nhưng để ngày nào cũng bỏ ra 2-3 tiếng “luyện công” thì bạn thực sự cần có kỹ năng kỷ luật bản thân rất tốt. Nhưng biết làm sao được, nếu ghế của cha bạn không to, nhà bạn không giàu, thì đó dường như là con đường duy nhất dẫn đến thành công.

7. “Tạm được là chưa đủ.” Chắc chắc đôi khi bạn sẽ gặp những sếp dễ tính, và khi bạn nộp một sản phẩm chưa hoàn hảo nhất với sức lực của mình, họ đã khen “Em làm tốt rồi”. Cái lợi của việc này là bạn cảm thấy được trân trọng, nhưng thực ra ông sếp đang làm hại bạn.

Thỏa mãn bản thân với những kết quả chưa thực sự “chín” sẽ làm bạn mất thái độ cầu toàn, và khó có thể leo lên tầm chuyên gia, khi những việc nhỏ còn làm chưa trọn vẹn.

8. Kiên nhẫn không phải dễ dàng. Nó đau đớn và cực kỳ nhọc nhằn. Thành công chưa bao giờ là dễ. Tập trung vào một điểm mạnh của mình và đưa nó lên “cấp” cao nhất chưa bao giờ là dễ dàng. Bạn sẽ gặp khó khăn, bạn sẽ nản và muốn nhảy vòng quanh để giỏi ở mọi thứ, nhưng đó là cái bẫy.

Thời trai trẻ, đừng lãng phí.

Từ năm 20-30 tuổi, siêu tập trung vào chỉ một lĩnh vực, trở thành chuyên gia hàng đầu trong lĩnh vực đó, ngành nghề gì cũng được, và bạn sẽ không phải hối hận.

Nguồn: Tri thức trẻ
Ảnh: happy.live