Compare commits
76 Commits
dev-jekyll
...
dev
| Author | SHA1 | Date | |
|---|---|---|---|
| 2acf391f7d | |||
| a8b466c8db | |||
| 7bd7fa90c4 | |||
| 33b8e61f42 | |||
| 7b3ae70073 | |||
| cd3ffa479c | |||
| 99cbe51cac | |||
| e3e3346fd3 | |||
| 0e69643c66 | |||
| e930ed0f2f | |||
| 4cd29e188d | |||
| 7ffcc1a83b | |||
| 8d37136815 | |||
| 2f1c45293e | |||
| 464bd0ccef | |||
| bb04c90f4a | |||
| a0fb32aa0f | |||
| a069ca7961 | |||
| c091bac4aa | |||
| a66e3fa1a3 | |||
| 8f4170a4b7 | |||
| e3e24d561d | |||
| f721c98e33 | |||
| 88ef311141 | |||
| c3d25b78e4 | |||
| a1c6f518aa | |||
| 01a666a42e | |||
| 982c65f9ed | |||
| edbf7ec02f | |||
| d684eca9b3 | |||
| 0357345d02 | |||
| ea8dddd6fb | |||
| 11364b0047 | |||
| 160441293e | |||
| 9852e338b0 | |||
| 50b53f6371 | |||
| 5e0b39a1fb | |||
| f06a42cb69 | |||
| 1c68d60f2b | |||
| 6c188e779b | |||
| 5a93cb9b86 | |||
| 95f097234d | |||
| dc3104527b | |||
| 68e056d3ad | |||
| 30c159be2c | |||
| 82276dbb8a | |||
| 31adea59f4 | |||
| 09d1c94a92 | |||
| 74a1ba43cd | |||
| 03a9269fa3 | |||
| 9dc892c1d4 | |||
| d69ee3326e | |||
| 5a0ff70502 | |||
| b7ce8ad551 | |||
| 85554b9a65 | |||
| 5942fde518 | |||
| c110f5bb79 | |||
| 77714e38b2 | |||
| ce7ed6540a | |||
| 1f6b3fffb8 | |||
| f073272f1f | |||
| ab3917adcc | |||
| b33faddcb5 | |||
| c03611262b | |||
| 345840c543 | |||
| 6aca7be258 | |||
| 36de09ac1c | |||
| da578461fc | |||
| 1d9ac4dbce | |||
| 42f4b533b1 | |||
| 4ab4cad773 | |||
| 27e59a86bc | |||
| c2c9bdad43 | |||
| 81bdcf6259 | |||
| d3db8448fb | |||
| 5e8c81991b |
@ -1 +1 @@
|
||||
{"taxonomy":{"tags":["comment-system","hello","privacy","remark42","self-hosted","test","world"],"categories":[]}}
|
||||
{"taxonomy":{"tags":["comment-system","hello","principles","privacy","remark42","self-hosted","test","world"],"categories":[]}}
|
||||
4
.github/workflows/pages-deploy.yml
vendored
4
.github/workflows/pages-deploy.yml
vendored
@ -42,7 +42,7 @@ jobs:
|
||||
- name: Setup Ruby
|
||||
uses: ruby/setup-ruby@v1
|
||||
with:
|
||||
ruby-version: 3.2
|
||||
ruby-version: 3.3
|
||||
bundler-cache: true
|
||||
|
||||
- name: Build site
|
||||
@ -53,7 +53,7 @@ jobs:
|
||||
- name: Test site
|
||||
run: |
|
||||
bundle exec htmlproofer _site \
|
||||
\-\-disable-external=true \
|
||||
\-\-disable-external \
|
||||
\-\-ignore-urls "/^http:\/\/127.0.0.1/,/^http:\/\/0.0.0.0/,/^http:\/\/localhost/"
|
||||
|
||||
- name: Upload site artifact
|
||||
|
||||
6
.gitignore
vendored
6
.gitignore
vendored
@ -5,6 +5,7 @@ Gemfile.lock
|
||||
|
||||
# Jekyll cache
|
||||
.jekyll-cache
|
||||
.jekyll-metadata
|
||||
_site
|
||||
|
||||
# RubyGems
|
||||
@ -16,6 +17,11 @@ package-lock.json
|
||||
|
||||
# IDE configurations
|
||||
.idea
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/extensions.json
|
||||
!.vscode/tasks.json
|
||||
|
||||
# Misc
|
||||
_sass/vendors
|
||||
assets/js/dist
|
||||
|
||||
26
.vscode/tasks.json
vendored
Normal file
26
.vscode/tasks.json
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
{
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "Run Jekyll Server",
|
||||
"type": "shell",
|
||||
"command": "./tools/run.sh",
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
},
|
||||
"problemMatcher": [],
|
||||
"detail": "Runs the Jekyll server with live reload."
|
||||
},
|
||||
{
|
||||
"label": "Build Jekyll Site",
|
||||
"type": "shell",
|
||||
"command": "./tools/test.sh",
|
||||
"group": {
|
||||
"kind": "build"
|
||||
},
|
||||
"problemMatcher": [],
|
||||
"detail": "Build the Jekyll site for production."
|
||||
}
|
||||
]
|
||||
}
|
||||
6
Gemfile
6
Gemfile
@ -2,10 +2,10 @@
|
||||
|
||||
source "https://rubygems.org"
|
||||
|
||||
gem "jekyll-theme-chirpy", "~> 6.2", ">= 6.5.5"
|
||||
gem "jekyll-theme-chirpy", "~> 7.2", ">= 7.2.2"
|
||||
|
||||
group :test do
|
||||
gem "html-proofer", "~> 4.4"
|
||||
gem "html-proofer", "~> 5.0", group: :test
|
||||
end
|
||||
|
||||
# Windows and JRuby does not include zoneinfo files, so bundle the tzinfo-data gem
|
||||
@ -16,7 +16,7 @@ platforms :mingw, :x64_mingw, :mswin, :jruby do
|
||||
end
|
||||
|
||||
# Performance-booster for watching directories on Windows
|
||||
gem "wdm", "~> 0.1.1", :platforms => [:mingw, :x64_mingw, :mswin]
|
||||
gem "wdm", "~> 0.2.0", :platforms => [:mingw, :x64_mingw, :mswin]
|
||||
|
||||
# Lock `http_parser.rb` gem to `v0.6.x` on JRuby builds since newer versions of the gem
|
||||
# do not have a Java counterpart.
|
||||
|
||||
92
README.md
92
README.md
@ -1,81 +1,43 @@
|
||||
<div align="center">
|
||||
# Chirpy Starter
|
||||
|
||||
# Chirpy Jekyll Theme
|
||||
[][gem]
|
||||
[][mit]
|
||||
|
||||
A minimal, responsive, and feature-rich Jekyll theme for technical writing.
|
||||
When installing the [**Chirpy**][chirpy] theme through [RubyGems.org][gem], Jekyll can only read files in the folders
|
||||
`_data`, `_layouts`, `_includes`, `_sass` and `assets`, as well as a small part of options of the `_config.yml` file
|
||||
from the theme's gem. If you have ever installed this theme gem, you can use the command
|
||||
`bundle info --path jekyll-theme-chirpy` to locate these files.
|
||||
|
||||
[][gem]
|
||||
[][ci]
|
||||
[][codacy]
|
||||
[][license]
|
||||
[](https://996.icu)
|
||||
The Jekyll team claims that this is to leave the ball in the user’s court, but this also results in users not being
|
||||
able to enjoy the out-of-the-box experience when using feature-rich themes.
|
||||
|
||||
[**Live Demo** →][demo]
|
||||
To fully use all the features of **Chirpy**, you need to copy the other critical files from the theme's gem to your
|
||||
Jekyll site. The following is a list of targets:
|
||||
|
||||
[][demo]
|
||||
```shell
|
||||
.
|
||||
├── _config.yml
|
||||
├── _plugins
|
||||
├── _tabs
|
||||
└── index.html
|
||||
```
|
||||
|
||||
</div>
|
||||
To save you time, and also in case you lose some files while copying, we extract those files/configurations of the
|
||||
latest version of the **Chirpy** theme and the [CD][CD] workflow to here, so that you can start writing in minutes.
|
||||
|
||||
## Features
|
||||
## Usage
|
||||
|
||||
- Dark / Light Theme Mode
|
||||
- Localized UI language
|
||||
- Pinned Posts on Home Page
|
||||
- Hierarchical Categories
|
||||
- Trending Tags
|
||||
- Table of Contents
|
||||
- Last Modified Date
|
||||
- Syntax Highlighting
|
||||
- Mathematical Expressions
|
||||
- Mermaid Diagrams & Flowcharts
|
||||
- Dark / Light Mode Images
|
||||
- Embed Videos
|
||||
- Disqus / Giscus / Utterances Comments
|
||||
- Built-in Search
|
||||
- Atom Feeds
|
||||
- PWA
|
||||
- Google Analytics / GoatCounter
|
||||
- SEO & Performance Optimization
|
||||
|
||||
## Documentation
|
||||
|
||||
To learn how to use, develop, and upgrade the project, please refer to the [Wiki][wiki].
|
||||
Check out the [theme's docs](https://github.com/cotes2020/jekyll-theme-chirpy/wiki).
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions (_pull requests_, _issues_, and _discussions_) are what make the open-source community such an amazing place
|
||||
to learn, inspire, and create. Any contributions you make are greatly appreciated.
|
||||
For details, see the "[Contributing Guidelines][contribute-guide]".
|
||||
|
||||
## Credits
|
||||
|
||||
### Contributors
|
||||
|
||||
Thanks to [all the contributors][contributors] involved in the development of the project!
|
||||
|
||||
[][contributors]
|
||||
<sub> —— Made with [contrib.rocks](https://contrib.rocks)</sub>
|
||||
|
||||
### Third-Party Assets
|
||||
|
||||
This project is built on the [Jekyll][jekyllrb] ecosystem and some [great libraries][lib], and is developed using [VS Code][vscode] as well as tools provided by [JetBrains][jetbrains] under a non-commercial open-source software license.
|
||||
|
||||
The avatar and favicon for the project's website are from [ClipartMAX][clipartmax].
|
||||
This repository is automatically updated with new releases from the theme repository. If you encounter any issues or want to contribute to its improvement, please visit the [theme repository][chirpy] to provide feedback.
|
||||
|
||||
## License
|
||||
|
||||
This project is published under [MIT License][license].
|
||||
This work is published under [MIT][mit] License.
|
||||
|
||||
[gem]: https://rubygems.org/gems/jekyll-theme-chirpy
|
||||
[ci]: https://github.com/cotes2020/jekyll-theme-chirpy/actions/workflows/ci.yml?query=event%3Apush+branch%3Amaster
|
||||
[codacy]: https://app.codacy.com/gh/cotes2020/jekyll-theme-chirpy/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade
|
||||
[license]: https://github.com/cotes2020/jekyll-theme-chirpy/blob/master/LICENSE
|
||||
[jekyllrb]: https://jekyllrb.com/
|
||||
[clipartmax]: https://www.clipartmax.com/middle/m2i8b1m2K9Z5m2K9_ant-clipart-childrens-ant-cute/
|
||||
[demo]: https://cotes2020.github.io/chirpy-demo/
|
||||
[wiki]: https://github.com/cotes2020/jekyll-theme-chirpy/wiki
|
||||
[contribute-guide]: https://github.com/cotes2020/jekyll-theme-chirpy/blob/master/docs/CONTRIBUTING.md
|
||||
[contributors]: https://github.com/cotes2020/jekyll-theme-chirpy/graphs/contributors
|
||||
[lib]: https://github.com/cotes2020/chirpy-static-assets
|
||||
[vscode]: https://code.visualstudio.com/
|
||||
[jetbrains]: https://www.jetbrains.com/?from=jekyll-theme-chirpy
|
||||
[chirpy]: https://github.com/cotes2020/jekyll-theme-chirpy/
|
||||
[CD]: https://en.wikipedia.org/wiki/Continuous_deployment
|
||||
[mit]: https://github.com/cotes2020/chirpy-starter/blob/master/LICENSE
|
||||
70
_config.yml
70
_config.yml
@ -15,22 +15,22 @@ timezone: Asia/Kolkata
|
||||
# jekyll-seo-tag settings › https://github.com/jekyll/jekyll-seo-tag/blob/master/docs/usage.md
|
||||
# ↓ --------------------------
|
||||
|
||||
title: Bangara Raju # the main title
|
||||
title: Engineer's Odyssey # the main title
|
||||
|
||||
tagline: Only Blogging Nothing More or Less # it will display as the sub-title
|
||||
tagline: Your Hub for Tech, DIY, and Innovation # it will display as the subtitle
|
||||
|
||||
description: >- # used by seo meta and the atom feed
|
||||
Through my articles and stories, I hope to guide you through the intricate world of technology, offer insights into automation's transformative power, unveil the secrets behind successful DIY projects, and encourage you to fearlessly pursue new skills.
|
||||
|
||||
# Fill in the protocol & hostname for your site.
|
||||
# e.g. 'https://username.github.io', note that it does not end with a '/'.
|
||||
# E.g. 'https://username.github.io', note that it does not end with a '/'.
|
||||
url: "http://localhost:4000"
|
||||
|
||||
github:
|
||||
username: rajukottedi # change to your github username
|
||||
username: rajukottedi # change to your GitHub username
|
||||
|
||||
twitter:
|
||||
username: RajuKottedi # change to your twitter username
|
||||
username: RajuKottedi # change to your Twitter username
|
||||
|
||||
social:
|
||||
# Change to your full name.
|
||||
@ -39,22 +39,44 @@ social:
|
||||
email: bangararaju.kottedi@gmail.com # change to your email address
|
||||
links:
|
||||
# The first element serves as the copyright owner's link
|
||||
- https://github.com/rajukottedi # change to your github homepage
|
||||
- https://twitter.com/rajukottedi # change to your twitter homepage
|
||||
- https://github.com/rajukottedi # change to your GitHub homepage
|
||||
- https://twitter.com/rajukottedi # change to your Twitter homepage
|
||||
# Uncomment below to add more social links
|
||||
- https://www.facebook.com/RajuKottedi435
|
||||
- https://in.linkedin.com/in/bangara-raju-kottedi-299072109
|
||||
- https://www.linkedin.com/in/bangararajuk/
|
||||
|
||||
google_site_verification: # fill in to your verification string
|
||||
# Site Verification Settings
|
||||
webmaster_verifications:
|
||||
google: # fill in your Google verification code
|
||||
bing: # fill in your Bing verification code
|
||||
alexa: # fill in your Alexa verification code
|
||||
yandex: # fill in your Yandex verification code
|
||||
baidu: # fill in your Baidu verification code
|
||||
facebook: # fill in your Facebook verification code
|
||||
|
||||
# ↑ --------------------------
|
||||
# The end of `jekyll-seo-tag` settings
|
||||
|
||||
google_analytics:
|
||||
id: G-W2VG43SN3N # fill in your Google Analytics ID
|
||||
# Web Analytics Settings
|
||||
analytics:
|
||||
google:
|
||||
id: # fill in your Google Analytics ID
|
||||
goatcounter:
|
||||
id: # fill in your GoatCounter ID
|
||||
umami:
|
||||
id: # fill in your Umami ID
|
||||
domain: # fill in your Umami domain
|
||||
matomo:
|
||||
id: # fill in your Matomo ID
|
||||
domain: # fill in your Matomo domain
|
||||
cloudflare:
|
||||
id: # fill in your Cloudflare Web Analytics token
|
||||
fathom:
|
||||
id: # fill in your Fathom Site ID
|
||||
|
||||
goatcounter:
|
||||
id: # fill in your Goatcounter ID
|
||||
# Page Views settings
|
||||
pageviews:
|
||||
provider: # now only supports 'goatcounter'
|
||||
|
||||
# Prefer color scheme setting.
|
||||
#
|
||||
@ -69,12 +91,12 @@ goatcounter:
|
||||
#
|
||||
theme_mode: # [light | dark]
|
||||
|
||||
# The CDN endpoint for images.
|
||||
# The CDN endpoint for media resources.
|
||||
# Notice that once it is assigned, the CDN url
|
||||
# will be added to all image (site avatar & posts' images) paths starting with '/'
|
||||
# will be added to all media resources (site avatar, posts' images, audio and video files) paths starting with '/'
|
||||
#
|
||||
# e.g. 'https://cdn.com'
|
||||
img_cdn:
|
||||
cdn:
|
||||
|
||||
# the avatar on sidebar, support local or CORS resources
|
||||
avatar: /assets/img/avatar.jpg
|
||||
@ -87,7 +109,8 @@ social_preview_image: # string, local or CORS resources
|
||||
toc: true
|
||||
|
||||
comments:
|
||||
active: 'remark42' # The global switch for posts comments, e.g., 'disqus'. Keep it empty means disable
|
||||
# Global switch for the post comment system. Keeping it empty means disabled.
|
||||
provider: 'remark42' # [disqus | utterances | giscus]
|
||||
# The active options are as follows:
|
||||
# remark42 settings > https://remark42.com/
|
||||
remark42:
|
||||
@ -105,6 +128,7 @@ comments:
|
||||
category:
|
||||
category_id:
|
||||
mapping: # optional, default to 'pathname'
|
||||
strict: # optional, default to '0'
|
||||
input_position: # optional, default to 'bottom'
|
||||
lang: # optional, default to the value of `site.lang`
|
||||
reactions_enabled: # optional, default to the value of `1`
|
||||
@ -118,13 +142,14 @@ assets:
|
||||
env: # [development | production]
|
||||
|
||||
pwa:
|
||||
enabled: true # the option for PWA feature (installable)
|
||||
enabled: true # The option for PWA feature (installable)
|
||||
cache:
|
||||
enabled: true # the option for PWA offline cache
|
||||
# Paths defined here will be excluded from the PWA cache.
|
||||
# Usually its value is the `baseurl` of another website that
|
||||
# shares the same domain name as the current website.
|
||||
deny_paths:
|
||||
- "/api"
|
||||
# - "/example" # URLs match `<SITE_URL>/example/*` will not be cached by the PWA
|
||||
|
||||
paginate: 10
|
||||
@ -135,6 +160,7 @@ baseurl: "/blog"
|
||||
# ------------ The following options are not recommended to be modified ------------------
|
||||
|
||||
kramdown:
|
||||
footnote_backlink: "↩︎"
|
||||
syntax_highlighter: rouge
|
||||
syntax_highlighter_opts: # Rouge Options › https://github.com/jneen/rouge#full-options
|
||||
css_class: highlight
|
||||
@ -195,8 +221,11 @@ exclude:
|
||||
- tools
|
||||
- README.md
|
||||
- LICENSE
|
||||
- purgecss.js
|
||||
- rollup.config.js
|
||||
- package*.json
|
||||
- "package*.json"
|
||||
- db_scripts
|
||||
- frontmatter.json
|
||||
|
||||
jekyll-archives:
|
||||
enabled: [categories, tags]
|
||||
@ -214,4 +243,5 @@ future: true
|
||||
# Custom configuration
|
||||
custom-config:
|
||||
blog-services:
|
||||
service_url: 'http://localhost:5000'
|
||||
service_url: 'https://localhost:7013/blog/api/v1/posts'
|
||||
service_key: 'c6eAXYcNT873TT7BfMgQyS4ii7hxa53TLEUN7pAGaaU='
|
||||
@ -5,7 +5,7 @@
|
||||
|
||||
- type: linkedin
|
||||
icon: 'fab fa-linkedin' # icons powered by <https://fontawesome.com/>
|
||||
url: 'https://in.linkedin.com/in/bangara-raju-kottedi-299072109' # Fill with your Linkedin homepage
|
||||
url: 'https://www.linkedin.com/in/bangararajuk/' # Fill with your Linkedin homepage
|
||||
|
||||
# - type: twitter
|
||||
# icon: "fa-brands fa-x-twitter"
|
||||
@ -26,3 +26,15 @@
|
||||
# - type: stack-overflow
|
||||
# icon: 'fab fa-stack-overflow'
|
||||
# url: '' # Fill with your stackoverflow homepage
|
||||
#
|
||||
# - type: bluesky
|
||||
# icon: 'fa-brands fa-bluesky'
|
||||
# url: '' # Fill with your Bluesky profile link
|
||||
#
|
||||
# - type: reddit
|
||||
# icon: 'fa-brands fa-reddit'
|
||||
# url: '' # Fill with your Reddit profile link
|
||||
#
|
||||
# - type: threads
|
||||
# icon: 'fa-brands fa-threads'
|
||||
# url: '' # Fill with your Threads profile link
|
||||
|
||||
@ -22,7 +22,7 @@ platforms:
|
||||
#
|
||||
# - type: Weibo
|
||||
# icon: "fab fa-weibo"
|
||||
# link: "http://service.weibo.com/share/share.php?title=TITLE&url=URL"
|
||||
# link: "https://service.weibo.com/share/share.php?title=TITLE&url=URL"
|
||||
#
|
||||
# - type: Mastodon
|
||||
# icon: "fa-brands fa-mastodon"
|
||||
@ -35,4 +35,16 @@ platforms:
|
||||
# - label: fosstodon.org
|
||||
# link: "https://fosstodon.org/"
|
||||
# - label: photog.social
|
||||
# link: "https://photog.social/"
|
||||
# link: "https://photog.social/"
|
||||
#
|
||||
# - type: Bluesky
|
||||
# icon: "fa-brands fa-bluesky"
|
||||
# link: "https://bsky.app/intent/compose?text=TITLE%20URL"
|
||||
#
|
||||
# - type: Reddit
|
||||
# icon: "fa-brands fa-square-reddit"
|
||||
# link: "https://www.reddit.com/submit?url=URL&title=TITLE"
|
||||
#
|
||||
# - type: Threads
|
||||
# icon: "fa-brands fa-square-threads"
|
||||
# link: "https://www.threads.net/intent/post?text=TITLE%20URL"
|
||||
8
_drafts/2024-07-08-anatomy-of-a-csrf-attack.md
Normal file
8
_drafts/2024-07-08-anatomy-of-a-csrf-attack.md
Normal file
@ -0,0 +1,8 @@
|
||||
---
|
||||
title: Anatomy of a CSRF Attack
|
||||
date: 2024-07-08 0:00:00 +5:30
|
||||
tags:
|
||||
- csrf
|
||||
- security
|
||||
slug: anatomy-csrf-attack
|
||||
---
|
||||
28
_drafts/2025-02-02-getting-started-with-python.md
Normal file
28
_drafts/2025-02-02-getting-started-with-python.md
Normal file
@ -0,0 +1,28 @@
|
||||
---
|
||||
title: "Part 1: Getting Started with Python"
|
||||
description: Kick off your Python journey! Learn what Python is, set up your environment, and write your first program. Perfect for beginners—let’s start coding!
|
||||
date: 2025-02-02T16:59:46.763Z
|
||||
tags: []
|
||||
categories: []
|
||||
image:
|
||||
path: /assets/img/posts/python-getting-started.png
|
||||
disable-ty: false
|
||||
series: "Python Practical Guide: A Beginner's Journey"
|
||||
slug: part-1-started-python
|
||||
---
|
||||
|
||||
## What is Python?
|
||||
Python is a versatile, high-level programming language known for its simplicity and readability. It’s used for:
|
||||
- Web development
|
||||
- Data analysis and visualization
|
||||
- Artificial intelligence and machine learning
|
||||
- Automation and scripting
|
||||
- Game development
|
||||
- And much more!
|
||||
|
||||
## Why Learn Python?
|
||||
1. **Beginner-Friendly**: Easy-to-read syntax makes it perfect for first-time coders.
|
||||
2. **Versatile**: Use it for almost any type of project or industry.
|
||||
3. **In-Demand Skill**: Python developers are highly sought after in the job market.
|
||||
4. **Huge Community**: Tons of resources, libraries, and frameworks to help you learn and grow.
|
||||
5. **Fun and Powerful**: Automate tasks, analyze data, or build apps—Python makes it easy!
|
||||
@ -0,0 +1,12 @@
|
||||
---
|
||||
title: "Part 2: Python Basics - Syntax and Fundamentals"
|
||||
description: "Learn Python’s building blocks: variables, data types, input/output, and basic operations. Start writing clean, readable code today!"
|
||||
date: 2025-02-02T18:04:14.853Z
|
||||
tags: []
|
||||
categories: []
|
||||
image:
|
||||
path: /assets/img/posts/python-logo.jpg
|
||||
disable-ty: true
|
||||
series: "Python Practical Guide: A Beginner's Journey"
|
||||
slug: part-2-python-basics-syntax-fundamentals
|
||||
---
|
||||
5
_includes/comment.html
Normal file
5
_includes/comment.html
Normal file
@ -0,0 +1,5 @@
|
||||
<!-- The comments switcher -->
|
||||
{% if page.comments and site.comments.provider %}
|
||||
{% capture path %}comments/{{ site.comments.provider }}.html{% endcapture %}
|
||||
{% include {{ path }} %}
|
||||
{% endif %}
|
||||
@ -4,6 +4,30 @@
|
||||
}
|
||||
</style>
|
||||
|
||||
<i class="fa fa-comment" aria-hidden="true" {% if include.tooltip %} title="{{site.data.locales[include.lang].post.comments}}"
|
||||
data-bs-toggle="tooltip" data-bs-placement="bottom" {% endif %}></i>
|
||||
<span class="remark42__counter"></span>
|
||||
<i class="fa fa-comment" aria-hidden="true" {% if include.tooltip %}
|
||||
title="{{site.data.locales[include.lang].post.comments}}" data-bs-toggle="tooltip" data-bs-placement="bottom" {%
|
||||
endif %}></i>
|
||||
<span class="remark42__counter"></span>
|
||||
|
||||
<script>
|
||||
function commentTextChange() {
|
||||
var target = document.querySelector('.remark42__counter');
|
||||
if(!target){
|
||||
window.setTimeout(commentTextChange, 500);
|
||||
return;
|
||||
}
|
||||
var observer = new MutationObserver(function (mutations) {
|
||||
const comments = document.querySelector(".remark42__counter");
|
||||
var commentsCount = 0;
|
||||
if(Number(comments.innerText) !== NaN){
|
||||
commentsCount = Number(comments.innerText);
|
||||
}
|
||||
if(commentsCount !== commentsCountFromResponse){
|
||||
ajax(serviceUrl + "/UpdatePostCommentsCount?blogUrl=" + siteId + "&postSlug=" + postId, "POST", commentsCount);
|
||||
}
|
||||
});
|
||||
var config = { childList: true };
|
||||
observer.observe(target, config);
|
||||
}
|
||||
commentTextChange();
|
||||
</script>
|
||||
@ -1,5 +0,0 @@
|
||||
<!-- The comments switcher -->
|
||||
{% if page.comments and site.comments.active %}
|
||||
{% capture path %}comments/{{ site.comments.active }}.html{% endcapture %}
|
||||
{% include {{ path }} %}
|
||||
{% endif %}
|
||||
@ -4,11 +4,11 @@
|
||||
<script>
|
||||
var remark_config = {
|
||||
host: remark42Host,
|
||||
site_id: siteId,
|
||||
site_id: "{{site.id}}",
|
||||
components: ['embed', 'counter'],
|
||||
|
||||
max_shown_comments: 10,
|
||||
theme: modeToggle.modeStatus,
|
||||
theme: Theme.visualState,
|
||||
|
||||
locale: 'en',
|
||||
show_email_subscription: false
|
||||
@ -23,11 +23,11 @@
|
||||
}
|
||||
})(remark_config.components || ['embed']);
|
||||
|
||||
var targetDiv = document.getElementById("sidebar").getElementsByClassName("mode-toggle")[0];
|
||||
var targetDiv = document.getElementById("mode-toggle");
|
||||
|
||||
if (targetDiv != null) {
|
||||
targetDiv.addEventListener("click", () => {
|
||||
window.REMARK42.changeTheme(modeToggle.modeStatus === 'light' ? 'dark' : 'light');
|
||||
window.REMARK42.changeTheme(Theme.visualState === 'light' ? 'dark' : 'light');
|
||||
})
|
||||
}
|
||||
</script>
|
||||
@ -4,7 +4,7 @@
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||
<meta name="theme-color" media="(prefers-color-scheme: light)" content="#f7f7f7">
|
||||
<meta name="theme-color" media="(prefers-color-scheme: dark)" content="#1b1b1e">
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta name="mobile-web-app-capable" content="yes">
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
|
||||
<meta name="viewport"
|
||||
content="width=device-width, user-scalable=no initial-scale=1, shrink-to-fit=no, viewport-fit=cover">
|
||||
@ -20,7 +20,7 @@
|
||||
|
||||
{% unless src contains '://' %}
|
||||
{%- capture img_url -%}
|
||||
{% include img-url.html src=src img_path=page.img_path absolute=true %}
|
||||
{% include media-url.html src=src subpath=page.media_subpath absolute=true %}
|
||||
{%- endcapture -%}
|
||||
|
||||
{%- capture old_url -%}{{ src | absolute_url }}{%- endcapture -%}
|
||||
@ -31,7 +31,7 @@
|
||||
|
||||
{% elsif site.social_preview_image %}
|
||||
{%- capture img_url -%}
|
||||
{% include img-url.html src=site.social_preview_image absolute=true %}
|
||||
{% include media-url.html src=site.social_preview_image absolute=true %}
|
||||
{%- endcapture -%}
|
||||
|
||||
{%- capture og_image -%}
|
||||
@ -59,34 +59,30 @@
|
||||
|
||||
{% include_cached favicons.html %}
|
||||
|
||||
{% if site.resources.ignore_env != jekyll.environment and site.resources.self_hosted %}
|
||||
<link href="{{ site.data.origin[type].webfonts | relative_url }}" rel="stylesheet">
|
||||
|
||||
{% else %}
|
||||
{% for cdn in site.data.origin[type].cdns %}
|
||||
<link rel="preconnect" href="{{ cdn.url }}" {{ cdn.args }}>
|
||||
<link rel="dns-prefetch" href="{{ cdn.url }}" {{ cdn.args }}>
|
||||
{% endfor %}
|
||||
|
||||
<link rel="stylesheet" href="{{ site.data.origin[type].webfonts | relative_url }}">
|
||||
{% endif %}
|
||||
|
||||
<!-- GA -->
|
||||
{% if jekyll.environment == 'production' and site.google_analytics.id != empty and site.google_analytics.id %}
|
||||
<link rel="preconnect" href="https://www.google-analytics.com" crossorigin="use-credentials">
|
||||
<link rel="dns-prefetch" href="https://www.google-analytics.com">
|
||||
|
||||
<link rel="preconnect" href="https://www.googletagmanager.com" crossorigin="anonymous">
|
||||
<link rel="dns-prefetch" href="https://www.googletagmanager.com">
|
||||
{% endif %}
|
||||
<!-- Resource Hints -->
|
||||
{% unless site.assets.self_host.enabled %}
|
||||
{% for hint in site.data.origin.cors.resource_hints %}
|
||||
{% for link in hint.links %}
|
||||
<link rel="{{ link.rel }}" href="{{ hint.url }}" {{ link.opts | join: ' ' }}>
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
{% endunless %}
|
||||
|
||||
<!-- Bootstrap -->
|
||||
<link rel="stylesheet" href="{{ site.data.origin[type].bootstrap.css | relative_url }}">
|
||||
{% unless jekyll.environment == 'production' %}
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css">
|
||||
{% endunless %}
|
||||
|
||||
<!-- Font Awesome -->
|
||||
<!-- Theme style -->
|
||||
<link rel="stylesheet" href="{{ '/assets/css/:THEME.css' | replace: ':THEME', site.theme | relative_url }}">
|
||||
|
||||
<!-- Web Font -->
|
||||
<link rel="stylesheet" href="{{ site.data.origin[type].webfonts | relative_url }}">
|
||||
|
||||
<!-- Font Awesome Icons -->
|
||||
<link rel="stylesheet" href="{{ site.data.origin[type].fontawesome.css | relative_url }}">
|
||||
|
||||
<link rel="stylesheet" href="{{ '/assets/css/:THEME.css' | replace: ':THEME', site.theme | relative_url }}">
|
||||
<!-- 3rd-party Dependencies -->
|
||||
|
||||
{% if site.toc and page.toc %}
|
||||
<link rel="stylesheet" href="{{ site.data.origin[type].toc.css | relative_url }}">
|
||||
@ -97,28 +93,61 @@
|
||||
{% endif %}
|
||||
|
||||
{% if page.layout == 'page' or page.layout == 'post' %}
|
||||
<!-- Manific Popup -->
|
||||
<link rel="stylesheet" href="{{ site.data.origin[type].magnific-popup.css | relative_url }}">
|
||||
<!-- Image Popup -->
|
||||
<link rel="stylesheet" href="{{ site.data.origin[type].glightbox.css | relative_url }}">
|
||||
{% endif %}
|
||||
|
||||
<!-- JavaScript -->
|
||||
<!-- Scripts -->
|
||||
<script>
|
||||
var serviceUrl = "{{site.custom-config.blog-services.service_url}}";
|
||||
var siteId = "{{site.id}}";
|
||||
var postId = "{{page.title}}";
|
||||
var serviceApiKey = "{{site.custom-config.blog-services.service_key}}";
|
||||
var siteId = "{{site.url}}{{site.baseurl}}";
|
||||
var postId = "{{page.slug}}";
|
||||
var remark42Host = "{{ site.comments.remark42.host }}";
|
||||
|
||||
function ajax(url) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.onload = function () {
|
||||
resolve(this.responseText);
|
||||
};
|
||||
xhr.onerror = reject;
|
||||
xhr.open('GET', url);
|
||||
xhr.send();
|
||||
});
|
||||
var postDetails = {
|
||||
postUrl: "{{site.url}}{{site.baseurl}}{{page.url}}",
|
||||
slug: "{{page.slug}}",
|
||||
title: "{{page.title}}",
|
||||
description: "{{page.description}}",
|
||||
categories: [],
|
||||
image: "{{page.image.path}}",
|
||||
createdDate: "{{page.date}}",
|
||||
modifiedDate: "{{page.last_modified_at | strip}}",
|
||||
blogUrl: "{{site.url}}{{site.baseurl}}",
|
||||
views: 0,
|
||||
likes: 0,
|
||||
comments: 0
|
||||
};
|
||||
|
||||
function liquidArrayToJsonArray(){
|
||||
var items = [];
|
||||
{% for category in page.categories %}
|
||||
{% assign cat = category %}
|
||||
items.push("{{cat}}");
|
||||
{% endfor %}
|
||||
return items;
|
||||
}
|
||||
|
||||
postDetails.categories = liquidArrayToJsonArray();
|
||||
|
||||
function ajax(url, type, payload) {
|
||||
if (payload === undefined) {
|
||||
payload = null;
|
||||
}
|
||||
return new Promise(function (resolve, reject) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.onload = function () {
|
||||
resolve(this.responseText);
|
||||
};
|
||||
xhr.onerror = reject;
|
||||
xhr.open(type, url);
|
||||
xhr.setRequestHeader('XApiKey', serviceApiKey);
|
||||
xhr.setRequestHeader('Content-Type', 'application/json');
|
||||
xhr.setRequestHeader('ngsw-bypass', '');
|
||||
xhr.send(JSON.stringify(payload));
|
||||
});
|
||||
}
|
||||
</script>
|
||||
{% if jekyll.environment == 'production' and site.google_analytics.id != empty and site.google_analytics.id %}
|
||||
<!-- Google Tag Manager -->
|
||||
@ -140,9 +169,28 @@
|
||||
<!-- End Microsoft Clarity -->
|
||||
{% endif %}
|
||||
|
||||
{% unless site.theme_mode %}
|
||||
{% include mode-toggle.html %}
|
||||
{% endunless %}
|
||||
<script src="{{ '/assets/js/dist/theme.min.js' | relative_url }}"></script>
|
||||
|
||||
{% include js-selector.html lang=lang %}
|
||||
|
||||
{% if jekyll.environment == 'production' %}
|
||||
<!-- PWA -->
|
||||
{% if site.pwa.enabled %}
|
||||
<script
|
||||
defer
|
||||
src="{{ '/app.min.js' | relative_url }}?baseurl={{ site.baseurl | default: '' }}®ister={{ site.pwa.cache.enabled }}"
|
||||
></script>
|
||||
{% endif %}
|
||||
|
||||
<!-- Web Analytics -->
|
||||
{% for analytics in site.analytics %}
|
||||
{% capture str %}{{ analytics }}{% endcapture %}
|
||||
{% assign platform = str | split: '{' | first %}
|
||||
{% if site.analytics[platform].id and site.analytics[platform].id != empty %}
|
||||
{% include analytics/{{ platform }}.html %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
{% include metadata-hook.html %}
|
||||
</head>
|
||||
@ -29,16 +29,43 @@
|
||||
const views = document.getElementById("views-count");
|
||||
const likes = document.getElementById("likes-count");
|
||||
const postLikesAndViews = document.getElementById("likes-views");
|
||||
var commentsCountFromResponse = 0;
|
||||
|
||||
postLikesAndViews.style.display = "none";
|
||||
|
||||
ajax(serviceUrl + "/GetPostLikesAndViews?siteId=" + siteId + "&postId=" + postId)
|
||||
ajax(serviceUrl + "/GetPostLikesAndViews?blogUrl=" + siteId + "&postSlug=" + postId, "GET")
|
||||
.then(function (result) {
|
||||
if (result != "N/A") {
|
||||
var response = JSON.parse(result);
|
||||
views.innerText = response.postViews;
|
||||
likes.innerText = response.postLikes;
|
||||
postLikesAndViews.style.display = "inline";
|
||||
if(!response.postExists){
|
||||
postDetails.likes = postDetails.views = postDetails.comments = 0;
|
||||
if(Number(likes.innerText) !== NaN){
|
||||
postDetails.likes = Number(likes.innerText);
|
||||
}
|
||||
if(Number(views.innerText) !== NaN){
|
||||
postDetails.views = Number(views.innerText);
|
||||
}
|
||||
if(postDetails.modifiedDate === ""){
|
||||
postDetails.modifiedDate = postDetails.createdDate;
|
||||
}
|
||||
}
|
||||
|
||||
ajax(serviceUrl + "/CreatePost", "POST", postDetails)
|
||||
.then(function (result) {
|
||||
if(result != "N/A"){
|
||||
var response = JSON.parse(result);
|
||||
setPostMetrics(response);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
function setPostMetrics(response){
|
||||
if(response.postExists){
|
||||
views.innerText = response.views;
|
||||
likes.innerText = response.likes;
|
||||
commentsCountFromResponse = response.comments;
|
||||
postLikesAndViews.style.display = "inline";
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@ -37,9 +37,8 @@
|
||||
|
||||
function apiCall(url, event) {
|
||||
onLoadAndClick();
|
||||
ajax(url)
|
||||
ajax(url, "POST")
|
||||
.then(function (result) {
|
||||
console.log(result);
|
||||
if (event === "click") {
|
||||
heartIcon.classList.toggle("liked");
|
||||
}
|
||||
@ -48,7 +47,7 @@
|
||||
});
|
||||
}
|
||||
|
||||
var apiUrl = serviceUrl + "/GetPostLikes?siteId=" + siteId + "&postId=" + postId;
|
||||
var apiUrl = serviceUrl + "/GetPostLikes?blogUrl=" + siteId + "&postSlug=" + postId;
|
||||
|
||||
if(likesOnLoad == "{{include.onload}}"){
|
||||
apiCall(apiUrl);
|
||||
@ -56,9 +55,9 @@
|
||||
|
||||
heartIcon.addEventListener("click", () => {
|
||||
if (!heartIcon.classList.contains("liked")) {
|
||||
apiUrl = serviceUrl + "/LikePost?siteId=" + siteId + "&postId=" + postId;
|
||||
apiUrl = serviceUrl + "/LikePost?blogUrl=" + siteId + "&postSlug=" + postId;
|
||||
} else {
|
||||
apiUrl = serviceUrl + "/DislikePost?siteId=" + siteId + "&postId=" + postId;
|
||||
apiUrl = serviceUrl + "/DislikePost?blogUrl=" + siteId + "&postSlug=" + postId;
|
||||
}
|
||||
|
||||
apiCall(apiUrl, "click");
|
||||
|
||||
@ -1,8 +1,4 @@
|
||||
<style>
|
||||
main h3 {
|
||||
margin: 10px
|
||||
}
|
||||
|
||||
#post-series {
|
||||
margin-top: 25px;
|
||||
}
|
||||
@ -17,7 +13,7 @@
|
||||
<div id="post-series">
|
||||
<div class="card">
|
||||
<div>
|
||||
<h3>{{ page.series }}</h3>
|
||||
<h3>{{ page.series }} ({{ posts | size }} - Part Series)</h3>
|
||||
<ol>
|
||||
{% assign posts = site.posts | where: "series", page.series | sort: "date" %}
|
||||
{% for post in posts %}
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
<i class="fa fa-eye fa-fw" aria-hidden="true" {% if include.tooltip %} title="{{site.data.locales[include.lang].post.views}}"
|
||||
data-bs-toggle="tooltip" data-bs-placement="bottom" {% endif %}></i>
|
||||
<em id="views-count" style="margin-right: 12px">
|
||||
</em>
|
||||
<em id="views-count" style="margin-right: 12px"></em>
|
||||
|
||||
<script>
|
||||
const viewsOnLoad = "true";
|
||||
|
||||
@ -12,7 +12,7 @@ layout: compress
|
||||
{% endif %}
|
||||
|
||||
<!-- `site.alt_lang` can specify a language different from the UI -->
|
||||
<html lang="{{ site.alt_lang | default: site.lang }}" {{ prefer_mode }}>
|
||||
<html lang="{{ page.lang | default: site.lang }}" {{ prefer_mode }}>
|
||||
{% include head.html %}
|
||||
|
||||
<body>
|
||||
@ -40,7 +40,7 @@ layout: compress
|
||||
</main>
|
||||
|
||||
<!-- panel -->
|
||||
<aside aria-label="Panel" id="panel-wrapper" class="col-xl-3 ps-2 mb-5 text-muted">
|
||||
<aside aria-label="Panel" id="panel-wrapper" class="col-xl-3 ps-2 text-muted">
|
||||
<div class="access">
|
||||
{% include_cached update-list.html lang=lang %}
|
||||
{% include_cached trending-tags.html lang=lang %}
|
||||
@ -75,21 +75,20 @@ layout: compress
|
||||
</aside>
|
||||
</div>
|
||||
|
||||
<div id="mask"></div>
|
||||
<div id="mask" class="d-none position-fixed w-100 h-100 z-1"></div>
|
||||
|
||||
{% if site.pwa.enabled %}
|
||||
{% include_cached notification.html lang=lang %}
|
||||
{% endif %}
|
||||
|
||||
<!-- JavaScripts -->
|
||||
<!-- Embedded scripts -->
|
||||
|
||||
{% include js-selector.html %}
|
||||
{% for _include in layout.script_includes %}
|
||||
{% assign _include_path = _include | append: '.html' %}
|
||||
{% include {{ _include_path }} %}
|
||||
{% endfor %}
|
||||
|
||||
{% if page.mermaid %}
|
||||
{% include mermaid.html %}
|
||||
{% endif %}
|
||||
|
||||
{% include_cached search-loader.html %}
|
||||
{% include_cached search-loader.html lang=lang %}
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@ -6,14 +6,21 @@ panel_includes:
|
||||
tail_includes:
|
||||
- related-posts
|
||||
- post-nav
|
||||
- comments
|
||||
- comment
|
||||
script_includes:
|
||||
- comment
|
||||
---
|
||||
|
||||
{% include lang.html %}
|
||||
|
||||
<article class="px-1">
|
||||
{% include toc-status.html %}
|
||||
|
||||
<article class="px-1" data-toc="{{ enable_toc }}">
|
||||
<header>
|
||||
<h1 data-toc-skip>{{ page.title }}</h1>
|
||||
{% if page.description %}
|
||||
<p class="post-desc fw-light mb-4">{{ page.description }}</p>
|
||||
{% endif %}
|
||||
|
||||
<div class="post-meta text-muted">
|
||||
<div class="d-flex justify-content-between">
|
||||
@ -85,15 +92,50 @@ tail_includes:
|
||||
</em>
|
||||
</span>
|
||||
|
||||
<!-- read time -->
|
||||
{% include read-time.html content=content prompt=true lang=lang %}
|
||||
<div>
|
||||
<!-- pageviews -->
|
||||
{% if site.pageviews.provider and site.analytics[site.pageviews.provider].id %}
|
||||
<span>
|
||||
<em id="pageviews">
|
||||
<i class="fas fa-spinner fa-spin small"></i>
|
||||
</em>
|
||||
{{ site.data.locales[lang].post.pageview_measure }}
|
||||
</span>
|
||||
{% endif %}
|
||||
|
||||
<!-- read time -->
|
||||
{% include read-time.html content=content prompt=true lang=lang %}
|
||||
</div>
|
||||
</div>
|
||||
<!-- .d-flex -->
|
||||
</div>
|
||||
<!-- .post-meta -->
|
||||
{% include post-series.html %}
|
||||
</header>
|
||||
|
||||
{% if enable_toc %}
|
||||
<div id="toc-bar" class="d-flex align-items-center justify-content-between invisible">
|
||||
<span class="label text-truncate">{{ page.title }}</span>
|
||||
<button type="button" class="toc-trigger btn me-1">
|
||||
<i class="fa-solid fa-list-ul fa-fw"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<button id="toc-solo-trigger" type="button" class="toc-trigger btn btn-outline-secondary btn-sm">
|
||||
<span class="label ps-2 pe-1">{{- site.data.locales[lang].panel.toc -}}</span>
|
||||
<i class="fa-solid fa-angle-right fa-fw"></i>
|
||||
</button>
|
||||
|
||||
<dialog id="toc-popup" class="p-0">
|
||||
<div class="header d-flex flex-row align-items-center justify-content-between">
|
||||
<div class="label text-truncate py-2 ms-4">{{- page.title -}}</div>
|
||||
<button id="toc-popup-close" type="button" class="btn mx-1 my-1 opacity-75">
|
||||
<i class="fas fa-close"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div id="toc-popup-content" class="px-4 py-3 pb-4"></div>
|
||||
</dialog>
|
||||
{% endif %}
|
||||
|
||||
<div class="content">
|
||||
{{ content }}
|
||||
{% if page.disable-ty != true %}
|
||||
|
||||
@ -7,6 +7,8 @@ slug: hello-world
|
||||
description: Hello World
|
||||
categories: []
|
||||
disable-ty: true
|
||||
image:
|
||||
path: /assets/img/posts/hello-world.jpg
|
||||
---
|
||||
|
||||
## Hello World
|
||||
|
||||
@ -9,6 +9,13 @@ tags:
|
||||
categories:
|
||||
- Open Source
|
||||
- Services
|
||||
slug: hosted-commenting-system
|
||||
image:
|
||||
path: /assets/img/posts/remark42.png
|
||||
keywords:
|
||||
- remark42
|
||||
- self-hosted
|
||||
- privacy
|
||||
---
|
||||
|
||||
## Privacy-focused lightweight commenting engine
|
||||
|
||||
@ -1,15 +1,17 @@
|
||||
---
|
||||
title: SOLID Principles
|
||||
description: Solid Principles
|
||||
description: The SOLID principles are a set of design principles aimed at improving software quality, making it easier to understand, extend, and maintain.
|
||||
date: 2024-04-03T16:10:57.476Z
|
||||
tags:
|
||||
- code quality
|
||||
- oops
|
||||
- code quality
|
||||
- oops
|
||||
- principles
|
||||
categories:
|
||||
- Programming
|
||||
- Principles
|
||||
- Programming
|
||||
- Principles
|
||||
image:
|
||||
path: /assets/img/posts/solid-principles.jpg
|
||||
path: /assets/img/posts/solid-principles.jpg
|
||||
alt: Understanding SOLID Principles
|
||||
slug: solid-principles
|
||||
---
|
||||
|
||||
|
||||
143
_posts/2025-01-01-a-beginners-guide-to-ufw.md
Normal file
143
_posts/2025-01-01-a-beginners-guide-to-ufw.md
Normal file
@ -0,0 +1,143 @@
|
||||
---
|
||||
title: "Keep Your Linux System Secure: A Beginner’s Guide to UFW"
|
||||
description: UFW is a tool that helps you decide which connections can or can't access your Linux system. It's simple enough for beginners but also has features for experts.
|
||||
date: 2025-01-01T17:48:18.319Z
|
||||
tags:
|
||||
- firewall
|
||||
- linux
|
||||
- security
|
||||
- ufw
|
||||
categories:
|
||||
- Linux
|
||||
- Firewall
|
||||
image:
|
||||
path: /assets/img/posts/ufw-logo.jpg
|
||||
alt: A Beginner's Guide to UFW (Uncomplicated Firewall)
|
||||
slug: ufw-guide
|
||||
---
|
||||
UFW (Uncomplicated Firewall) is a powerful yet user-friendly tool that allows you to control which connections can access your Linux system. Designed with simplicity in mind, it’s perfect for beginners while still offering advanced features for experienced users. In this post, we’ll explore how UFW works, how to use it effectively, and why it’s an essential tool for securing your system.
|
||||
|
||||
When it comes to securing your Linux server or desktop, managing network access is one of the most critical tasks. Firewalls serve as the first line of defense, and while tools like iptables offer granular control, they can be intimidating for beginners. That’s where UFW (Uncomplicated Firewall) steps in.
|
||||
|
||||
UFW is a user-friendly interface for managing iptables, designed to simplify the process of configuring a firewall. Whether you’re a seasoned Linux administrator or a newcomer, UFW makes securing your system straightforward and efficient.
|
||||
|
||||
## Why Use UFW?
|
||||
1. **Ease of Use:** UFW abstracts the complexities of iptables, offering simple commands to configure firewall rules.
|
||||
2. **Default Settings:** UFW ships with sensible defaults, such as denying all incoming connections while allowing outgoing ones.
|
||||
3. **Integration:** It integrates well with many linux distributions and is often installed by default.
|
||||
4. **Script-Friendly:** UFW is ideal for automation and scripting, making it perfect for managing servers at scale.
|
||||
|
||||
## Installing UFW
|
||||
Most modern Linux distributions come with UFW pre-installed. If it’s not already on your system, you can install it with the following commands:
|
||||
|
||||
For Ubuntu/Debian:
|
||||
```terminal
|
||||
sudo apt update
|
||||
sudo apt install ufw
|
||||
```
|
||||
For CentOS/RHEL:
|
||||
```terminal
|
||||
sudo yum install epel-release
|
||||
sudo yum install ufw
|
||||
```
|
||||
For Arch Linux:
|
||||
```terminal
|
||||
sudo pacman -S ufw
|
||||
```
|
||||
## Basic UFW Commands
|
||||
### Enable UFW
|
||||
Before configuring UFW, you need to enable it:
|
||||
```terminal
|
||||
sudo ufw enable
|
||||
```
|
||||
### Check UFW Status
|
||||
To see whether UFW is running and view current rules:
|
||||
```terminal
|
||||
sudo ufw status
|
||||
```
|
||||
### Allowing connections
|
||||
To allow traffic on a specific port, use the `allow` command. For example, to allow SSH connections:
|
||||
```terminal
|
||||
sudo ufw allow ssh
|
||||
```
|
||||
Or, specify the port number:
|
||||
```terminal
|
||||
sudo ufw allow 22
|
||||
```
|
||||
### Denying Connections
|
||||
To block traffic on a specific port:
|
||||
```terminal
|
||||
sudo ufw deny 80
|
||||
```
|
||||
### Removing Rules
|
||||
To delete a rule, prepend the rule with `delete`. For example:
|
||||
```terminal
|
||||
sudo ufw delete allow 22
|
||||
```
|
||||
Or Remove a rule by its number
|
||||
|
||||
List UFW Rules with Numbers
|
||||
```terminal
|
||||
sudo ufw status numbered
|
||||
```
|
||||
Example output
|
||||
```terminal
|
||||
Status: active
|
||||
|
||||
To Action From
|
||||
[ 1] 22/tcp ALLOW Anywhere
|
||||
[ 2] 80/tcp ALLOW Anywhere
|
||||
[ 3] 22/tcp (v6) ALLOW Anywhere (v6)
|
||||
[ 4] 80/tcp (v6) ALLOW Anywhere (v6)
|
||||
```
|
||||
Delete the Rule by Number
|
||||
```terminal
|
||||
sudo ufw delete 2
|
||||
```
|
||||
### Resetting UFW
|
||||
To reset UFW to its default state, removing all rules:
|
||||
```terminal
|
||||
sudo ufw reset
|
||||
```
|
||||
## Advanced Usage
|
||||
### Limiting Connections
|
||||
To protect against brute-force attacks, you can limit connections by using `limit` rule in UFW. This rule restricts the rate of new connections from the same IP address, allowing only a limited number of connections per minute (default: 6 attempts within 30 seconds). You can adjust these values by modifying the UFW configuration files, typically found in `/etc/ufw/` or `/etc/ufw/ufw.conf`, or by customizing rate limits using iptables rules directly. within a specified time frame. For instance, to limit SSH attempts, you can execute:
|
||||
```terminal
|
||||
sudo ufw limit ssh
|
||||
```
|
||||
This helps to deter malicious actors trying to gain unauthorized access to your system by repeatedly guessing passwords or exploiting vulnerabilities.
|
||||
### Allowing Specific IP Addresses
|
||||
To allow traffic from a specific IP address:
|
||||
```terminal
|
||||
sudo ufw allow from 192.168.0.100
|
||||
```
|
||||
Allowing Traffic to a Specific Port and IP
|
||||
For more granular control, you can specify both source IP and destination port:
|
||||
```terminal
|
||||
sudo ufw allow from 192.168.0.100 to any port 22
|
||||
sudo ufw allow from 192.168.0.0/24 to any port 22 proto tcp
|
||||
```
|
||||
### Using Application Profiles
|
||||
UFW supports application profiles to simplify rule management for common services. List available profiles with:
|
||||
```terminal
|
||||
sudo ufw app list
|
||||
```
|
||||
To allow a specific application, UFW provides predefined profiles for commonly used software and services. These profiles encapsulate the necessary port and protocol details, simplifying firewall configuration. For instance, to permit traffic for an application like Apache, you can execute:
|
||||
```terminal
|
||||
sudo ufw allow 'Apache Full'
|
||||
```
|
||||
This command enables both HTTP (port 80) and HTTPS (port 443) traffic, as defined in the application profile.
|
||||
|
||||
## Best Practices
|
||||
1. **Start with Defaults:** UFW's default policy denies incoming traffic and allows outgoing traffic, a good starting point for most setups.
|
||||
2. **Enable Logging:** Turn on logging to monitor blocked traffic:
|
||||
```terminal
|
||||
sudo ufw logging on
|
||||
```
|
||||
3. **Test Rules:** Before applying complex rules on a production system, test them in a safe environment.
|
||||
4. **Document Changes:** Keep a record of the rules you add or remove to make troubleshooting easier.
|
||||
|
||||
## Conclusion
|
||||
UFW makes it easy to manage your firewall, even if you’re new to Linux. By learning its simple and advanced features, you can protect your system without the hassle of complicated tools like iptables. Whether you’re using one computer or many servers, UFW is a great tool to keep things secure.
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@ order: 4
|
||||
---
|
||||
|
||||
## Meet Bangara Raju: Your Guide to Tech, DIY, and Beyond
|
||||
Hello there, curious minds and fellow explorers! I'm **Bangara Raju**, and I'm absolutely thrilled to welcome you to my corner of the internet.
|
||||
Hello there, curious minds and fellow explorers! I'm [**Bangara Raju**](https://bangararaju.kottedi.in/){:target="_blank"}, and I'm absolutely thrilled to welcome you to my corner of the internet.
|
||||
|
||||
### A Byte-Sized Introduction:
|
||||
By day, I'm immersed in the world of code and algorithms, working as a **Software Engineer** to shape the digital landscapes we navigate.
|
||||
|
||||
BIN
assets/img/posts/hello-world.jpg
Normal file
BIN
assets/img/posts/hello-world.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 87 KiB |
BIN
assets/img/posts/python-getting-started.png
Normal file
BIN
assets/img/posts/python-getting-started.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 53 KiB |
BIN
assets/img/posts/python-logo.jpg
Normal file
BIN
assets/img/posts/python-logo.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 23 KiB |
BIN
assets/img/posts/remark42.png
Normal file
BIN
assets/img/posts/remark42.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 29 KiB |
BIN
assets/img/posts/ufw-logo.jpg
Normal file
BIN
assets/img/posts/ufw-logo.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 38 KiB |
@ -4,7 +4,7 @@ var remark_config = {
|
||||
components: ['embed'],
|
||||
|
||||
max_shown_comments: 10,
|
||||
theme: modeToggle.modeStatus,
|
||||
theme: Theme.visualState,
|
||||
|
||||
locale: 'en',
|
||||
show_email_subscription: false
|
||||
@ -23,6 +23,6 @@ var targetDiv = document.getElementById("sidebar").getElementsByClassName("mode-
|
||||
|
||||
if (targetDiv != null) {
|
||||
targetDiv.addEventListener("click", () => {
|
||||
window.REMARK42.changeTheme(modeToggle.modeStatus === 'light' ? 'dark' : 'light');
|
||||
window.REMARK42.changeTheme(Theme.visualState === 'light' ? 'dark' : 'light');
|
||||
})
|
||||
}
|
||||
@ -3,14 +3,17 @@ var siteId = document.currentScript.getAttribute('siteid');
|
||||
var postId = document.currentScript.getAttribute('postid');
|
||||
var remark42Host = document.currentScript.getAttribute('remark42host');
|
||||
|
||||
function ajax(url) {
|
||||
function ajax(url, type, payload) {
|
||||
if (payload === undefined) {
|
||||
payload = null;
|
||||
}
|
||||
return new Promise(function (resolve, reject) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.onload = function () {
|
||||
resolve(this.responseText);
|
||||
};
|
||||
xhr.onerror = reject;
|
||||
xhr.open('GET', url);
|
||||
xhr.send();
|
||||
xhr.open(type, url);
|
||||
xhr.send(payload);
|
||||
});
|
||||
}
|
||||
|
||||
@ -16,7 +16,6 @@ function apiCall(url, event) {
|
||||
onLoadAndClick();
|
||||
ajax(url)
|
||||
.then(function (result) {
|
||||
console.log(result);
|
||||
if(event === "click"){
|
||||
heartIcon.classList.toggle("liked");
|
||||
}
|
||||
|
||||
@ -49,12 +49,17 @@
|
||||
"title": "disable-ty",
|
||||
"name": "disable-ty",
|
||||
"type": "boolean"
|
||||
},
|
||||
{
|
||||
"title": "series",
|
||||
"name": "series",
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"frontMatter.framework.id": "jekyll",
|
||||
"frontMatter.content.publicFolder": "assets",
|
||||
"frontMatter.content.publicFolder": "",
|
||||
"frontMatter.preview.host": "http://localhost:4000",
|
||||
"frontMatter.content.pageFolders": [
|
||||
{
|
||||
|
||||
54
tools/run.sh
Normal file
54
tools/run.sh
Normal file
@ -0,0 +1,54 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Run jekyll serve and then launch the site
|
||||
|
||||
prod=false
|
||||
command="bundle exec jekyll s -l"
|
||||
host="127.0.0.1"
|
||||
|
||||
help() {
|
||||
echo "Usage:"
|
||||
echo
|
||||
echo " bash /path/to/run [options]"
|
||||
echo
|
||||
echo "Options:"
|
||||
echo " -H, --host [HOST] Host to bind to."
|
||||
echo " -p, --production Run Jekyll in 'production' mode."
|
||||
echo " -h, --help Print this help information."
|
||||
}
|
||||
|
||||
while (($#)); do
|
||||
opt="$1"
|
||||
case $opt in
|
||||
-H | --host)
|
||||
host="$2"
|
||||
shift 2
|
||||
;;
|
||||
-p | --production)
|
||||
prod=true
|
||||
shift
|
||||
;;
|
||||
-h | --help)
|
||||
help
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
echo -e "> Unknown option: '$opt'\n"
|
||||
help
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
command="$command -H $host"
|
||||
|
||||
if $prod; then
|
||||
command="JEKYLL_ENV=production $command"
|
||||
fi
|
||||
|
||||
if [ -e /proc/1/cgroup ] && grep -q docker /proc/1/cgroup; then
|
||||
command="$command --force_polling"
|
||||
fi
|
||||
|
||||
echo -e "\n> $command\n"
|
||||
eval "$command"
|
||||
89
tools/test.sh
Normal file
89
tools/test.sh
Normal file
@ -0,0 +1,89 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Build and test the site content
|
||||
#
|
||||
# Requirement: html-proofer, jekyll
|
||||
#
|
||||
# Usage: See help information
|
||||
|
||||
set -eu
|
||||
|
||||
SITE_DIR="_site"
|
||||
|
||||
_config="_config.yml"
|
||||
|
||||
_baseurl=""
|
||||
|
||||
help() {
|
||||
echo "Build and test the site content"
|
||||
echo
|
||||
echo "Usage:"
|
||||
echo
|
||||
echo " bash $0 [options]"
|
||||
echo
|
||||
echo "Options:"
|
||||
echo ' -c, --config "<config_a[,config_b[...]]>" Specify config file(s)'
|
||||
echo " -h, --help Print this information."
|
||||
}
|
||||
|
||||
read_baseurl() {
|
||||
if [[ $_config == *","* ]]; then
|
||||
# multiple config
|
||||
IFS=","
|
||||
read -ra config_array <<<"$_config"
|
||||
|
||||
# reverse loop the config files
|
||||
for ((i = ${#config_array[@]} - 1; i >= 0; i--)); do
|
||||
_tmp_baseurl="$(grep '^baseurl:' "${config_array[i]}" | sed "s/.*: *//;s/['\"]//g;s/#.*//")"
|
||||
|
||||
if [[ -n $_tmp_baseurl ]]; then
|
||||
_baseurl="$_tmp_baseurl"
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
else
|
||||
# single config
|
||||
_baseurl="$(grep '^baseurl:' "$_config" | sed "s/.*: *//;s/['\"]//g;s/#.*//")"
|
||||
fi
|
||||
}
|
||||
|
||||
main() {
|
||||
# clean up
|
||||
if [[ -d $SITE_DIR ]]; then
|
||||
rm -rf "$SITE_DIR"
|
||||
fi
|
||||
|
||||
read_baseurl
|
||||
|
||||
# build
|
||||
JEKYLL_ENV=production bundle exec jekyll b \
|
||||
-d "$SITE_DIR$_baseurl" -c "$_config"
|
||||
|
||||
# test
|
||||
bundle exec htmlproofer "$SITE_DIR" \
|
||||
--disable-external \
|
||||
--ignore-urls "/^http:\/\/127.0.0.1/,/^http:\/\/0.0.0.0/,/^http:\/\/localhost/"
|
||||
}
|
||||
|
||||
while (($#)); do
|
||||
opt="$1"
|
||||
case $opt in
|
||||
-c | --config)
|
||||
_config="$2"
|
||||
shift
|
||||
shift
|
||||
;;
|
||||
-h | --help)
|
||||
help
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
# unknown option
|
||||
help
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
main
|
||||
Loading…
Reference in New Issue
Block a user